8 VG_STATIC
void player_walk_drop_in_vector( player_instance
*player
, v3f vec
)
10 struct player_walk
*w
= &player
->_walk
;
13 v3_cross( player
->basis
[1], w
->state
.drop_in_normal
, axis
);
14 v3_cross( axis
, w
->state
.drop_in_normal
, init_dir
);
15 v3_normalize( init_dir
);
16 v3_muls( init_dir
, 7.0f
, vec
);
19 VG_STATIC
float player_xyspeed2( player_instance
*player
)
22 v3_muladds( player
->rb
.v
, player
->basis
[1],
23 -v3_dot( player
->basis
[1], player
->rb
.v
), xy
);
25 return v3_length2(xy
);
28 VG_STATIC
void player_walk_generic_to_skate( player_instance
*player
,
29 enum skate_activity init
,
32 player
->subsystem
= k_player_subsystem_skate
;
34 struct player_walk
*w
= &player
->_walk
;
35 struct player_skate
*s
= &player
->_skate
;
39 if( player_xyspeed2(player
) < 0.1f
* 0.1f
)
40 q_mulv( player
->rb
.q
, (v3f
){0.0f
,0.0f
,1.6f
}, v
);
42 v3_copy( player
->rb
.v
, v
);
44 s
->state
.activity_prev
= k_skate_activity_ground
;
45 s
->state
.activity
= init
;
50 m3x3_mulv( player
->invbasis
, dir
, dir
);
52 q_axis_angle( player
->rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, atan2f(-dir
[0],-dir
[2]) );
53 q_mul( player
->qbasis
, player
->rb
.q
, player
->rb
.q
);
54 q_normalize( player
->rb
.q
);
56 q_mulv( player
->rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, s
->state
.cog
);
57 v3_add( s
->state
.cog
, player
->rb
.co
, s
->state
.cog
);
59 v3_copy( v
, s
->state
.cog_v
);
60 v3_copy( v
, player
->rb
.v
);
62 player__begin_holdout( player
);
63 player__skate_reset_animator( player
);
64 player__skate_clear_mechanics( player
);
65 rb_update_transform( &player
->rb
);
66 v3_copy( (v3f
){yaw
,0.0f
,0.0f
}, s
->state
.trick_euler
);
68 if( init
== k_skate_activity_air
)
69 player__approximate_best_trajectory( player
);
72 VG_STATIC
void player_walk_drop_in_to_skate( player_instance
*player
)
75 player
->subsystem
= k_player_subsystem_skate
;
77 struct player_walk
*w
= &player
->_walk
;
78 struct player_skate
*s
= &player
->_skate
;
79 s
->state
.activity_prev
= k_skate_activity_ground
;
80 s
->state
.activity
= k_skate_activity_ground
;
82 player__begin_holdout( player
);
83 player__skate_clear_mechanics( player
);
84 player__skate_reset_animator( player
);
87 player_walk_drop_in_vector( player
, init_velocity
);
89 rb_update_transform( &player
->rb
);
90 v3_muladds( player
->rb
.co
, player
->rb
.to_world
[1], 1.0f
, s
->state
.cog
);
91 v3_copy( init_velocity
, s
->state
.cog_v
);
92 v3_copy( init_velocity
, player
->rb
.v
);
93 v3_copy( init_velocity
, player
->cam_control
.cam_velocity_smooth
);
94 v3_copy( (v3f
){1.0f
,0.0f
,0.0f
}, s
->state
.trick_euler
);
97 VG_STATIC
void player_walk_drop_in_overhang_transform( player_instance
*player
,
101 struct player_walk
*w
= &player
->_walk
;
104 v3_cross( player
->basis
[1], w
->state
.drop_in_normal
, axis
);
105 v3_normalize( axis
);
107 float a
= acosf( w
->state
.drop_in_normal
[1] ) * t
;
109 q_axis_angle( q
, axis
, a
);
112 heading_angle
= w
->state
.drop_in_angle
;
115 overhang
[0] = sinf( heading_angle
) * l
;
116 overhang
[1] = 0.28f
* l
;
117 overhang
[2] = cosf( heading_angle
) * l
;
119 q_mulv( q
, overhang
, overhang
);
120 v3_add( w
->state
.drop_in_target
, overhang
, co
);
123 VG_STATIC
int player_walk_scan_for_drop_in( player_instance
*player
)
125 struct player_walk
*w
= &player
->_walk
;
126 world_instance
*world
= world_current_instance();
129 q_mulv( player
->rb
.q
, (v3f
){0.0f
,0.0f
,1.0f
}, dir
);
130 v3_muladds( player
->rb
.co
, player
->rb
.to_world
[1], -1.0f
, center
);
133 int sample_count
= 0;
135 for( int i
=0; i
<20; i
++ )
137 float t
= (float)i
* (1.0f
/19.0f
),
138 s
= sinf( t
* VG_PIf
* 0.25f
),
139 c
= cosf( t
* VG_PIf
* 0.25f
);
142 v3_muls ( player
->rb
.to_world
[1], -c
, ray_dir
);
143 v3_muladds( ray_dir
, dir
, -s
, ray_dir
);
144 v3_muladds( center
, ray_dir
, -2.0f
, pos
);
146 ray_hit
*ray
= &samples
[ sample_count
];
149 if( ray_world( world
, pos
, ray_dir
, ray
, 0 ) ){
150 vg_line( pos
, ray
->pos
, VG__RED
);
151 vg_line_point( ray
->pos
, 0.025f
, VG__BLACK
);
157 float min_a
= 0.70710678118654752f
;
158 ray_hit
*candidate
= NULL
;
160 if( sample_count
>= 2 ){
161 for( int i
=0; i
<sample_count
-1; i
++ ){
162 ray_hit
*s0
= &samples
[i
],
165 float a
= v3_dot( s0
->normal
, s1
->normal
);
167 if( (a
< min_a
) && (a
>= -0.1f
) && (s0
->normal
[1]>s1
->normal
[1]) ){
177 ray_hit
*s0
= candidate
,
180 vg_line( s0
->pos
, s1
->pos
, VG__WHITE
);
182 v3_copy( s0
->normal
, pa
);
183 v3_copy( s1
->normal
, pb
);
184 v3_cross( player
->rb
.to_world
[1], dir
, pc
);
187 pa
[3] = v3_dot( pa
, s0
->pos
);
188 pb
[3] = v3_dot( pb
, s1
->pos
);
189 pc
[3] = v3_dot( pc
, player
->rb
.co
);
192 if( plane_intersect3( pa
, pb
, pc
, edge
) ){
193 v3_copy( edge
, w
->state
.drop_in_target
);
194 v3_copy( s1
->normal
, w
->state
.drop_in_normal
);
195 v3_copy( player
->rb
.co
, w
->state
.drop_in_start
);
197 w
->state
.drop_in_start_angle
= player_get_heading_yaw( player
);
198 w
->state
.drop_in_angle
= atan2f( w
->state
.drop_in_normal
[0],
199 w
->state
.drop_in_normal
[2] );
201 /* TODO: scan multiple of these? */
204 player_walk_drop_in_overhang_transform( player
, 1.0f
, oco
, oq
);
206 v3f va
= {0.0f
,0.0f
,-k_board_length
- 0.3f
},
207 vb
= {0.0f
,0.0f
, k_board_length
+ 0.3f
};
209 q_mulv( oq
, va
, va
);
210 q_mulv( oq
, vb
, vb
);
211 v3_add( oco
, va
, va
);
212 v3_add( oco
, vb
, vb
);
215 v3_sub( vb
, va
, v0
);
219 ray
.dist
= k_board_length
*2.0f
+ 0.6f
;
221 if( ray_world( world
, va
, v0
, &ray
, 0 ) ){
222 vg_line( va
, vb
, VG__RED
);
223 vg_line_point( ray
.pos
, 0.1f
, VG__RED
);
224 vg_error( "invalidated\n" );
228 v3_muls( v0
, -1.0f
, v0
);
229 if( ray_world( world
, vb
, v0
, &ray
, 0 ) ){
230 vg_line( va
, vb
, VG__RED
);
231 vg_line_point( ray
.pos
, 0.1f
, VG__RED
);
232 vg_error( "invalidated\n" );
236 player_walk_drop_in_vector( player
, player
->rb
.v
);
241 vg_error( "failed to find intersection of drop in\n" );
248 VG_STATIC
struct skeleton_anim
*player_walk_outro_anim( player_instance
*player
,
249 enum walk_outro type
){
250 struct player_walk
*w
= &player
->_walk
;
252 return (struct skeleton_anim
*[]){
253 [k_walk_outro_none
] = NULL
,
254 [k_walk_outro_jump_to_air
] = w
->anim_jump_to_air
,
255 [k_walk_outro_regular
] = w
->anim_intro
,
256 [k_walk_outro_drop_in
] = w
->anim_drop_in
261 VG_STATIC
void player__walk_pre_update( player_instance
*player
)
263 struct player_walk
*w
= &player
->_walk
;
265 if( !player
->immobile
)
266 player_look( player
->angles
, skaterift
.time_rate
);
268 if( w
->state
.outro_type
){
269 struct skeleton_anim
*anim
=
270 player_walk_outro_anim( player
, w
->state
.outro_type
);
272 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
273 outro_time
= vg
.time
- w
->state
.outro_start_time
;
275 if( outro_time
>= outro_length
){
276 if( w
->state
.outro_type
== k_walk_outro_drop_in
){
277 player_walk_drop_in_to_skate( player
);
279 else if( w
->state
.outro_type
== k_walk_outro_jump_to_air
){
280 player_walk_generic_to_skate( player
, k_skate_activity_air
, 0.0f
);
283 player_walk_generic_to_skate( player
,
284 k_skate_activity_ground
, 1.0f
);
287 w
->state
.outro_type
= k_walk_outro_none
;
291 else if( button_down( k_srbind_use
) && !player
->immobile
){
292 if( v3_dist2( player
->rb
.co
, gzoomer
.obj
.rb
.co
) <= 4.0f
*4.0f
){
293 player
->subsystem
= k_player_subsystem_drive
;
296 struct player_board
*board
=
297 addon_cache_item_if_loaded( k_addon_type_board
,
298 player
->board_view_slot
);
302 if( w
->state
.activity
== k_walk_activity_ground
){
303 if( player_walk_scan_for_drop_in( player
) ){
304 w
->state
.outro_type
= k_walk_outro_drop_in
;
305 w
->state
.outro_start_time
= vg
.time
;
306 player
->immobile
= 1;
308 struct player_avatar
*av
= player
->playeravatar
;
309 m4x3_mulv( av
->sk
.final_mtx
[ av
->id_ik_foot_r
],
310 av
->sk
.bones
[ av
->id_ik_foot_r
].co
,
311 w
->state
.drop_in_foot_anchor
);
314 w
->state
.outro_type
= k_walk_outro_regular
;
315 w
->state
.outro_start_time
= vg
.time
;
316 w
->state
.activity
= k_walk_activity_lockedmove
;
318 if( player_xyspeed2(player
) < 0.1f
* 0.1f
)
319 q_mulv( player
->rb
.q
, (v3f
){0.0f
,0.0f
,1.6f
}, player
->rb
.v
);
323 w
->state
.outro_type
= k_walk_outro_jump_to_air
;
324 w
->state
.outro_start_time
= vg
.time
;
329 else if( button_down( k_srbind_jump
) && !player
->immobile
){
330 w
->state
.jump_queued
= 1;
331 w
->state
.jump_input_time
= vg
.time
;
335 VG_STATIC
int player_walk_normal_standable( player_instance
*player
, v3f n
){
336 return v3_dot( n
, player
->basis
[1] ) > 0.70710678118f
;
339 VG_STATIC
void player_accelerate( v3f v
, v3f movedir
, f32 speed
, f32 accel
){
340 float currentspeed
= v3_dot( v
, movedir
),
341 addspeed
= speed
- currentspeed
;
346 float accelspeed
= accel
* k_rb_delta
* speed
;
348 if( accelspeed
> addspeed
)
349 accelspeed
= addspeed
;
351 v3_muladds( v
, movedir
, accelspeed
, v
);
354 VG_STATIC
void player_friction( v3f v
){
355 float speed
= v3_length( v
),
357 control
= vg_maxf( speed
, k_stopspeed
);
362 drop
+= control
* k_walk_friction
* k_rb_delta
;
364 float newspeed
= vg_maxf( 0.0f
, speed
- drop
);
367 v3_muls( v
, newspeed
, v
);
370 VG_STATIC
void player_walk_custom_filter( world_instance
*world
,
371 rb_ct
*man
, int len
, f32 w
){
372 for( int i
=0; i
<len
; i
++ ){
374 if( ci
->type
== k_contact_type_disabled
||
375 ci
->type
== k_contact_type_edge
)
379 float d1
= v3_dot( ci
->co
, ci
->n
);
381 for( int j
=0; j
<len
; j
++ ){
386 if( cj
->type
== k_contact_type_disabled
)
389 struct world_surface
*si
= world_contact_surface( world
, ci
),
390 *sj
= world_contact_surface( world
, cj
);
392 if( (sj
->info
.flags
& k_material_flag_walking
) &&
393 !(si
->info
.flags
& k_material_flag_walking
)){
397 float d2
= v3_dot( cj
->co
, ci
->n
),
400 if( fabsf( d
) <= w
){
401 cj
->type
= k_contact_type_disabled
;
407 VG_STATIC
void player__walk_update( player_instance
*player
){
408 struct player_walk
*w
= &player
->_walk
;
409 v3_copy( player
->rb
.co
, w
->state
.prev_pos
);
410 v3_zero( player
->rb
.w
);
412 world_instance
*world
= world_current_instance();
414 if( world
->water
.enabled
){
415 if( player
->rb
.co
[1]+0.4f
< world
->water
.height
){
416 audio_oneshot_3d( &audio_splash
, player
->rb
.co
, 40.0f
, 1.0f
);
417 player__dead_transition( player
);
422 enum walk_activity prev_state
= w
->state
.activity
;
424 w
->collider
.height
= 2.0f
;
425 w
->collider
.radius
= 0.3f
;
428 m3x3_copy( player
->rb
.to_world
, mtx
);
429 v3_add( player
->rb
.co
, player
->basis
[1], mtx
[3] );
431 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__WHITE
);
436 float yaw
= player
->angles
[0];
438 v3f forward_dir
= { -sinf(yaw
), 0.0f
, cosf(yaw
) };
439 v3f right_dir
= { forward_dir
[2], 0.0f
, -forward_dir
[0] };
441 m3x3_mulv( player
->basis
, forward_dir
, forward_dir
);
442 m3x3_mulv( player
->basis
, right_dir
, right_dir
);
445 joystick_state( k_srjoystick_steer
, steer
);
447 w
->move_speed
= player
->immobile
? 0.0f
: v2_length( steer
);
450 * Collision detection
453 len
= rb_capsule__scene( mtx
, &w
->collider
, NULL
,
454 &world
->rb_geo
.inf
.scene
, manifold
, 0 );
455 player_walk_custom_filter( world
, manifold
, len
, 0.01f
);
456 len
= rb_manifold_apply_filtered( manifold
, len
);
458 v3f surface_avg
= { 0.0f
, 0.0f
, 0.0f
};
460 if( w
->state
.activity
!= k_walk_activity_lockedmove
)
461 w
->state
.activity
= k_walk_activity_air
;
463 w
->surface
= k_surface_prop_concrete
;
465 for( int i
=0; i
<len
; i
++ ){
466 struct contact
*ct
= &manifold
[i
];
467 rb_debug_contact( ct
);
469 if( player_walk_normal_standable( player
, ct
->n
) ){
470 if( w
->state
.activity
!= k_walk_activity_lockedmove
)
471 w
->state
.activity
= k_walk_activity_ground
;
473 v3_add( surface_avg
, ct
->n
, surface_avg
);
475 struct world_surface
*surf
= world_contact_surface( world
, ct
);
476 if( surf
->info
.surface_prop
> w
->surface
)
477 w
->surface
= surf
->info
.surface_prop
;
480 rb_prepare_contact( ct
, k_rb_delta
);
486 float accel_speed
= 0.0f
, nominal_speed
= 0.0f
;
489 v3_muls( right_dir
, steer
[0], movedir
);
490 v3_muladds( movedir
, forward_dir
, steer
[1], movedir
);
492 if( w
->state
.activity
== k_walk_activity_ground
){
493 v3_normalize( surface_avg
);
496 v3_tangent_basis( surface_avg
, tx
, ty
);
498 if( v2_length2(steer
) > 0.001f
){
499 /* clip movement to the surface */
500 float d
= v3_dot(surface_avg
,movedir
);
501 v3_muladds( movedir
, surface_avg
, -d
, movedir
);
504 accel_speed
= k_walk_accel
;
505 nominal_speed
= k_walkspeed
;
508 if( w
->state
.jump_queued
){
509 w
->state
.jump_queued
= 0;
511 f32 t
= vg
.time
- w
->state
.jump_input_time
;
512 if( t
< PLAYER_JUMP_EPSILON
){
513 float d
= v3_dot( player
->basis
[1], player
->rb
.v
);
514 v3_muladds( player
->rb
.v
, player
->basis
[1], -d
, player
->rb
.v
);
515 v3_muladds( player
->rb
.v
, player
->basis
[1], 5.0f
, player
->rb
.v
);
516 w
->state
.activity
= k_walk_activity_air
;
517 prev_state
= k_walk_activity_air
;
518 accel_speed
= k_walk_air_accel
;
519 nominal_speed
= k_airspeed
;
523 player_friction( player
->rb
.v
);
527 accel_speed
= k_walk_air_accel
;
528 nominal_speed
= k_airspeed
;
531 if( v2_length2( steer
) > 0.001f
){
532 player_accelerate( player
->rb
.v
, movedir
, nominal_speed
, accel_speed
);
533 v3_normalize( movedir
);
537 * Resolve velocity constraints
539 for( int j
=0; j
<5; j
++ ){
540 for( int i
=0; i
<len
; i
++ ){
541 struct contact
*ct
= &manifold
[i
];
544 float vn
= -v3_dot( player
->rb
.v
, ct
->n
);
546 float temp
= ct
->norm_impulse
;
547 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
548 vn
= ct
->norm_impulse
- temp
;
550 v3_muladds( player
->rb
.v
, ct
->n
, vn
, player
->rb
.v
);
555 if( w
->state
.activity
== k_walk_activity_ground
||
556 prev_state
== k_walk_activity_ground
){
557 float max_dist
= 0.4f
;
560 v3_copy( player
->rb
.co
, pa
);
561 v3_muladds( pa
, player
->basis
[1], w
->collider
.radius
+ max_dist
, pa
);
562 v3_muladds( pa
, player
->basis
[1], -max_dist
* 2.0f
, pb
);
563 vg_line( pa
, pb
, 0xff000000 );
567 if( spherecast_world( world
, pa
, pb
,
568 w
->collider
.radius
, &t
, n
, 0 ) != -1 ){
569 if( player_walk_normal_standable( player
, n
) ){
570 v3_lerp( pa
, pb
, t
, player
->rb
.co
);
571 v3_muladds( player
->rb
.co
, player
->basis
[1],
572 -w
->collider
.radius
- k_penetration_slop
,
574 w
->state
.activity
= k_walk_activity_ground
;
576 float d
= -v3_dot(n
,player
->rb
.v
),
577 g
= -k_gravity
* k_rb_delta
;
578 v3_muladds( player
->rb
.v
, n
, d
, player
->rb
.v
);
579 v3_muladds( player
->rb
.v
, player
->basis
[1], g
, player
->rb
.v
);
588 rb_depenetrate( manifold
, len
, dt
);
589 v3_add( dt
, player
->rb
.co
, player
->rb
.co
);
592 if( w
->state
.activity
== k_walk_activity_air
){
593 v3_muladds( player
->rb
.v
, player
->basis
[1], -k_gravity
*k_rb_delta
,
597 if( player
->immobile
){
598 player
->rb
.v
[0] = 0.0f
;
599 player
->rb
.v
[2] = 0.0f
;
602 v3_muladds( player
->rb
.co
, player
->rb
.v
, k_rb_delta
, player
->rb
.co
);
603 v3_add( player
->rb
.co
, player
->basis
[1], mtx
[3] );
604 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__GREEN
);
608 * ---------------------------------------------------
613 lwr_offs
= { 0.0f
, w
->collider
.radius
, 0.0f
};
615 v3_add( lwr_offs
, w
->state
.prev_pos
, lwr_prev
);
616 v3_add( lwr_offs
, player
->rb
.co
, lwr_now
);
619 v3_sub( player
->rb
.co
, w
->state
.prev_pos
, movedelta
);
621 float movedist
= v3_length( movedelta
);
623 if( movedist
> 0.3f
){
624 float t
, sr
= w
->collider
.radius
-0.04f
;
627 if( spherecast_world( world
, lwr_prev
, lwr_now
, sr
, &t
, n
, 0 ) != -1 ){
628 v3_lerp( lwr_prev
, lwr_now
, vg_maxf(0.01f
,t
), player
->rb
.co
);
629 player
->rb
.co
[1] -= w
->collider
.radius
;
630 rb_update_transform( &player
->rb
);
632 v3_add( player
->rb
.co
, player
->basis
[1], mtx
[3] );
633 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__RED
);
638 world_intersect_gates( world
, player
->rb
.co
, w
->state
.prev_pos
);
640 m4x3_mulv( gate
->transport
, player
->rb
.co
, player
->rb
.co
);
641 m3x3_mulv( gate
->transport
, player
->rb
.v
, player
->rb
.v
);
643 v4f transport_rotation
;
644 m3x3_q( gate
->transport
, transport_rotation
);
645 q_mul( transport_rotation
, player
->rb
.q
, player
->rb
.q
);
647 rb_update_transform( &player
->rb
);
648 player__pass_gate( player
, gate
);
650 rb_update_transform( &player
->rb
);
653 VG_STATIC
void player__walk_post_update( player_instance
*player
){
654 struct player_walk
*w
= &player
->_walk
;
657 m3x3_copy( player
->rb
.to_world
, mtx
);
658 v3_add( player
->rb
.co
, player
->basis
[1], mtx
[3] );
660 float substep
= vg
.time_fixed_extrapolate
;
661 v3_muladds( mtx
[3], player
->rb
.v
, k_rb_delta
*substep
, mtx
[3] );
662 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__YELOW
);
665 /* Calculate header */
667 if( player_xyspeed2(player
) > 0.1f
*0.1f
)
670 m3x3_mulv( player
->invbasis
, player
->rb
.v
, v_xy
);
671 float a
= atan2f( v_xy
[0], v_xy
[2] );
673 q_axis_angle( player
->rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, a
);
674 q_mul( player
->qbasis
, player
->rb
.q
, player
->rb
.q
);
675 q_normalize( player
->rb
.q
);
678 vg_line_point( w
->state
.drop_in_target
, 0.1f
, VG__GREEN
);
680 v3_muladds( w
->state
.drop_in_target
, w
->state
.drop_in_normal
, 0.3f
, p1
);
681 vg_line( w
->state
.drop_in_target
, p1
, VG__GREEN
);
682 v3_muladds( w
->state
.drop_in_target
, player
->rb
.to_world
[1], 0.3f
, p1
);
683 vg_line( w
->state
.drop_in_target
, p1
, VG__GREEN
);
685 vg_line( w
->state
.drop_in_target
, w
->state
.drop_in_foot_anchor
, VG__WHITE
);
686 vg_line_point( w
->state
.drop_in_foot_anchor
, 0.08f
, VG__PINK
);
689 float a
= player_get_heading_yaw( player
);
693 m3x3_mulv( player
->basis
, p1
, p1
);
695 v3_add( player
->rb
.co
, p1
, p1
);
696 vg_line( player
->rb
.co
, p1
, VG__PINK
);
700 if( vg_fractf(w
->state
.walk_timer
) > 0.5f
)
705 if( (w
->state
.step_phase
!= walk_phase
) &&
706 (w
->state
.activity
== k_walk_activity_ground
) )
709 if( w
->surface
== k_surface_prop_concrete
){
711 &audio_footsteps
[vg_randu32()%vg_list_size(audio_footsteps
)],
712 player
->rb
.co
, 40.0f
, 1.0f
715 else if( w
->surface
== k_surface_prop_grass
){
717 &audio_footsteps_grass
[ vg_randu32()%
718 vg_list_size(audio_footsteps_grass
)],
719 player
->rb
.co
, 40.0f
, 1.0f
722 else if( w
->surface
== k_surface_prop_wood
){
724 &audio_footsteps_wood
[ vg_randu32()%
725 vg_list_size(audio_footsteps_wood
)],
726 player
->rb
.co
, 40.0f
, 1.0f
732 w
->state
.step_phase
= walk_phase
;
735 VG_STATIC
void player__walk_animate( player_instance
*player
){
736 struct player_walk
*w
= &player
->_walk
;
737 player_pose
*pose
= &player
->pose
;
738 struct player_walk_animator
*animator
= &w
->animator
;
740 animator
->outro_type
= w
->state
.outro_type
;
743 f32 fly
= (w
->state
.activity
== k_walk_activity_air
)? 1.0f
: 0.0f
,
746 if( w
->state
.activity
== k_walk_activity_air
) rate
= 2.4f
;
749 animator
->fly
= vg_lerpf( animator
->fly
, fly
, rate
*vg
.time_delta
);
750 animator
->run
= vg_lerpf( animator
->run
, w
->move_speed
,
754 if( w
->move_speed
> 0.025f
){
756 float walk_norm
= 30.0f
/(float)w
->anim_walk
->length
,
757 run_norm
= 30.0f
/(float)w
->anim_run
->length
,
758 walk_adv
= vg_lerpf( walk_norm
, run_norm
, w
->move_speed
);
760 w
->state
.walk_timer
+= walk_adv
* vg
.time_delta
;
763 w
->state
.walk_timer
= 0.0f
;
764 animator
->walk_timer
= w
->state
.walk_timer
;
766 if( !player
->immobile
)
767 rb_extrapolate( &player
->rb
, animator
->root_co
, animator
->root_q
);
769 v3_copy( player
->rb
.co
, animator
->root_co
);
770 v4_copy( player
->rb
.q
, animator
->root_q
);
773 f32 walk_yaw
= player_get_heading_yaw( player
);
774 if( w
->state
.outro_type
){
775 struct player_avatar
*av
= player
->playeravatar
;
776 struct skeleton_anim
*anim
=
777 player_walk_outro_anim( player
, w
->state
.outro_type
);
778 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
779 outro_time
= vg
.time
- w
->state
.outro_start_time
;
780 animator
->outro_t
= outro_time
/ outro_length
;
782 if( w
->state
.outro_type
== k_walk_outro_drop_in
){
783 float inv_rate
= 1.0f
/ anim
->rate
,
784 anim_frames
= anim
->length
* inv_rate
,
785 step_frames
= 12.0f
* inv_rate
,
786 commit_frames
= 6.0f
* inv_rate
,
787 drop_frames
= anim_frames
- step_frames
,
788 step_t
= vg_minf( 1.0f
, outro_time
/ step_frames
),
789 remaind_time
= vg_maxf( 0.0f
, outro_time
- step_frames
),
790 dop_t
= vg_minf( 1.0f
, remaind_time
/ drop_frames
);
791 animator
->commit_t
= vg_minf( 1.0f
, remaind_time
/ commit_frames
);
793 walk_yaw
= vg_alerpf( w
->state
.drop_in_start_angle
,
794 w
->state
.drop_in_angle
, step_t
);
796 v3_lerp( w
->state
.drop_in_start
, w
->state
.drop_in_target
,
797 step_t
, player
->rb
.co
);
798 q_axis_angle( animator
->root_q
, (v3f
){0.0f
,1.0f
,0.0f
},
801 v3_copy( w
->state
.drop_in_foot_anchor
, animator
->foot_anchor
);
803 /* the drop in bit */
804 if( step_t
>= 1.0f
){
806 player_walk_drop_in_overhang_transform( player
, dop_t
,
807 player
->rb
.co
, final_q
);
808 q_mul( final_q
, animator
->root_q
, animator
->root_q
);
810 v4_copy( animator
->root_q
, player
->rb
.q
);
811 v3_muladds( animator
->root_co
, player
->rb
.to_world
[1],
812 -0.1f
*dop_t
, animator
->root_co
);
817 v3_muladds( animator
->root_co
, player
->rb
.to_world
[1],
818 -0.1f
*animator
->outro_t
, animator
->root_co
);
822 q_axis_angle( animator
->root_q
, (v3f
){0.0f
,1.0f
,0.0f
}, walk_yaw
+ VG_PIf
);
823 q_mul( player
->qbasis
, animator
->root_q
, animator
->root_q
);
824 q_normalize( animator
->root_q
);
827 VG_STATIC
void player__walk_pose( player_instance
*player
, player_pose
*pose
){
828 struct player_walk
*w
= &player
->_walk
;
829 struct player_walk_animator
*animator
= &w
->animator
;
830 struct skeleton
*sk
= &player
->playeravatar
->sk
;
831 struct player_avatar
*av
= player
->playeravatar
;
833 v3_copy( animator
->root_co
, pose
->root_co
);
834 v4_copy( animator
->root_q
, pose
->root_q
);
835 pose
->board
.lean
= 0.0f
;
836 pose
->type
= k_player_pose_type_ik
;
838 float walk_norm
= (float)w
->anim_walk
->length
/30.0f
,
839 run_norm
= (float)w
->anim_run
->length
/30.0f
,
840 t
= animator
->walk_timer
,
841 l
= vg_clampf( animator
->run
*15.0f
, 0.0f
, 1.0f
),
842 idle_walk
= vg_clampf( (animator
->run
-0.1f
)/(1.0f
-0.1f
), 0.0f
, 1.0f
);
845 mdl_keyframe apose
[32], bpose
[32];
846 skeleton_sample_anim( sk
, w
->anim_walk
, t
*walk_norm
, apose
);
847 skeleton_sample_anim( sk
, w
->anim_run
, t
*run_norm
, bpose
);
849 skeleton_lerp_pose( sk
, apose
, bpose
, l
, apose
);
852 skeleton_sample_anim( sk
, w
->anim_idle
, vg
.time
*0.1f
, bpose
);
853 skeleton_lerp_pose( sk
, apose
, bpose
, 1.0f
-idle_walk
, apose
);
856 skeleton_sample_anim( sk
, w
->anim_jump
, vg
.time
*0.6f
, bpose
);
857 skeleton_lerp_pose( sk
, apose
, bpose
, animator
->fly
, apose
);
859 if( animator
->outro_type
){
860 struct skeleton_anim
*anim
=
861 player_walk_outro_anim( player
, animator
->outro_type
);
863 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
864 outro_time
= animator
->outro_t
*outro_length
;
866 skeleton_sample_anim_clamped( sk
, anim
, outro_time
, bpose
);
867 skeleton_lerp_pose( sk
, apose
, bpose
, animator
->outro_t
*10.0f
,
870 if( animator
->outro_type
== k_walk_outro_drop_in
){
871 m4x3f transform
, inverse
;
872 q_m3x3( pose
->root_q
, transform
);
873 v3_copy( pose
->root_co
, transform
[3] );
874 m4x3_invert_affine( transform
, inverse
);
877 m4x3_mulv( inverse
, animator
->foot_anchor
, anchored_pos
);
879 v3_lerp( pose
->keyframes
[ av
->id_ik_foot_r
-1 ].co
, anchored_pos
,
880 1.0f
-animator
->commit_t
,
881 pose
->keyframes
[ av
->id_ik_foot_r
-1 ].co
);
885 skeleton_copy_pose( sk
, apose
, pose
->keyframes
);
888 VG_STATIC
void player__walk_post_animate( player_instance
*player
){
892 struct player_walk
*w
= &player
->_walk
;
893 struct player_avatar
*av
= player
->playeravatar
;
895 if( w
->state
.outro_type
){
896 struct skeleton_anim
*anim
=
897 player_walk_outro_anim( player
, w
->state
.outro_type
);
899 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
900 outro_time
= vg
.time
- w
->state
.outro_start_time
,
901 outro_t
= outro_time
/ outro_length
;
903 player
->cam_velocity_influence
= outro_t
;
906 player
->cam_velocity_influence
= 0.0f
;
909 VG_STATIC
void player__walk_im_gui( player_instance
*player
){
910 struct player_walk
*w
= &player
->_walk
;
911 player__debugtext( 1, "V: %5.2f %5.2f %5.2f",player
->rb
.v
[0],
914 player__debugtext( 1, "CO: %5.2f %5.2f %5.2f",player
->rb
.co
[0],
917 player__debugtext( 1, "activity: %s\n",
918 (const char *[]){ "k_walk_activity_air",
919 "k_walk_activity_ground",
920 "k_walk_activity_sleep",
921 "k_walk_activity_lockedmove" }
922 [w
->state
.activity
] );
923 player__debugtext( 1, "surface: %s\n",
924 (const char *[]){ "concrete",
931 if( w
->state
.outro_type
){
932 struct skeleton_anim
*anim
=
933 player_walk_outro_anim( player
, w
->state
.outro_type
);
935 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
936 outro_time
= vg
.time
- w
->state
.outro_start_time
;
937 player__debugtext( 1, "outro time: %f / %f", outro_time
, outro_length
);
941 VG_STATIC
void player__walk_bind( player_instance
*player
){
942 struct player_walk
*w
= &player
->_walk
;
943 struct player_avatar
*av
= player
->playeravatar
;
944 struct skeleton
*sk
= &av
->sk
;
946 w
->anim_idle
= skeleton_get_anim( sk
, "idle_cycle+y" );
947 w
->anim_walk
= skeleton_get_anim( sk
, "walk+y" );
948 w
->anim_run
= skeleton_get_anim( sk
, "run+y" );
949 w
->anim_jump
= skeleton_get_anim( sk
, "jump+y" );
950 w
->anim_jump_to_air
= skeleton_get_anim( sk
, "jump_to_air" );
951 w
->anim_drop_in
= skeleton_get_anim( sk
, "drop_in" );
952 w
->anim_intro
= skeleton_get_anim( sk
, "into_skate" );
955 VG_STATIC
void player__walk_transition( player_instance
*player
){
956 struct player_walk
*w
= &player
->_walk
;
957 w
->state
.activity
= k_walk_activity_air
;
958 w
->state
.outro_type
= k_walk_outro_none
;
959 w
->state
.outro_start_time
= 0.0;
960 w
->state
.jump_queued
= 0;
961 w
->state
.jump_input_time
= 0.0;
962 w
->state
.walk_timer
= 0.0f
;
963 w
->state
.step_phase
= 0;
965 v3f fwd
= { 0.0f
, 0.0f
, 1.0f
};
966 q_mulv( player
->rb
.q
, fwd
, fwd
);
967 m3x3_mulv( player
->invbasis
, fwd
, fwd
);
969 q_axis_angle( player
->rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, atan2f(fwd
[0], fwd
[2]) );
970 q_mul( player
->qbasis
, player
->rb
.q
, player
->rb
.q
);
971 q_normalize( player
->rb
.q
);
973 rb_update_transform( &player
->rb
);
976 VG_STATIC
void player__walk_reset( player_instance
*player
, ent_spawn
*rp
){
977 struct player_walk
*w
= &player
->_walk
;
978 w
->state
.activity
= k_walk_activity_air
;
979 w
->state
.outro_type
= k_walk_outro_none
;
980 w
->state
.outro_start_time
= 0.0;
983 #endif /* PLAYER_DEVICE_WALK_H */