Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/camera/2d_top_down_camera.rs
6592 views
1
//! This example showcases a 2D top-down camera with smooth player tracking.
2
//!
3
//! ## Controls
4
//!
5
//! | Key Binding | Action |
6
//! |:---------------------|:--------------|
7
//! | `W` | Move up |
8
//! | `S` | Move down |
9
//! | `A` | Move left |
10
//! | `D` | Move right |
11
12
use bevy::{post_process::bloom::Bloom, prelude::*};
13
14
/// Player movement speed factor.
15
const PLAYER_SPEED: f32 = 100.;
16
17
/// How quickly should the camera snap to the desired location.
18
const CAMERA_DECAY_RATE: f32 = 2.;
19
20
#[derive(Component)]
21
struct Player;
22
23
fn main() {
24
App::new()
25
.add_plugins(DefaultPlugins)
26
.add_systems(Startup, (setup_scene, setup_instructions, setup_camera))
27
.add_systems(Update, (move_player, update_camera).chain())
28
.run();
29
}
30
31
fn setup_scene(
32
mut commands: Commands,
33
mut meshes: ResMut<Assets<Mesh>>,
34
mut materials: ResMut<Assets<ColorMaterial>>,
35
) {
36
// World where we move the player
37
commands.spawn((
38
Mesh2d(meshes.add(Rectangle::new(1000., 700.))),
39
MeshMaterial2d(materials.add(Color::srgb(0.2, 0.2, 0.3))),
40
));
41
42
// Player
43
commands.spawn((
44
Player,
45
Mesh2d(meshes.add(Circle::new(25.))),
46
MeshMaterial2d(materials.add(Color::srgb(6.25, 9.4, 9.1))), // RGB values exceed 1 to achieve a bright color for the bloom effect
47
Transform::from_xyz(0., 0., 2.),
48
));
49
}
50
51
fn setup_instructions(mut commands: Commands) {
52
commands.spawn((
53
Text::new("Move the light with WASD.\nThe camera will smoothly track the light."),
54
Node {
55
position_type: PositionType::Absolute,
56
bottom: px(12),
57
left: px(12),
58
..default()
59
},
60
));
61
}
62
63
fn setup_camera(mut commands: Commands) {
64
commands.spawn((Camera2d, Bloom::NATURAL));
65
}
66
67
/// Update the camera position by tracking the player.
68
fn update_camera(
69
mut camera: Single<&mut Transform, (With<Camera2d>, Without<Player>)>,
70
player: Single<&Transform, (With<Player>, Without<Camera2d>)>,
71
time: Res<Time>,
72
) {
73
let Vec3 { x, y, .. } = player.translation;
74
let direction = Vec3::new(x, y, camera.translation.z);
75
76
// Applies a smooth effect to camera movement using stable interpolation
77
// between the camera position and the player position on the x and y axes.
78
camera
79
.translation
80
.smooth_nudge(&direction, CAMERA_DECAY_RATE, time.delta_secs());
81
}
82
83
/// Update the player position with keyboard inputs.
84
/// Note that the approach used here is for demonstration purposes only,
85
/// as the point of this example is to showcase the camera tracking feature.
86
///
87
/// A more robust solution for player movement can be found in `examples/movement/physics_in_fixed_timestep.rs`.
88
fn move_player(
89
mut player: Single<&mut Transform, With<Player>>,
90
time: Res<Time>,
91
kb_input: Res<ButtonInput<KeyCode>>,
92
) {
93
let mut direction = Vec2::ZERO;
94
95
if kb_input.pressed(KeyCode::KeyW) {
96
direction.y += 1.;
97
}
98
99
if kb_input.pressed(KeyCode::KeyS) {
100
direction.y -= 1.;
101
}
102
103
if kb_input.pressed(KeyCode::KeyA) {
104
direction.x -= 1.;
105
}
106
107
if kb_input.pressed(KeyCode::KeyD) {
108
direction.x += 1.;
109
}
110
111
// Progressively update the player's position over time. Normalize the
112
// direction vector to prevent it from exceeding a magnitude of 1 when
113
// moving diagonally.
114
let move_delta = direction.normalize_or_zero() * PLAYER_SPEED * time.delta_secs();
115
player.translation += move_delta.extend(0.);
116
}
117
118