Add examples/helpers/* as library examples (#18288)

# Objective

Some of Bevy's examples contain boilerplate which is split out into the
`helpers` folder. This allows examples to have access to common
functionality without building into Bevy directly. However, these
helpers are themselves quite high-quality code, and we do intend for
users to read them and even use them. But, we don't list them in the
examples document, and they aren't explicitly checked in CI, only
transitively through examples which import them.

## Solution

- Added `camera_controller` and `widgets` as library examples.

## Testing

- CI

---

## Notes

- Library examples are identical to any other example, just with
`crate-type = ["lib"]` in the `Cargo.toml`. Since they are marked as
libraries, they don't require a `main` function but do require public
items to be documented.
- Library examples opens the possibility of creating examples which
don't need to be actual runnable applications. This may be more
appropriate for certain ECS examples, and allows for adding helpers
which (currently) don't have an example that needs them without them
going stale.
- I learned about this as a concept during research for `no_std`
examples, but believe it has value for Bevy outside that specific niche.

---------

Co-authored-by: mgi388 <135186256+mgi388@users.noreply.github.com>
Co-authored-by: Carter Weinberg <weinbergcarter@gmail.com>
This commit is contained in:
Zachary Harrold 2025-03-14 03:34:16 +11:00 committed by GitHub
parent 4d47de8ad8
commit 6299e3de3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 59 additions and 0 deletions

View File

@ -4263,3 +4263,27 @@ name = "Occlusion Culling"
description = "Demonstration of Occlusion Culling"
category = "3D Rendering"
wasm = false
[[example]]
name = "camera_controller"
path = "examples/helpers/camera_controller.rs"
doc-scrape-examples = true
crate-type = ["lib"]
[package.metadata.example.camera_controller]
name = "Camera Controller"
description = "Example Free-Cam Styled Camera Controller"
category = "Helpers"
wasm = true
[[example]]
name = "widgets"
path = "examples/helpers/widgets.rs"
doc-scrape-examples = true
crate-type = ["lib"]
[package.metadata.example.widgets]
name = "Widgets"
description = "Example UI Widgets"
category = "Helpers"
wasm = true

View File

@ -51,6 +51,7 @@ git checkout v0.4.0
- [ECS (Entity Component System)](#ecs-entity-component-system)
- [Games](#games)
- [Gizmos](#gizmos)
- [Helpers](#helpers)
- [Input](#input)
- [Math](#math)
- [Movement](#movement)
@ -352,6 +353,13 @@ Example | Description
[Axes](../examples/gizmos/axes.rs) | Demonstrates the function of axes gizmos
[Light Gizmos](../examples/gizmos/light_gizmos.rs) | A scene showcasing light gizmos
## Helpers
Example | Description
--- | ---
[Camera Controller](../examples/helpers/camera_controller.rs) | Example Free-Cam Styled Camera Controller
[Widgets](../examples/helpers/widgets.rs) | Example UI Widgets
## Input
Example | Description

View File

@ -2,6 +2,8 @@
//! To use in your own application:
//! - Copy the code for the [`CameraControllerPlugin`] and add the plugin to your App.
//! - Attach the [`CameraController`] component to an entity with a [`Camera3d`].
//!
//! Unlike other examples, which demonstrate an application, this demonstrates a plugin library.
use bevy::{
input::mouse::{AccumulatedMouseMotion, AccumulatedMouseScroll, MouseScrollUnit},
@ -10,6 +12,7 @@ use bevy::{
};
use std::{f32::consts::*, fmt};
/// A freecam-style camera controller plugin.
pub struct CameraControllerPlugin;
impl Plugin for CameraControllerPlugin {
@ -23,26 +26,48 @@ impl Plugin for CameraControllerPlugin {
/// it because it felt nice.
pub const RADIANS_PER_DOT: f32 = 1.0 / 180.0;
/// Camera controller [`Component`].
#[derive(Component)]
pub struct CameraController {
/// Enables this [`CameraController`] when `true`.
pub enabled: bool,
/// Indicates if this controller has been initialized by the [`CameraControllerPlugin`].
pub initialized: bool,
/// Multiplier for pitch and yaw rotation speed.
pub sensitivity: f32,
/// [`KeyCode`] for forward translation.
pub key_forward: KeyCode,
/// [`KeyCode`] for backward translation.
pub key_back: KeyCode,
/// [`KeyCode`] for left translation.
pub key_left: KeyCode,
/// [`KeyCode`] for right translation.
pub key_right: KeyCode,
/// [`KeyCode`] for up translation.
pub key_up: KeyCode,
/// [`KeyCode`] for down translation.
pub key_down: KeyCode,
/// [`KeyCode`] to use [`run_speed`](CameraController::run_speed) instead of
/// [`walk_speed`](CameraController::walk_speed) for translation.
pub key_run: KeyCode,
/// [`MouseButton`] for grabbing the mouse focus.
pub mouse_key_cursor_grab: MouseButton,
/// [`KeyCode`] for grabbing the keyboard focus.
pub keyboard_key_toggle_cursor_grab: KeyCode,
/// Multiplier for unmodified translation speed.
pub walk_speed: f32,
/// Multiplier for running translation speed.
pub run_speed: f32,
/// Multiplier for how the mouse scroll wheel modifies [`walk_speed`](CameraController::walk_speed)
/// and [`run_speed`](CameraController::run_speed).
pub scroll_factor: f32,
/// Friction factor used to exponentially decay [`velocity`](CameraController::velocity) over time.
pub friction: f32,
/// This [`CameraController`]'s pitch rotation.
pub pitch: f32,
/// This [`CameraController`]'s yaw rotation.
pub yaw: f32,
/// This [`CameraController`]'s translation velocity.
pub velocity: Vec3,
}

View File

@ -1,4 +1,6 @@
//! Simple widgets for example UI.
//!
//! Unlike other examples, which demonstrate an application, this demonstrates a plugin library.
use bevy::{ecs::system::EntityCommands, prelude::*};