bevy_dev/debug_camera/
controller.rs

1use std::f32::consts::PI;
2
3use bevy::{
4    input::mouse::{MouseMotion, MouseWheel},
5    prelude::*,
6};
7
8#[cfg(feature = "ui")]
9use crate::ui::popup::{PopupEvent, PopupPosition};
10
11use super::{DebugCamera, DebugCameraControls, DebugCameraData};
12
13const MOUSE_LOOK_X_LIMIT: f32 = PI / 2.0;
14const RESET_SPEED_THRESHOLD_IN_SECONDS: f32 = 0.2;
15
16pub(super) fn system(
17    mut cameras: Query<(
18        &mut Transform,
19        &mut DebugCameraData,
20        &mut DebugCamera,
21        &Camera,
22    )>,
23    mut mouse_motion: EventReader<MouseMotion>,
24    mut mouse_wheel: EventReader<MouseWheel>,
25    time: Res<Time>,
26    keys: Res<ButtonInput<KeyCode>>,
27    controls: Res<DebugCameraControls>,
28    #[cfg(feature = "ui")] mut popup_event: EventWriter<PopupEvent>,
29) {
30    let (mut transform, mut data, mut debug_camera, _) =
31        match cameras.iter_mut().find(|x| x.3.is_active) {
32            Some(v) => v,
33            None => return,
34        };
35
36    // Speed
37    for input in mouse_wheel.read() {
38        data.speed_level += input.y;
39        data.speed_level = data.speed_level.clamp(
40            (debug_camera.speed_multiplier_range.start().log2() * 4.0).floor(),
41            (debug_camera.speed_multiplier_range.end().log2() * 4.0).ceil(),
42        );
43
44        debug_camera.speed_multiplier = 2.0f32.powf(data.speed_level * 0.25).clamp(
45            *debug_camera.speed_multiplier_range.start(),
46            *debug_camera.speed_multiplier_range.end(),
47        );
48
49        #[cfg(feature = "ui")]
50        {
51            let value = debug_camera.speed_multiplier;
52            popup_event.write(PopupEvent::new(
53                PopupPosition::BelowCenter,
54                0.5,
55                move |ui| {
56                    ui.label(format!("Speed multiplier: {:.2}", value));
57                },
58            ));
59        }
60    }
61
62    // Position
63    let mut translation = Vec3::ZERO;
64    if keys.pressed(controls.move_forward) {
65        translation -= Vec3::from(transform.local_z());
66    }
67    if keys.pressed(controls.move_backward) {
68        translation += Vec3::from(transform.local_z());
69    }
70    if keys.pressed(controls.move_left) {
71        translation -= Vec3::from(transform.local_x());
72    }
73    if keys.pressed(controls.move_right) {
74        translation += Vec3::from(transform.local_x());
75    }
76    if keys.pressed(controls.move_up) {
77        translation += Vec3::Y;
78    }
79    if keys.pressed(controls.move_down) {
80        translation -= Vec3::Y;
81    }
82
83    transform.translation += translation.normalize_or_zero()
84        * (data.current_speed * debug_camera.speed_multiplier * time.delta_secs());
85
86    // Rotation
87    for input in mouse_motion.read() {
88        let (mut y, mut x, _) = transform.rotation.to_euler(EulerRot::YXZ);
89
90        x -= (input.delta.y * debug_camera.sensitivity).to_radians();
91        x = x.clamp(-MOUSE_LOOK_X_LIMIT, MOUSE_LOOK_X_LIMIT);
92
93        y -= (input.delta.x * debug_camera.sensitivity).to_radians();
94
95        transform.rotation = Quat::from_rotation_y(y) * Quat::from_rotation_x(x);
96    }
97
98    // Increase speed
99    if translation != Vec3::ZERO {
100        data.current_speed += data.current_speed * time.delta_secs() * debug_camera.speed_increase;
101        data.last_change_position_time = time.elapsed_secs();
102    } else if data.last_change_position_time > RESET_SPEED_THRESHOLD_IN_SECONDS {
103        data.current_speed = debug_camera.base_speed;
104    }
105}