1
1
use std:: f32:: consts:: * ;
2
+ use std:: hash:: Hash ;
2
3
3
- use bevy:: { input:: mouse:: MouseMotion , math :: Vec3Swizzles , prelude:: * } ;
4
+ use bevy:: { input:: mouse:: MouseMotion , prelude:: * } ;
4
5
use bevy_rapier3d:: prelude:: * ;
5
6
6
7
/// Manages the FPS controllers. Executes in `PreUpdate`, after bevy's internal
@@ -33,7 +34,9 @@ impl Plugin for FpsControllerPlugin {
33
34
app. add_systems (
34
35
PreUpdate ,
35
36
(
36
- fps_controller_input,
37
+ fps_controller_reset_input,
38
+ fps_controller_keyboard_mouse_input,
39
+ fps_controller_gamepad_input,
37
40
fps_controller_look,
38
41
fps_controller_move,
39
42
fps_controller_render,
@@ -112,7 +115,7 @@ pub struct FpsController {
112
115
pub yaw : f32 ,
113
116
pub ground_tick : u8 ,
114
117
pub stop_speed : f32 ,
115
- pub sensitivity : f32 ,
118
+ pub mouse_sensitivity : f32 ,
116
119
pub enable_input : bool ,
117
120
pub step_offset : f32 ,
118
121
pub key_forward : KeyCode ,
@@ -125,6 +128,17 @@ pub struct FpsController {
125
128
pub key_jump : KeyCode ,
126
129
pub key_fly : KeyCode ,
127
130
pub key_crouch : KeyCode ,
131
+ pub pad_move_x : GamepadAxis ,
132
+ pub pad_move_y : GamepadAxis ,
133
+ pub pad_look_x : GamepadAxis ,
134
+ pub pad_look_y : GamepadAxis ,
135
+ pub pad_fly_up : GamepadButton ,
136
+ pub pad_fly_down : GamepadButton ,
137
+ pub pad_jump : GamepadButton ,
138
+ pub pad_sprint : GamepadButton ,
139
+ pub pad_fly : GamepadButton ,
140
+ pub pad_crouch : GamepadButton ,
141
+ pub pad_sensitivity : f32 ,
128
142
}
129
143
130
144
impl Default for FpsController {
@@ -171,7 +185,18 @@ impl Default for FpsController {
171
185
key_jump : KeyCode :: Space ,
172
186
key_fly : KeyCode :: KeyF ,
173
187
key_crouch : KeyCode :: ControlLeft ,
174
- sensitivity : 0.001 ,
188
+ mouse_sensitivity : 0.001 ,
189
+ pad_move_x : GamepadAxis :: LeftStickX ,
190
+ pad_move_y : GamepadAxis :: LeftStickY ,
191
+ pad_look_x : GamepadAxis :: RightStickX ,
192
+ pad_look_y : GamepadAxis :: RightStickY ,
193
+ pad_fly_up : GamepadButton :: DPadUp ,
194
+ pad_fly_down : GamepadButton :: DPadDown ,
195
+ pad_jump : GamepadButton :: South ,
196
+ pad_sprint : GamepadButton :: LeftThumb ,
197
+ pad_fly : GamepadButton :: RightThumb ,
198
+ pad_crouch : GamepadButton :: East ,
199
+ pad_sensitivity : 0.025 ,
175
200
}
176
201
}
177
202
}
@@ -188,7 +213,13 @@ const ANGLE_EPSILON: f32 = 0.001953125;
188
213
189
214
const SLIGHT_SCALE_DOWN : f32 = 0.9375 ;
190
215
191
- pub fn fps_controller_input (
216
+ pub fn fps_controller_reset_input ( mut query : Query < & mut FpsControllerInput > ) {
217
+ for mut input in query. iter_mut ( ) {
218
+ * input = default ( ) ;
219
+ }
220
+ }
221
+
222
+ pub fn fps_controller_keyboard_mouse_input (
192
223
key_input : Res < ButtonInput < KeyCode > > ,
193
224
mut mouse_events : EventReader < MouseMotion > ,
194
225
mut query : Query < ( & FpsController , & mut FpsControllerInput ) > ,
@@ -201,7 +232,7 @@ pub fn fps_controller_input(
201
232
for mouse_event in mouse_events. read ( ) {
202
233
mouse_delta += mouse_event. delta ;
203
234
}
204
- mouse_delta *= controller. sensitivity ;
235
+ mouse_delta *= controller. mouse_sensitivity ;
205
236
206
237
input. pitch = ( input. pitch - mouse_delta. y )
207
238
. clamp ( -FRAC_PI_2 + ANGLE_EPSILON , FRAC_PI_2 - ANGLE_EPSILON ) ;
@@ -210,22 +241,57 @@ pub fn fps_controller_input(
210
241
input. yaw = input. yaw . rem_euclid ( TAU ) ;
211
242
}
212
243
213
- input. movement = Vec3 :: new (
214
- get_axis ( & key_input, controller. key_right , controller. key_left ) ,
215
- get_axis ( & key_input, controller. key_up , controller. key_down ) ,
216
- get_axis ( & key_input, controller. key_forward , controller. key_back ) ,
244
+ input. movement + = Vec3 :: new (
245
+ to_axis ( & key_input, controller. key_right , controller. key_left ) ,
246
+ to_axis ( & key_input, controller. key_up , controller. key_down ) ,
247
+ to_axis ( & key_input, controller. key_forward , controller. key_back ) ,
217
248
) ;
218
- input. sprint = key_input. pressed ( controller. key_sprint ) ;
219
- input. jump = key_input. pressed ( controller. key_jump ) ;
220
- input. fly = key_input. just_pressed ( controller. key_fly ) ;
221
- input. crouch = key_input. pressed ( controller. key_crouch ) ;
249
+ input. sprint = input. sprint || key_input. pressed ( controller. key_sprint ) ;
250
+ input. jump = input. jump || key_input. pressed ( controller. key_jump ) ;
251
+ input. fly = input. fly || key_input. just_pressed ( controller. key_fly ) ;
252
+ input. crouch = input. crouch || key_input. pressed ( controller. key_crouch ) ;
253
+ }
254
+ }
255
+
256
+ pub fn fps_controller_gamepad_input (
257
+ gamepads : Query < & Gamepad > ,
258
+ mut query : Query < ( & FpsController , & mut FpsControllerInput ) > ,
259
+ ) {
260
+ for gamepad in gamepads. iter ( ) {
261
+
262
+ for ( controller, mut input) in query. iter_mut ( ) {
263
+ if !controller. enable_input {
264
+ continue ;
265
+ }
266
+
267
+ // Helper function to get axis values
268
+ let axis = |axis_type| gamepad. get ( axis_type) . unwrap ( ) ;
269
+ let move_vec = Vec2 :: new ( axis ( controller. pad_move_x ) , axis ( controller. pad_move_y ) ) ;
270
+ let look_vec = Vec2 :: new ( axis ( controller. pad_look_x ) , axis ( controller. pad_look_y ) )
271
+ * controller. pad_sensitivity ;
272
+
273
+ input. pitch = ( input. pitch + look_vec. y )
274
+ . clamp ( -FRAC_PI_2 + ANGLE_EPSILON , FRAC_PI_2 - ANGLE_EPSILON ) ;
275
+ input. yaw -= look_vec. x ;
276
+ if input. yaw . abs ( ) > PI {
277
+ input. yaw = input. yaw . rem_euclid ( TAU ) ;
278
+ }
279
+
280
+ let vertical_axis = to_axis ( gamepad. digital ( ) , controller. pad_fly_up , controller. pad_fly_down ) ;
281
+
282
+ input. movement += Vec3 :: new ( move_vec. x , vertical_axis, move_vec. y ) ;
283
+ input. sprint = input. sprint || gamepad. pressed ( controller. pad_sprint ) ;
284
+ input. jump = input. jump || gamepad. pressed ( controller. pad_jump ) ;
285
+ input. fly = input. fly || gamepad. just_pressed ( controller. pad_fly ) ;
286
+ input. crouch = input. crouch || gamepad. pressed ( controller. pad_crouch ) ;
287
+ }
222
288
}
223
289
}
224
290
225
291
pub fn fps_controller_look ( mut query : Query < ( & mut FpsController , & FpsControllerInput ) > ) {
226
292
for ( mut controller, input) in query. iter_mut ( ) {
227
- controller. pitch = input. pitch ;
228
- controller. yaw = input. yaw ;
293
+ controller. pitch + = input. pitch ;
294
+ controller. yaw + = input. yaw ;
229
295
}
230
296
}
231
297
@@ -267,8 +333,7 @@ pub fn fps_controller_move(
267
333
} else {
268
334
controller. fly_speed
269
335
} ;
270
- let mut move_to_world =
271
- Mat3 :: from_euler ( EulerRot :: YXZ , input. yaw , input. pitch , 0.0 ) ;
336
+ let mut move_to_world = Mat3 :: from_euler ( EulerRot :: YXZ , controller. yaw , controller. pitch , 0.0 ) ;
272
337
move_to_world. z_axis *= -1.0 ; // Forward is -Z
273
338
move_to_world. y_axis = Vec3 :: Y ; // Vertical movement aligned with world up
274
339
velocity. linvel = move_to_world * input. movement * fly_speed;
@@ -291,7 +356,7 @@ pub fn fps_controller_move(
291
356
) ;
292
357
293
358
let speeds = Vec3 :: new ( controller. side_speed , 0.0 , controller. forward_speed ) ;
294
- let mut move_to_world = Mat3 :: from_axis_angle ( Vec3 :: Y , input . yaw ) ;
359
+ let mut move_to_world = Mat3 :: from_axis_angle ( Vec3 :: Y , controller . yaw ) ;
295
360
move_to_world. z_axis *= -1.0 ; // Forward is -Z
296
361
let mut wish_direction = move_to_world * ( input. movement * speeds) ;
297
362
let mut wish_speed = wish_direction. length ( ) ;
@@ -561,16 +626,9 @@ fn acceleration(
561
626
wish_direction * acceleration_speed
562
627
}
563
628
564
- fn get_pressed ( key_input : & Res < ButtonInput < KeyCode > > , key : KeyCode ) -> f32 {
565
- if key_input. pressed ( key) {
566
- 1.0
567
- } else {
568
- 0.0
569
- }
570
- }
571
-
572
- fn get_axis ( key_input : & Res < ButtonInput < KeyCode > > , key_pos : KeyCode , key_neg : KeyCode ) -> f32 {
573
- get_pressed ( key_input, key_pos) - get_pressed ( key_input, key_neg)
629
+ /// Converts two button inputs into an f32 with a range of [-1, 1]
630
+ fn to_axis < T : Copy + Eq + Send + Sync + Hash > ( input : & ButtonInput < T > , pos : T , neg : T ) -> f32 {
631
+ input. pressed ( pos) as u8 as f32 - input. pressed ( neg) as u8 as f32
574
632
}
575
633
576
634
// ██████╗ ███████╗███╗ ██╗██████╗ ███████╗██████╗
0 commit comments