1use bevy::input::mouse::MouseMotion;
4use bevy::prelude::*;
5
6pub struct CameraPlugin;
7
8impl Plugin for CameraPlugin {
9 fn build(&self, app: &mut App) {
10 app.add_systems(Startup, spawn_camera)
11 .add_systems(Update, (camera_look, camera_move, camera_reset));
12 }
13}
14
15const DEFAULT_CAM_POS: Vec3 = Vec3::new(1.0, 1.7, 5.0); const DEFAULT_LOOK_AT: Vec3 = Vec3::new(5.0, 4.0, 15.0); #[derive(Component)]
21pub struct FirstPersonCamera {
22 pub speed: f32,
23 pub sensitivity: f32,
24 pub pitch: f32,
25 pub yaw: f32,
26}
27
28impl Default for FirstPersonCamera {
29 fn default() -> Self {
30 Self {
31 speed: 3.0,
32 sensitivity: 0.003,
33 pitch: 0.0,
34 yaw: 0.8, }
36 }
37}
38
39fn direction_to_yaw_pitch(dir: Vec3) -> (f32, f32) {
41 let yaw = dir.z.atan2(dir.x) - std::f32::consts::FRAC_PI_2;
42 let pitch = (-dir.y).asin();
43 (yaw, pitch)
44}
45
46fn default_yaw_pitch() -> (f32, f32) {
48 let dir = (DEFAULT_LOOK_AT - DEFAULT_CAM_POS).normalize();
49 direction_to_yaw_pitch(dir)
50}
51
52fn spawn_camera(mut commands: Commands) {
53 let (yaw, pitch) = default_yaw_pitch();
54 commands.spawn((
55 Camera3d::default(),
56 Transform::from_translation(DEFAULT_CAM_POS).with_rotation(Quat::from_euler(
57 EulerRot::YXZ,
58 yaw,
59 pitch,
60 0.0,
61 )),
62 FirstPersonCamera {
63 yaw,
64 pitch,
65 ..default()
66 },
67 ));
68}
69
70fn camera_reset(
72 mut query: Query<(&mut Transform, &mut FirstPersonCamera)>,
73 keyboard: Res<ButtonInput<KeyCode>>,
74) {
75 if keyboard.just_pressed(KeyCode::KeyR) || keyboard.just_pressed(KeyCode::Home) {
76 let (yaw, pitch) = default_yaw_pitch();
77 for (mut transform, mut camera) in query.iter_mut() {
78 transform.translation = DEFAULT_CAM_POS;
79 camera.yaw = yaw;
80 camera.pitch = pitch;
81 transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, 0.0);
82 }
83 }
84}
85
86fn camera_look(
87 mut query: Query<(&mut Transform, &mut FirstPersonCamera)>,
88 mut mouse_motion: EventReader<MouseMotion>,
89 mouse_button: Res<ButtonInput<MouseButton>>,
90) {
91 if !mouse_button.pressed(MouseButton::Right) {
93 mouse_motion.clear();
94 return;
95 }
96
97 let mut delta = Vec2::ZERO;
98 for event in mouse_motion.read() {
99 delta += event.delta;
100 }
101
102 if delta == Vec2::ZERO {
103 return;
104 }
105
106 for (mut transform, mut camera) in query.iter_mut() {
107 camera.yaw -= delta.x * camera.sensitivity;
108 camera.pitch -= delta.y * camera.sensitivity;
109 camera.pitch = camera.pitch.clamp(-1.5, 1.5);
110
111 transform.rotation = Quat::from_euler(EulerRot::YXZ, camera.yaw, camera.pitch, 0.0);
112 }
113}
114
115fn camera_move(
116 mut query: Query<(&mut Transform, &FirstPersonCamera)>,
117 keyboard: Res<ButtonInput<KeyCode>>,
118 time: Res<Time>,
119) {
120 for (mut transform, camera) in query.iter_mut() {
121 let mut direction = Vec3::ZERO;
122
123 let forward = transform.forward();
125 let forward_flat = Vec3::new(forward.x, 0.0, forward.z).normalize_or_zero();
126 let right = transform.right();
127 let right_flat = Vec3::new(right.x, 0.0, right.z).normalize_or_zero();
128
129 if keyboard.pressed(KeyCode::KeyW) || keyboard.pressed(KeyCode::ArrowUp) {
131 direction += forward_flat;
132 }
133 if keyboard.pressed(KeyCode::KeyS) || keyboard.pressed(KeyCode::ArrowDown) {
134 direction -= forward_flat;
135 }
136 if keyboard.pressed(KeyCode::KeyA) || keyboard.pressed(KeyCode::ArrowLeft) {
137 direction -= right_flat;
138 }
139 if keyboard.pressed(KeyCode::KeyD) || keyboard.pressed(KeyCode::ArrowRight) {
140 direction += right_flat;
141 }
142
143 if keyboard.pressed(KeyCode::KeyQ) {
145 direction += Vec3::Y;
146 }
147 if keyboard.pressed(KeyCode::KeyE) {
148 direction -= Vec3::Y;
149 }
150
151 if direction != Vec3::ZERO {
153 direction = direction.normalize();
154 transform.translation += direction * camera.speed * time.delta_secs();
155 }
156 }
157}