1 #ifndef PLAYER_DEVICE_WALK_H
2 #define PLAYER_DEVICE_WALK_H
4 #include "player_interface.h"
11 k_walk_air_accel
= 7.0f
,
12 k_walk_friction
= 10.0f
,
13 k_walk_step_height
= 0.2f
;
15 struct player_device_walk
26 k_walk_activity_ground
,
33 enum mdl_surface_prop surface
;
36 VG_STATIC
void player_walk_pre_update( player_interface
*player
,
37 player_attachment
*at
)
39 struct player_device_walk
*w
= at
->storage
;
40 player_look( player
, w
->state
.angles
);
43 v3f walk
= { player
->input_walkh
->axis
.value
,
45 -player
->input_walkv
->axis
.value
};
47 v3_muls( walk
, 10.0f
* vg
.time_delta
, walk
);
50 euler_m3x3( w
->angles
, m
);
51 v3_muladds( player
->rb
.co
, m
[0], walk
[0], player
->rb
.co
);
52 v3_muladds( player
->rb
.co
, m
[1], walk
[1], player
->rb
.co
);
53 v3_muladds( player
->rb
.co
, m
[2], walk
[2], player
->rb
.co
);
57 VG_STATIC
int player_walk_normal_standable( v3f n
)
59 return n
[1] > 0.70710678118f
;
62 VG_STATIC
void player_accelerate( v3f v
, v3f movedir
, float speed
, float accel
)
64 float currentspeed
= v3_dot( v
, movedir
),
65 addspeed
= speed
- currentspeed
;
70 float accelspeed
= accel
* k_rb_delta
* speed
;
72 if( accelspeed
> addspeed
)
73 accelspeed
= addspeed
;
75 v3_muladds( v
, movedir
, accelspeed
, v
);
78 VG_STATIC
void player_friction( v3f v
)
80 float speed
= v3_length( v
),
82 control
= vg_maxf( speed
, k_stopspeed
);
87 drop
+= control
* k_walk_friction
* k_rb_delta
;
89 float newspeed
= vg_maxf( 0.0f
, speed
- drop
);
92 v3_muls( v
, newspeed
, v
);
95 VG_STATIC
void player_walk_update( player_interface
*player
,
96 player_attachment
*at
)
98 struct player_device_walk
*w
= at
->storage
;
99 w
->collider
.height
= 2.0f
;
100 w
->collider
.radius
= 0.3f
;
103 m3x3_identity( mtx
);
104 v3_add( player
->rb
.co
, (v3f
){0.0f
, 1.0f
, 0.0f
}, mtx
[3] );
106 debug_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__WHITE
);
111 float yaw
= w
->state
.angles
[0];
113 v3f forward_dir
= { sinf(yaw
), 0.0f
, -cosf(yaw
) };
114 v3f right_dir
= { -forward_dir
[2], 0.0f
, forward_dir
[0] };
116 v2f walk
= { player
->input_walkh
->axis
.value
,
117 player
->input_walkv
->axis
.value
};
119 if( v2_length2(walk
) > 0.001f
)
120 v2_normalize_clamp( walk
);
123 * Collision detection
125 len
= rb_capsule__scene( mtx
, &w
->collider
, NULL
,
126 &world
.rb_geo
.inf
.scene
, manifold
);
127 rb_manifold_filter_coplanar( manifold
, len
, 0.01f
);
128 len
= rb_manifold_apply_filtered( manifold
, len
);
130 v3f surface_avg
= { 0.0f
, 0.0f
, 0.0f
};
131 w
->state
.activity
= k_walk_activity_air
;
133 for( int i
=0; i
<len
; i
++ )
135 struct contact
*ct
= &manifold
[i
];
136 rb_debug_contact( ct
);
138 if( player_walk_normal_standable( ct
->n
) )
140 w
->state
.activity
= k_walk_activity_ground
;
141 v3_add( surface_avg
, ct
->n
, surface_avg
);
144 rb_prepare_contact( ct
);
151 float accel_speed
= 0.0f
, nominal_speed
= 0.0f
;
153 v3_muls( right_dir
, walk
[0], movedir
);
154 v3_muladds( movedir
, forward_dir
, walk
[1], movedir
);
156 if( w
->state
.activity
== k_walk_activity_ground
)
158 v3_normalize( surface_avg
);
161 rb_tangent_basis( surface_avg
, tx
, ty
);
163 if( v2_length2(walk
) > 0.001f
)
165 /* clip movement to the surface */
166 float d
= v3_dot(surface_avg
,movedir
);
167 v3_muladds( movedir
, surface_avg
, -d
, movedir
);
170 accel_speed
= k_walk_accel
;
171 nominal_speed
= k_walkspeed
;
174 if( player
->input_jump
->button
.value
)
176 player
->rb
.v
[1] = 5.0f
;
177 w
->state
.activity
= k_walk_activity_air
;
178 accel_speed
= k_walk_air_accel
;
179 nominal_speed
= k_airspeed
;
183 player_friction( player
->rb
.v
);
185 struct world_material
*surface_mat
= world_contact_material(manifold
);
186 w
->surface
= surface_mat
->info
.surface_prop
;
191 accel_speed
= k_walk_air_accel
;
192 nominal_speed
= k_airspeed
;
195 if( v2_length2(walk
) > 0.001f
)
197 vg_info( "%f %f\n", walk
[0], walk
[1] );
198 player_accelerate( player
->rb
.v
, movedir
, nominal_speed
, accel_speed
);
199 v3_normalize( movedir
);
203 * Resolve velocity constraints
205 for( int j
=0; j
<5; j
++ )
207 for( int i
=0; i
<len
; i
++ )
209 struct contact
*ct
= &manifold
[i
];
212 float vn
= -v3_dot( player
->rb
.v
, ct
->n
);
214 float temp
= ct
->norm_impulse
;
215 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
216 vn
= ct
->norm_impulse
- temp
;
218 v3_muladds( player
->rb
.v
, ct
->n
, vn
, player
->rb
.v
);
227 for( int j
=0; j
<8; j
++ )
229 for( int i
=0; i
<len
; i
++ )
231 struct contact
*ct
= &manifold
[i
];
233 float resolved_amt
= v3_dot( ct
->n
, dt
),
234 remaining
= (ct
->p
-k_penetration_slop
) - resolved_amt
,
235 apply
= vg_maxf( remaining
, 0.0f
) * 0.3f
;
237 v3_muladds( dt
, ct
->n
, apply
, dt
);
240 v3_add( dt
, player
->rb
.co
, player
->rb
.co
);
242 /* TODO: Stepping......
244 * ideas; walkgrid style steps
247 if( w
->state
.activity
== k_walk_activity_ground
)
250 float max_dist
= 0.4f
;
253 v3_copy( player
->rb
.co
, pa
);
254 pa
[1] += w
->collider
.radius
+ max_dist
;
256 v3_muladds( pa
, (v3f
){0.0f
,1.0f
,0.0f
}, -max_dist
* 2.0f
, pb
);
257 vg_line( pa
, pb
, 0xff000000 );
261 if( spherecast_world( pa
, pb
, w
->collider
.radius
, &t
, n
) != -1 )
263 if( player_walk_normal_standable( n
) )
265 v3_lerp( pa
, pb
, t
, player
->rb
.co
);
266 player
->rb
.co
[1] -= w
->collider
.radius
;
274 if( w
->state
.activity
== k_walk_activity_air
)
275 player
->rb
.v
[1] += -k_gravity
* k_rb_delta
;
277 v3_muladds( player
->rb
.co
, player
->rb
.v
, k_rb_delta
, player
->rb
.co
);
280 v3_add( player
->rb
.co
, (v3f
){0.0f
, 1.0f
, 0.0f
}, mtx
[3] );
281 debug_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__GREEN
);
284 VG_STATIC
void player_walk_post_update( player_interface
*player
,
285 player_attachment
*at
)
290 VG_STATIC
void player_walk_get_camera( player_interface
*player
,
291 player_attachment
*at
, camera
*cam
)
293 struct player_device_walk
*w
= at
->storage
;
295 float substep
= vg_clampf( vg
.accumulator
/ k_rb_delta
, 0.0f
, 1.0f
);
297 v3_muladds( player
->rb
.co
, player
->rb
.v
, k_rb_delta
*substep
, pos
);
299 v3_add( pos
, (v3f
){0.0f
,1.8f
,0.0f
}, cam
->pos
);
300 v3_copy( w
->state
.angles
, cam
->angles
);
304 VG_STATIC
void player_walk_ui( player_interface
*player
,
305 player_attachment
*at
)
307 player_debugtext( 1, "V: %5.2f %5.2f %5.2f",player
->rb
.v
[0],
310 player_debugtext( 1, "CO: %5.2f %5.2f %5.2f",player
->rb
.co
[0],
315 player_device player_device_walk
=
317 .pre_update
= player_walk_pre_update
,
318 .update
= player_walk_update
,
319 .post_update
= player_walk_post_update
,
320 .get_camera
= player_walk_get_camera
,
321 .debug_ui
= player_walk_ui
324 #endif /* PLAYER_DEVICE_WALK_H */