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,
@@ -110,7 +113,7 @@ pub struct FpsController {
110
113
pub yaw : f32 ,
111
114
pub ground_tick : u8 ,
112
115
pub stop_speed : f32 ,
113
- pub sensitivity : f32 ,
116
+ pub mouse_sensitivity : f32 ,
114
117
pub enable_input : bool ,
115
118
pub step_offset : f32 ,
116
119
pub key_forward : KeyCode ,
@@ -123,6 +126,17 @@ pub struct FpsController {
123
126
pub key_jump : KeyCode ,
124
127
pub key_fly : KeyCode ,
125
128
pub key_crouch : KeyCode ,
129
+ pub pad_move_x : GamepadAxis ,
130
+ pub pad_move_y : GamepadAxis ,
131
+ pub pad_look_x : GamepadAxis ,
132
+ pub pad_look_y : GamepadAxis ,
133
+ pub pad_fly_up : GamepadButton ,
134
+ pub pad_fly_down : GamepadButton ,
135
+ pub pad_jump : GamepadButton ,
136
+ pub pad_sprint : GamepadButton ,
137
+ pub pad_fly : GamepadButton ,
138
+ pub pad_crouch : GamepadButton ,
139
+ pub pad_sensitivity : f32 ,
126
140
}
127
141
128
142
impl Default for FpsController {
@@ -168,7 +182,18 @@ impl Default for FpsController {
168
182
key_jump : KeyCode :: Space ,
169
183
key_fly : KeyCode :: KeyF ,
170
184
key_crouch : KeyCode :: ControlLeft ,
171
- sensitivity : 0.001 ,
185
+ mouse_sensitivity : 0.001 ,
186
+ pad_move_x : GamepadAxis :: LeftStickX ,
187
+ pad_move_y : GamepadAxis :: LeftStickY ,
188
+ pad_look_x : GamepadAxis :: RightStickX ,
189
+ pad_look_y : GamepadAxis :: RightStickY ,
190
+ pad_fly_up : GamepadButton :: DPadUp ,
191
+ pad_fly_down : GamepadButton :: DPadDown ,
192
+ pad_jump : GamepadButton :: South ,
193
+ pad_sprint : GamepadButton :: LeftThumb ,
194
+ pad_fly : GamepadButton :: RightThumb ,
195
+ pad_crouch : GamepadButton :: East ,
196
+ pad_sensitivity : 0.025 ,
172
197
}
173
198
}
174
199
}
@@ -188,7 +213,13 @@ const GROUNDED_DISTANCE: f32 = 0.125;
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 ) > ,
@@ -199,7 +230,7 @@ pub fn fps_controller_input(
199
230
for mouse_event in mouse_events. read ( ) {
200
231
mouse_delta += mouse_event. delta ;
201
232
}
202
- mouse_delta *= controller. sensitivity ;
233
+ mouse_delta *= controller. mouse_sensitivity ;
203
234
204
235
input. pitch = ( input. pitch - mouse_delta. y )
205
236
. clamp ( -FRAC_PI_2 + ANGLE_EPSILON , FRAC_PI_2 - ANGLE_EPSILON ) ;
@@ -208,22 +239,57 @@ pub fn fps_controller_input(
208
239
input. yaw = input. yaw . rem_euclid ( TAU ) ;
209
240
}
210
241
211
- input. movement = Vec3 :: new (
212
- get_axis ( & key_input, controller. key_right , controller. key_left ) ,
213
- get_axis ( & key_input, controller. key_up , controller. key_down ) ,
214
- get_axis ( & key_input, controller. key_forward , controller. key_back ) ,
242
+ input. movement + = Vec3 :: new (
243
+ to_axis ( & key_input, controller. key_right , controller. key_left ) ,
244
+ to_axis ( & key_input, controller. key_up , controller. key_down ) ,
245
+ to_axis ( & key_input, controller. key_forward , controller. key_back ) ,
215
246
) ;
216
- input. sprint = key_input. pressed ( controller. key_sprint ) ;
217
- input. jump = key_input. pressed ( controller. key_jump ) ;
218
- input. fly = key_input. just_pressed ( controller. key_fly ) ;
219
- input. crouch = key_input. pressed ( controller. key_crouch ) ;
247
+ input. sprint = input. sprint || key_input. pressed ( controller. key_sprint ) ;
248
+ input. jump = input. jump || key_input. pressed ( controller. key_jump ) ;
249
+ input. fly = input. fly || key_input. just_pressed ( controller. key_fly ) ;
250
+ input. crouch = input. crouch || key_input. pressed ( controller. key_crouch ) ;
251
+ }
252
+ }
253
+
254
+ pub fn fps_controller_gamepad_input (
255
+ gamepads : Query < & Gamepad > ,
256
+ mut query : Query < ( & FpsController , & mut FpsControllerInput ) > ,
257
+ ) {
258
+ for gamepad in gamepads. iter ( ) {
259
+
260
+ for ( controller, mut input) in query. iter_mut ( ) {
261
+ if !controller. enable_input {
262
+ continue ;
263
+ }
264
+
265
+ // Helper function to get axis values
266
+ let axis = |axis_type| gamepad. get ( axis_type) . unwrap ( ) ;
267
+ let move_vec = Vec2 :: new ( axis ( controller. pad_move_x ) , axis ( controller. pad_move_y ) ) ;
268
+ let look_vec = Vec2 :: new ( axis ( controller. pad_look_x ) , axis ( controller. pad_look_y ) )
269
+ * controller. pad_sensitivity ;
270
+
271
+ input. pitch = ( input. pitch + look_vec. y )
272
+ . clamp ( -FRAC_PI_2 + ANGLE_EPSILON , FRAC_PI_2 - ANGLE_EPSILON ) ;
273
+ input. yaw -= look_vec. x ;
274
+ if input. yaw . abs ( ) > PI {
275
+ input. yaw = input. yaw . rem_euclid ( TAU ) ;
276
+ }
277
+
278
+ let vertical_axis = to_axis ( gamepad. digital ( ) , controller. pad_fly_up , controller. pad_fly_down ) ;
279
+
280
+ input. movement += Vec3 :: new ( move_vec. x , vertical_axis, move_vec. y ) ;
281
+ input. sprint = input. sprint || gamepad. pressed ( controller. pad_sprint ) ;
282
+ input. jump = input. jump || gamepad. pressed ( controller. pad_jump ) ;
283
+ input. fly = input. fly || gamepad. just_pressed ( controller. pad_fly ) ;
284
+ input. crouch = input. crouch || gamepad. pressed ( controller. pad_crouch ) ;
285
+ }
220
286
}
221
287
}
222
288
223
289
pub fn fps_controller_look ( mut query : Query < ( & mut FpsController , & FpsControllerInput ) > ) {
224
290
for ( mut controller, input) in query. iter_mut ( ) {
225
- controller. pitch = input. pitch ;
226
- controller. yaw = input. yaw ;
291
+ controller. pitch + = input. pitch ;
292
+ controller. yaw + = input. yaw ;
227
293
}
228
294
}
229
295
@@ -265,7 +331,7 @@ pub fn fps_controller_move(
265
331
} else {
266
332
controller. fly_speed
267
333
} ;
268
- let mut move_to_world = Mat3 :: from_euler ( EulerRot :: YXZ , input . yaw , input . pitch , 0.0 ) ;
334
+ let mut move_to_world = Mat3 :: from_euler ( EulerRot :: YXZ , controller . yaw , controller . pitch , 0.0 ) ;
269
335
move_to_world. z_axis *= -1.0 ; // Forward is -Z
270
336
move_to_world. y_axis = Vec3 :: Y ; // Vertical movement aligned with world up
271
337
velocity. linvel = move_to_world * input. movement * fly_speed;
@@ -288,7 +354,7 @@ pub fn fps_controller_move(
288
354
) ;
289
355
290
356
let speeds = Vec3 :: new ( controller. side_speed , 0.0 , controller. forward_speed ) ;
291
- let mut move_to_world = Mat3 :: from_axis_angle ( Vec3 :: Y , input . yaw ) ;
357
+ let mut move_to_world = Mat3 :: from_axis_angle ( Vec3 :: Y , controller . yaw ) ;
292
358
move_to_world. z_axis *= -1.0 ; // Forward is -Z
293
359
let mut wish_direction = move_to_world * ( input. movement * speeds) ;
294
360
let mut wish_speed = wish_direction. length ( ) ;
@@ -543,16 +609,9 @@ fn acceleration(
543
609
wish_direction * acceleration_speed
544
610
}
545
611
546
- fn get_pressed ( key_input : & Res < ButtonInput < KeyCode > > , key : KeyCode ) -> f32 {
547
- if key_input. pressed ( key) {
548
- 1.0
549
- } else {
550
- 0.0
551
- }
552
- }
553
-
554
- fn get_axis ( key_input : & Res < ButtonInput < KeyCode > > , key_pos : KeyCode , key_neg : KeyCode ) -> f32 {
555
- get_pressed ( key_input, key_pos) - get_pressed ( key_input, key_neg)
612
+ /// Converts two button inputs into an f32 with a range of [-1, 1]
613
+ fn to_axis < T : Copy + Eq + Send + Sync + Hash > ( input : & ButtonInput < T > , pos : T , neg : T ) -> f32 {
614
+ input. pressed ( pos) as u8 as f32 - input. pressed ( neg) as u8 as f32
556
615
}
557
616
558
617
// ██████╗ ███████╗███╗ ██╗██████╗ ███████╗██████╗
0 commit comments