From be65fbb691b8c4261ca86d8d7c3362d90b9eeb38 Mon Sep 17 00:00:00 2001 From: Julian Date: Mon, 10 Jun 2024 14:33:48 +0200 Subject: [PATCH] 2D top-down camera example (#12720) # Objective This PR addresses the 2D part of #12658. I plan to separate the examples and make one PR per camera example. ## Solution Added a new top-down example composed of: - [x] Player keyboard movements - [x] UI for keyboard instructions - [x] Colors and bloom effect to see the movement of the player - [x] Camera smooth movement towards the player (lerp) ## Testing ```bash cargo run --features="wayland,bevy/dynamic_linking" --example 2d_top_down_camera ``` https://github.com/bevyengine/bevy/assets/10638479/95db0587-e5e0-4f55-be11-97444b795793 --- Cargo.toml | 11 ++ examples/README.md | 7 ++ examples/camera/2d_top_down_camera.rs | 149 ++++++++++++++++++++++++++ 3 files changed, 167 insertions(+) create mode 100644 examples/camera/2d_top_down_camera.rs diff --git a/Cargo.toml b/Cargo.toml index 08af584ee8c86..263f23d866ce0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3086,6 +3086,17 @@ path = "examples/dev_tools/fps_overlay.rs" doc-scrape-examples = true required-features = ["bevy_dev_tools"] +[[example]] +name = "2d_top_down_camera" +path = "examples/camera/2d_top_down_camera.rs" +doc-scrape-examples = true + +[package.metadata.example.2d_top_down_camera] +name = "2D top-down camera" +description = "A 2D top-down camera smoothly following player movements" +category = "Camera" +wasm = true + [package.metadata.example.fps_overlay] name = "FPS overlay" description = "Demonstrates FPS overlay" diff --git a/examples/README.md b/examples/README.md index c4f46cc013bab..1d1d995cf31bb 100644 --- a/examples/README.md +++ b/examples/README.md @@ -45,6 +45,7 @@ git checkout v0.4.0 - [Assets](#assets) - [Async Tasks](#async-tasks) - [Audio](#audio) + - [Camera](#camera) - [Dev tools](#dev-tools) - [Diagnostics](#diagnostics) - [ECS (Entity Component System)](#ecs-entity-component-system) @@ -240,6 +241,12 @@ Example | Description [Spatial Audio 2D](../examples/audio/spatial_audio_2d.rs) | Shows how to play spatial audio, and moving the emitter in 2D [Spatial Audio 3D](../examples/audio/spatial_audio_3d.rs) | Shows how to play spatial audio, and moving the emitter in 3D +## Camera + +Example | Description +--- | --- +[2D top-down camera](../examples/camera/2d_top_down_camera.rs) | A 2D top-down camera smoothly following player movements + ## Dev tools Example | Description diff --git a/examples/camera/2d_top_down_camera.rs b/examples/camera/2d_top_down_camera.rs new file mode 100644 index 0000000000000..7321712988d62 --- /dev/null +++ b/examples/camera/2d_top_down_camera.rs @@ -0,0 +1,149 @@ +//! This example showcases a 2D top-down camera with smooth player tracking. +//! +//! ## Controls +//! +//! | Key Binding | Action | +//! |:---------------------|:--------------| +//! | `Z`(azerty), `W`(US) | Move forward | +//! | `S` | Move backward | +//! | `Q`(azerty), `A`(US) | Move left | +//! | `D` | Move right | + +use bevy::core_pipeline::bloom::BloomSettings; +use bevy::math::vec3; +use bevy::prelude::*; +use bevy::sprite::{MaterialMesh2dBundle, Mesh2dHandle}; + +/// Player movement speed factor. +const PLAYER_SPEED: f32 = 100.; + +/// Camera lerp factor. +const CAM_LERP_FACTOR: f32 = 2.; + +#[derive(Component)] +struct Player; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_systems(Startup, (setup_scene, setup_instructions, setup_camera)) + .add_systems(Update, (move_player, update_camera).chain()) + .run(); +} + +fn setup_scene( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // World where we move the player + commands.spawn(MaterialMesh2dBundle { + mesh: Mesh2dHandle(meshes.add(Rectangle::new(1000., 700.))), + material: materials.add(Color::srgb(0.2, 0.2, 0.3)), + ..default() + }); + + // Player + commands.spawn(( + Player, + MaterialMesh2dBundle { + mesh: meshes.add(Circle::new(25.)).into(), + material: materials.add(Color::srgb(6.25, 9.4, 9.1)), // RGB values exceed 1 to achieve a bright color for the bloom effect + transform: Transform { + translation: vec3(0., 0., 2.), + ..default() + }, + ..default() + }, + )); +} + +fn setup_instructions(mut commands: Commands) { + commands.spawn( + TextBundle::from_section( + "Move the light with ZQSD or WASD.\nThe camera will smoothly track the light.", + TextStyle::default(), + ) + .with_style(Style { + position_type: PositionType::Absolute, + bottom: Val::Px(12.0), + left: Val::Px(12.0), + ..default() + }), + ); +} + +fn setup_camera(mut commands: Commands) { + commands.spawn(( + Camera2dBundle { + camera: Camera { + hdr: true, // HDR is required for the bloom effect + ..default() + }, + ..default() + }, + BloomSettings::NATURAL, + )); +} + +/// Update the camera position by tracking the player. +fn update_camera( + mut camera: Query<&mut Transform, (With, Without)>, + player: Query<&Transform, (With, Without)>, + time: Res