@@ -4,78 +4,108 @@ use std::f32::consts::FRAC_PI_2;
4
4
5
5
use crate :: debug:: DebugUISet ;
6
6
7
- // Reusing the player controller impl for now.
7
+ const BODY_ROTATION_SLERP : f32 = 0.5 ;
8
8
9
- pub const DEFAULT_CAMERA_SENS : f32 = 0.005 ;
9
+ #[ derive( Component ) ]
10
+ pub struct Player ;
11
+
12
+ /// Marker component for player body.
13
+ #[ derive( Component ) ]
14
+ pub struct Body ;
10
15
11
- #[ derive( Default , Component ) ]
12
- pub struct PlayerController {
13
- yaw : f32 ,
14
- pitch : f32 ,
15
- cursor_locked : bool ,
16
+ #[ derive( Component ) ]
17
+ pub struct Head ;
18
+
19
+ #[ derive( Component , Debug , Clone , Copy ) ]
20
+ pub enum CameraMode {
21
+ FirstPerson ,
22
+ ThirdPersonForward ,
16
23
}
17
24
18
- pub fn handle_player_mouse_move (
19
- mut query : Query < ( & mut PlayerController , & mut Transform ) > ,
20
- mut mouse_motion_event_reader : EventReader < MouseMotion > ,
21
- mut window : Query < & mut Window > ,
22
- ) {
23
- let ( mut controller , mut transform ) = query . single_mut ( ) ;
24
- let mut delta = Vec2 :: ZERO ;
25
+ impl CameraMode {
26
+ fn next ( self ) -> Self {
27
+ match self {
28
+ Self :: FirstPerson => Self :: ThirdPersonForward ,
29
+ Self :: ThirdPersonForward => Self :: FirstPerson ,
30
+ }
31
+ }
25
32
26
- if controller. cursor_locked {
27
- for mouse_move in mouse_motion_event_reader. iter ( ) {
28
- delta += mouse_move. delta ;
33
+ fn translation ( self ) -> Vec3 {
34
+ match self {
35
+ Self :: FirstPerson => Vec3 :: ZERO ,
36
+ Self :: ThirdPersonForward => Vec3 :: Z * -5.0 ,
29
37
}
30
38
}
39
+ }
31
40
32
- let mut first_win = window. single_mut ( ) ;
33
- first_win. cursor . visible = !controller. cursor_locked ;
34
- first_win. cursor . grab_mode = if controller. cursor_locked {
35
- CursorGrabMode :: Locked
36
- } else {
37
- CursorGrabMode :: None
38
- } ;
41
+ // Reusing the player controller impl for now.
39
42
40
- if delta == Vec2 :: ZERO {
41
- return ;
42
- }
43
+ pub const DEFAULT_CAMERA_SENS : f32 = 0.005 ;
43
44
44
- let mut new_pitch = delta. y . mul_add ( DEFAULT_CAMERA_SENS , controller. pitch ) ;
45
- let new_yaw = delta. x . mul_add ( -DEFAULT_CAMERA_SENS , controller. yaw ) ;
45
+ fn handle_player_mouse_move (
46
+ mut head : Query < & mut Transform , With < Head > > ,
47
+ mut mouse_motion_event_reader : EventReader < MouseMotion > ,
48
+ windows : Query < & Window > ,
49
+ ) {
50
+ let window = windows. single ( ) ;
51
+ let mut head_transform = head. single_mut ( ) ;
52
+ let mut delta = Vec2 :: ZERO ;
46
53
47
- new_pitch = new_pitch. clamp ( -FRAC_PI_2 , FRAC_PI_2 ) ;
54
+ for mouse_move in mouse_motion_event_reader. iter ( ) {
55
+ delta -= mouse_move. delta ;
56
+ }
48
57
49
- controller. yaw = new_yaw;
50
- controller. pitch = new_pitch;
58
+ if !matches ! ( window. cursor. grab_mode, CursorGrabMode :: Locked ) {
59
+ return ;
60
+ }
51
61
52
- transform. rotation =
53
- Quat :: from_axis_angle ( Vec3 :: Y , new_yaw) * Quat :: from_axis_angle ( -Vec3 :: X , new_pitch) ;
62
+ let ( yaw, pitch, _roll) = head_transform. rotation . to_euler ( EulerRot :: YXZ ) ;
63
+ let yaw = delta. x . mul_add ( DEFAULT_CAMERA_SENS , yaw) ;
64
+ let pitch = delta
65
+ . y
66
+ . mul_add ( -DEFAULT_CAMERA_SENS , pitch)
67
+ // ensure that the look direction always has a component in the xz plane:
68
+ . clamp ( -FRAC_PI_2 + 1e-5 , FRAC_PI_2 - 1e-5 ) ;
69
+ head_transform. rotation = Quat :: from_euler ( EulerRot :: YXZ , yaw, pitch, 0. ) ;
54
70
}
55
71
56
- pub fn handle_player_input (
72
+ fn handle_player_keyboard_input (
57
73
mut egui : EguiContexts ,
58
- mut query : Query < ( & mut PlayerController , & mut Transform ) > ,
74
+ // mut queries: ParamSet<Query<&mut Transform, With<Body>>>,
75
+ mut queries : ParamSet < (
76
+ Query < & mut Transform , With < Player > > ,
77
+ Query < & Transform , With < Body > > ,
78
+ ) > ,
59
79
keys : Res < Input < KeyCode > > ,
60
80
btns : Res < Input < MouseButton > > ,
81
+ mut windows : Query < & mut Window > ,
61
82
) {
62
- let ( mut controller , mut transform ) = query . single_mut ( ) ;
83
+ let mut window = windows . single_mut ( ) ;
63
84
64
85
// cursor grabbing
65
- // @todo: this should prevent cursor grabbing when the user is interacting with a debug UI. Why doesn't this work?
66
86
if btns. just_pressed ( MouseButton :: Left ) && !egui. ctx_mut ( ) . wants_pointer_input ( ) {
67
- controller. cursor_locked = true ;
87
+ window. cursor . grab_mode = CursorGrabMode :: Locked ;
88
+ window. cursor . visible = false ;
68
89
}
69
90
70
91
// cursor ungrabbing
71
92
if keys. just_pressed ( KeyCode :: Escape ) {
72
- controller. cursor_locked = false ;
93
+ window. cursor . grab_mode = CursorGrabMode :: None ;
94
+ window. cursor . visible = true ;
73
95
}
74
- let mut direction = Vec3 :: ZERO ;
75
96
76
- let forward = transform. rotation . mul_vec3 ( Vec3 :: Z ) . normalize ( ) * Vec3 :: new ( 1.0 , 0. , 1.0 ) ;
77
- let right = transform. rotation . mul_vec3 ( Vec3 :: X ) . normalize ( ) ;
97
+ let ( forward, right) = {
98
+ let body = queries. p1 ( ) ;
99
+ let body_transform = body. single ( ) ;
100
+ let forward = body_transform. rotation . mul_vec3 ( Vec3 :: Z ) . normalize ( ) ;
101
+ let right = Vec3 :: Y . cross ( forward) ; // @todo(meyerzinn): not sure why this is the correct orientation
102
+ ( forward, right)
103
+ } ;
104
+
105
+ let mut body = queries. p0 ( ) ;
106
+ let mut body_transform = body. single_mut ( ) ;
78
107
108
+ let mut direction = Vec3 :: ZERO ;
79
109
let mut acceleration = 1.0f32 ;
80
110
81
111
if keys. pressed ( KeyCode :: W ) {
@@ -111,11 +141,39 @@ pub fn handle_player_input(
111
141
}
112
142
113
143
// hardcoding 0.10 as a factor for now to not go zoomin across the world.
114
- transform . translation += direction. x * right * acceleration
144
+ body_transform . translation += direction. x * right * acceleration
115
145
+ direction. z * forward * acceleration
116
146
+ direction. y * Vec3 :: Y * acceleration;
117
147
}
118
148
149
+ fn handle_player_change_camera_mode (
150
+ keys : Res < Input < KeyCode > > ,
151
+ mut cameras : Query < ( & mut CameraMode , & mut Transform ) > ,
152
+ ) {
153
+ if keys. just_pressed ( KeyCode :: F5 ) {
154
+ let ( mut mode, mut transform) = cameras. single_mut ( ) ;
155
+ * mode = mode. next ( ) ;
156
+ transform. translation = mode. translation ( ) ;
157
+ }
158
+ }
159
+
160
+ fn update_player_body_rotation (
161
+ mut queries : ParamSet < (
162
+ Query < & mut Transform , With < Body > > ,
163
+ Query < & Transform , With < Head > > ,
164
+ ) > ,
165
+ ) {
166
+ let yaw = {
167
+ let head = queries. p1 ( ) ;
168
+ let ( yaw, _pitch, _roll) = head. single ( ) . rotation . to_euler ( EulerRot :: YXZ ) ;
169
+ yaw
170
+ } ;
171
+ let mut body = queries. p0 ( ) ;
172
+ let mut body_transform = body. single_mut ( ) ;
173
+ let desired = Quat :: from_euler ( EulerRot :: YXZ , yaw, 0. , 0. ) ;
174
+ body_transform. rotation = body_transform. rotation . slerp ( desired, BODY_ROTATION_SLERP ) ;
175
+ }
176
+
119
177
#[ derive( Hash , Copy , Clone , PartialEq , Eq , Debug , SystemSet ) ]
120
178
/// Systems related to player controls.
121
179
pub struct PlayerControllerSet ;
@@ -125,7 +183,12 @@ pub struct VoxelWorldPlayerControllerPlugin;
125
183
impl Plugin for VoxelWorldPlayerControllerPlugin {
126
184
fn build ( & self , app : & mut App ) {
127
185
app. add_systems (
128
- ( handle_player_input, handle_player_mouse_move)
186
+ (
187
+ handle_player_mouse_move,
188
+ update_player_body_rotation,
189
+ handle_player_keyboard_input,
190
+ handle_player_change_camera_mode,
191
+ )
129
192
. chain ( )
130
193
. in_base_set ( CoreSet :: Update )
131
194
. after ( DebugUISet :: Display ) ,
0 commit comments