-
Notifications
You must be signed in to change notification settings - Fork 31
/
Copy pathmovement.rs
84 lines (74 loc) · 2.78 KB
/
movement.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
//! Handle player input and translate it into movement through a character
//! controller. A character controller is the collection of systems that govern
//! the movement of characters.
//!
//! In our case, the character controller has the following logic:
//! - Set [`MovementController`] intent based on directional keyboard input.
//! This is done in the `player` module, as it is specific to the player
//! character.
//! - Apply movement based on [`MovementController`] intent and maximum speed.
//! - Wrap the character within the window.
//!
//! Note that the implementation used here is limited for demonstration
//! purposes. If you want to move the player in a smoother way,
//! consider using a [fixed timestep](https://github.com/bevyengine/bevy/blob/main/examples/movement/physics_in_fixed_timestep.rs).
use bevy::{prelude::*, window::PrimaryWindow};
use crate::AppSet;
pub(super) fn plugin(app: &mut App) {
app.register_type::<(MovementController, ScreenWrap)>();
app.add_systems(
Update,
(apply_movement, apply_screen_wrap)
.chain()
.in_set(AppSet::Update),
);
}
/// These are the movement parameters for our character controller.
/// For now, this is only used for a single player, but it could power NPCs or
/// other players as well.
#[derive(Component, Reflect)]
#[reflect(Component)]
pub struct MovementController {
/// The direction the character wants to move in.
pub intent: Vec2,
/// Maximum speed in world units per second.
/// 1 world unit = 1 pixel when using the default 2D camera and no physics
/// engine.
pub max_speed: f32,
}
impl Default for MovementController {
fn default() -> Self {
Self {
intent: Vec2::ZERO,
// 400 pixels per second is a nice default, but we can still vary this per character.
max_speed: 400.0,
}
}
}
fn apply_movement(
time: Res<Time>,
mut movement_query: Query<(&MovementController, &mut Transform)>,
) {
for (controller, mut transform) in &mut movement_query {
let velocity = controller.max_speed * controller.intent;
transform.translation += velocity.extend(0.0) * time.delta_secs();
}
}
#[derive(Component, Reflect)]
#[reflect(Component)]
pub struct ScreenWrap;
fn apply_screen_wrap(
window_query: Query<&Window, With<PrimaryWindow>>,
mut wrap_query: Query<&mut Transform, With<ScreenWrap>>,
) {
let Ok(window) = window_query.get_single() else {
return;
};
let size = window.size() + 256.0;
let half_size = size / 2.0;
for mut transform in &mut wrap_query {
let position = transform.translation.xy();
let wrapped = (position + half_size).rem_euclid(size) - half_size;
transform.translation = wrapped.extend(transform.translation.z);
}
}