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