8 static void player_walk_drop_in_vector( v3f vec
){
10 v3_cross( localplayer
.basis
[1], player_walk
.state
.drop_in_normal
, axis
);
11 v3_cross( axis
, player_walk
.state
.drop_in_normal
, init_dir
);
12 v3_normalize( init_dir
);
13 v3_muls( init_dir
, 7.0f
, vec
);
16 static float player_xyspeed2(void){
18 v3_muladds( localplayer
.rb
.v
, localplayer
.basis
[1],
19 -v3_dot( localplayer
.basis
[1], localplayer
.rb
.v
), xy
);
21 return v3_length2(xy
);
24 static void player_walk_generic_to_skate( enum skate_activity init
, f32 yaw
){
25 localplayer
.subsystem
= k_player_subsystem_skate
;
29 if( player_xyspeed2() < 0.1f
* 0.1f
)
30 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,0.0f
,1.6f
}, v
);
32 v3_copy( localplayer
.rb
.v
, v
);
34 player_skate
.state
.activity_prev
= k_skate_activity_ground
;
35 player_skate
.state
.activity
= init
;
40 m3x3_mulv( localplayer
.invbasis
, dir
, dir
);
42 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
43 atan2f(-dir
[0],-dir
[2]) );
44 q_mul( localplayer
.qbasis
, localplayer
.rb
.q
, localplayer
.rb
.q
);
45 q_normalize( localplayer
.rb
.q
);
47 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, player_skate
.state
.cog
);
48 v3_add( player_skate
.state
.cog
, localplayer
.rb
.co
, player_skate
.state
.cog
);
50 v3_copy( v
, player_skate
.state
.cog_v
);
51 v3_copy( v
, localplayer
.rb
.v
);
53 player__begin_holdout();
54 player__skate_reset_animator();
55 player__skate_clear_mechanics();
56 rb_update_transform( &localplayer
.rb
);
57 v3_copy( (v3f
){yaw
,0.0f
,0.0f
}, player_skate
.state
.trick_euler
);
59 if( init
== k_skate_activity_air
)
60 player__approximate_best_trajectory();
63 static void player_walk_drop_in_to_skate(void){
64 localplayer
.immobile
= 0;
65 localplayer
.subsystem
= k_player_subsystem_skate
;
67 player_skate
.state
.activity_prev
= k_skate_activity_ground
;
68 player_skate
.state
.activity
= k_skate_activity_ground
;
70 player__begin_holdout();
71 player__skate_clear_mechanics();
72 player__skate_reset_animator();
75 player_walk_drop_in_vector( init_velocity
);
77 rb_update_transform( &localplayer
.rb
);
78 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.to_world
[1], 1.0f
,
79 player_skate
.state
.cog
);
80 v3_copy( init_velocity
, player_skate
.state
.cog_v
);
81 v3_copy( init_velocity
, localplayer
.rb
.v
);
82 v3_copy( init_velocity
, localplayer
.cam_control
.cam_velocity_smooth
);
83 v3_copy( (v3f
){1.0f
,0.0f
,0.0f
}, player_skate
.state
.trick_euler
);
86 static void player_walk_drop_in_overhang_transform( f32 t
, v3f co
, v4f q
){
88 v3_cross( localplayer
.basis
[1], player_walk
.state
.drop_in_normal
, axis
);
91 float a
= acosf( player_walk
.state
.drop_in_normal
[1] ) * t
;
92 q_axis_angle( q
, axis
, a
);
95 heading_angle
= player_walk
.state
.drop_in_angle
;
98 overhang
[0] = sinf( heading_angle
) * l
;
99 overhang
[1] = 0.28f
* l
;
100 overhang
[2] = cosf( heading_angle
) * l
;
102 q_mulv( q
, overhang
, overhang
);
103 v3_add( player_walk
.state
.drop_in_target
, overhang
, co
);
106 static int player_walk_scan_for_drop_in(void){
107 world_instance
*world
= world_current_instance();
110 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,0.0f
,1.0f
}, dir
);
111 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.to_world
[1], -1.0f
, center
);
114 int sample_count
= 0;
116 for( int i
=0; i
<20; i
++ ){
117 float t
= (float)i
* (1.0f
/19.0f
),
118 s
= sinf( t
* VG_PIf
* 0.25f
),
119 c
= cosf( t
* VG_PIf
* 0.25f
);
122 v3_muls ( localplayer
.rb
.to_world
[1], -c
, ray_dir
);
123 v3_muladds( ray_dir
, dir
, -s
, ray_dir
);
124 v3_muladds( center
, ray_dir
, -2.0f
, pos
);
126 ray_hit
*ray
= &samples
[ sample_count
];
129 if( ray_world( world
, pos
, ray_dir
, ray
, 0 ) ){
130 vg_line( pos
, ray
->pos
, VG__RED
);
131 vg_line_point( ray
->pos
, 0.025f
, VG__BLACK
);
137 float min_a
= 0.70710678118654752f
;
138 ray_hit
*candidate
= NULL
;
140 if( sample_count
>= 2 ){
141 for( int i
=0; i
<sample_count
-1; i
++ ){
142 ray_hit
*s0
= &samples
[i
],
145 float a
= v3_dot( s0
->normal
, s1
->normal
);
147 if( (a
< min_a
) && (a
>= -0.1f
) && (s0
->normal
[1]>s1
->normal
[1]) ){
157 ray_hit
*s0
= candidate
,
160 vg_line( s0
->pos
, s1
->pos
, VG__WHITE
);
162 v3_copy( s0
->normal
, pa
);
163 v3_copy( s1
->normal
, pb
);
164 v3_cross( localplayer
.rb
.to_world
[1], dir
, pc
);
167 pa
[3] = v3_dot( pa
, s0
->pos
);
168 pb
[3] = v3_dot( pb
, s1
->pos
);
169 pc
[3] = v3_dot( pc
, localplayer
.rb
.co
);
172 if( plane_intersect3( pa
, pb
, pc
, edge
) ){
173 v3_copy( edge
, player_walk
.state
.drop_in_target
);
174 v3_copy( s1
->normal
, player_walk
.state
.drop_in_normal
);
175 v3_copy( localplayer
.rb
.co
, player_walk
.state
.drop_in_start
);
177 player_walk
.state
.drop_in_start_angle
= player_get_heading_yaw();
178 player_walk
.state
.drop_in_angle
=
179 atan2f( player_walk
.state
.drop_in_normal
[0],
180 player_walk
.state
.drop_in_normal
[2] );
182 /* TODO: scan multiple of these? */
185 player_walk_drop_in_overhang_transform( 1.0f
, oco
, oq
);
187 v3f va
= {0.0f
,0.0f
,-k_board_length
- 0.3f
},
188 vb
= {0.0f
,0.0f
, k_board_length
+ 0.3f
};
190 q_mulv( oq
, va
, va
);
191 q_mulv( oq
, vb
, vb
);
192 v3_add( oco
, va
, va
);
193 v3_add( oco
, vb
, vb
);
196 v3_sub( vb
, va
, v0
);
200 ray
.dist
= k_board_length
*2.0f
+ 0.6f
;
202 if( ray_world( world
, va
, v0
, &ray
, 0 ) ){
203 vg_line( va
, vb
, VG__RED
);
204 vg_line_point( ray
.pos
, 0.1f
, VG__RED
);
205 vg_error( "invalidated\n" );
209 v3_muls( v0
, -1.0f
, v0
);
210 if( ray_world( world
, vb
, v0
, &ray
, 0 ) ){
211 vg_line( va
, vb
, VG__RED
);
212 vg_line_point( ray
.pos
, 0.1f
, VG__RED
);
213 vg_error( "invalidated\n" );
217 player_walk_drop_in_vector( localplayer
.rb
.v
);
221 vg_error( "failed to find intersection of drop in\n" );
228 static struct skeleton_anim
*player_walk_outro_anim( enum walk_outro type
){
229 struct player_walk
*w
= &player_walk
;
231 return (struct skeleton_anim
*[]){
232 [k_walk_outro_none
] = NULL
,
233 [k_walk_outro_jump_to_air
] = w
->anim_jump_to_air
,
234 [k_walk_outro_regular
] = w
->anim_intro
,
235 [k_walk_outro_drop_in
] = w
->anim_drop_in
240 static void player__walk_pre_update(void){
241 struct player_walk
*w
= &player_walk
;
243 if( !localplayer
.immobile
)
244 player_look( localplayer
.angles
, skaterift
.time_rate
);
246 if( w
->state
.outro_type
){
247 struct skeleton_anim
*anim
= player_walk_outro_anim(w
->state
.outro_type
);
249 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
250 outro_time
= vg
.time
- w
->state
.outro_start_time
;
252 if( outro_time
>= outro_length
){
253 if( w
->state
.outro_type
== k_walk_outro_drop_in
){
254 player_walk_drop_in_to_skate();
256 else if( w
->state
.outro_type
== k_walk_outro_jump_to_air
){
257 player_walk_generic_to_skate( k_skate_activity_air
, 0.0f
);
260 player_walk_generic_to_skate( k_skate_activity_ground
, 1.0f
);
263 w
->state
.outro_type
= k_walk_outro_none
;
267 else if( button_down( k_srbind_use
) && !localplayer
.immobile
){
268 if( v3_dist2( localplayer
.rb
.co
, gzoomer
.obj
.rb
.co
) <= 4.0f
*4.0f
){
269 localplayer
.subsystem
= k_player_subsystem_drive
;
272 struct player_board
*board
=
273 addon_cache_item_if_loaded( k_addon_type_board
,
274 localplayer
.board_view_slot
);
278 if( w
->state
.activity
== k_walk_activity_ground
){
279 if( player_walk_scan_for_drop_in() ){
280 w
->state
.outro_type
= k_walk_outro_drop_in
;
281 w
->state
.outro_start_time
= vg
.time
;
282 localplayer
.immobile
= 1;
284 struct player_avatar
*av
= localplayer
.playeravatar
;
285 m4x3_mulv( localplayer
.final_mtx
[ av
->id_ik_foot_r
],
286 av
->sk
.bones
[ av
->id_ik_foot_r
].co
,
287 w
->state
.drop_in_foot_anchor
);
290 w
->state
.outro_type
= k_walk_outro_regular
;
291 w
->state
.outro_start_time
= vg
.time
;
292 w
->state
.activity
= k_walk_activity_lockedmove
;
294 if( player_xyspeed2() < 0.1f
* 0.1f
){
295 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,0.0f
,1.6f
},
301 w
->state
.outro_type
= k_walk_outro_jump_to_air
;
302 w
->state
.outro_start_time
= vg
.time
;
307 else if( button_down( k_srbind_jump
) && !localplayer
.immobile
){
308 w
->state
.jump_queued
= 1;
309 w
->state
.jump_input_time
= vg
.time
;
313 static int player_walk_normal_standable( v3f n
){
314 return v3_dot( n
, localplayer
.basis
[1] ) > 0.70710678118f
;
317 static void player_accelerate( v3f v
, v3f movedir
, f32 speed
, f32 accel
){
318 float currentspeed
= v3_dot( v
, movedir
),
319 addspeed
= speed
- currentspeed
;
324 float accelspeed
= accel
* k_rb_delta
* speed
;
326 if( accelspeed
> addspeed
)
327 accelspeed
= addspeed
;
329 v3_muladds( v
, movedir
, accelspeed
, v
);
332 static void player_friction( v3f v
){
333 float speed
= v3_length( v
),
335 control
= vg_maxf( speed
, k_stopspeed
);
340 drop
+= control
* k_walk_friction
* k_rb_delta
;
342 float newspeed
= vg_maxf( 0.0f
, speed
- drop
);
345 v3_muls( v
, newspeed
, v
);
348 static void player_walk_custom_filter( world_instance
*world
,
349 rb_ct
*man
, int len
, f32 w
){
350 for( int i
=0; i
<len
; i
++ ){
352 if( ci
->type
== k_contact_type_disabled
||
353 ci
->type
== k_contact_type_edge
)
357 float d1
= v3_dot( ci
->co
, ci
->n
);
359 for( int j
=0; j
<len
; j
++ ){
364 if( cj
->type
== k_contact_type_disabled
)
367 struct world_surface
*si
= world_contact_surface( world
, ci
),
368 *sj
= world_contact_surface( world
, cj
);
370 if( (sj
->info
.flags
& k_material_flag_walking
) &&
371 !(si
->info
.flags
& k_material_flag_walking
)){
375 float d2
= v3_dot( cj
->co
, ci
->n
),
378 if( fabsf( d
) <= w
){
379 cj
->type
= k_contact_type_disabled
;
385 static void player__walk_update(void){
386 struct player_walk
*w
= &player_walk
;
387 v3_copy( localplayer
.rb
.co
, w
->state
.prev_pos
);
388 v3_zero( localplayer
.rb
.w
);
390 world_instance
*world
= world_current_instance();
392 if( world
->water
.enabled
){
393 if( localplayer
.rb
.co
[1]+0.4f
< world
->water
.height
){
394 audio_oneshot_3d( &audio_splash
, localplayer
.rb
.co
, 40.0f
, 1.0f
);
395 player__dead_transition();
400 enum walk_activity prev_state
= w
->state
.activity
;
402 w
->collider
.height
= 2.0f
;
403 w
->collider
.radius
= 0.3f
;
406 m3x3_copy( localplayer
.rb
.to_world
, mtx
);
407 v3_add( localplayer
.rb
.co
, localplayer
.basis
[1], mtx
[3] );
409 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__WHITE
);
414 float yaw
= localplayer
.angles
[0];
416 v3f forward_dir
= { -sinf(yaw
), 0.0f
, cosf(yaw
) };
417 v3f right_dir
= { forward_dir
[2], 0.0f
, -forward_dir
[0] };
419 m3x3_mulv( localplayer
.basis
, forward_dir
, forward_dir
);
420 m3x3_mulv( localplayer
.basis
, right_dir
, right_dir
);
423 joystick_state( k_srjoystick_steer
, steer
);
425 w
->move_speed
= localplayer
.immobile
? 0.0f
: v2_length( steer
);
428 * Collision detection
431 len
= rb_capsule__scene( mtx
, &w
->collider
, NULL
,
432 &world
->rb_geo
.inf
.scene
, manifold
, 0 );
433 player_walk_custom_filter( world
, manifold
, len
, 0.01f
);
434 len
= rb_manifold_apply_filtered( manifold
, len
);
436 v3f surface_avg
= { 0.0f
, 0.0f
, 0.0f
};
438 if( w
->state
.activity
!= k_walk_activity_lockedmove
)
439 w
->state
.activity
= k_walk_activity_air
;
441 w
->surface
= k_surface_prop_concrete
;
443 for( int i
=0; i
<len
; i
++ ){
444 struct contact
*ct
= &manifold
[i
];
445 rb_debug_contact( ct
);
447 if( player_walk_normal_standable( ct
->n
) ){
448 if( w
->state
.activity
!= k_walk_activity_lockedmove
)
449 w
->state
.activity
= k_walk_activity_ground
;
451 v3_add( surface_avg
, ct
->n
, surface_avg
);
453 struct world_surface
*surf
= world_contact_surface( world
, ct
);
454 if( surf
->info
.surface_prop
> w
->surface
)
455 w
->surface
= surf
->info
.surface_prop
;
458 rb_prepare_contact( ct
, k_rb_delta
);
464 float accel_speed
= 0.0f
, nominal_speed
= 0.0f
;
467 v3_muls( right_dir
, steer
[0], movedir
);
468 v3_muladds( movedir
, forward_dir
, steer
[1], movedir
);
470 if( w
->state
.activity
== k_walk_activity_ground
){
471 v3_normalize( surface_avg
);
474 v3_tangent_basis( surface_avg
, tx
, ty
);
476 if( v2_length2(steer
) > 0.001f
){
477 /* clip movement to the surface */
478 float d
= v3_dot(surface_avg
,movedir
);
479 v3_muladds( movedir
, surface_avg
, -d
, movedir
);
482 accel_speed
= k_walk_accel
;
483 nominal_speed
= k_walkspeed
;
486 if( w
->state
.jump_queued
){
487 w
->state
.jump_queued
= 0;
489 f32 t
= vg
.time
- w
->state
.jump_input_time
;
490 if( t
< PLAYER_JUMP_EPSILON
){
491 float d
= v3_dot( localplayer
.basis
[1], localplayer
.rb
.v
);
492 v3_muladds( localplayer
.rb
.v
, localplayer
.basis
[1], -d
,
494 v3_muladds( localplayer
.rb
.v
, localplayer
.basis
[1], 5.0f
,
496 w
->state
.activity
= k_walk_activity_air
;
497 prev_state
= k_walk_activity_air
;
498 accel_speed
= k_walk_air_accel
;
499 nominal_speed
= k_airspeed
;
503 player_friction( localplayer
.rb
.v
);
507 accel_speed
= k_walk_air_accel
;
508 nominal_speed
= k_airspeed
;
511 if( v2_length2( steer
) > 0.001f
){
512 player_accelerate( localplayer
.rb
.v
, movedir
,
513 nominal_speed
, accel_speed
);
514 v3_normalize( movedir
);
518 * Resolve velocity constraints
520 for( int j
=0; j
<5; j
++ ){
521 for( int i
=0; i
<len
; i
++ ){
522 struct contact
*ct
= &manifold
[i
];
525 float vn
= -v3_dot( localplayer
.rb
.v
, ct
->n
);
527 float temp
= ct
->norm_impulse
;
528 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
529 vn
= ct
->norm_impulse
- temp
;
531 v3_muladds( localplayer
.rb
.v
, ct
->n
, vn
, localplayer
.rb
.v
);
536 if( w
->state
.activity
== k_walk_activity_ground
||
537 prev_state
== k_walk_activity_ground
){
538 float max_dist
= 0.4f
;
541 v3_copy( localplayer
.rb
.co
, pa
);
542 v3_muladds( pa
, localplayer
.basis
[1], w
->collider
.radius
+ max_dist
, pa
);
543 v3_muladds( pa
, localplayer
.basis
[1], -max_dist
* 2.0f
, pb
);
544 vg_line( pa
, pb
, 0xff000000 );
548 if( spherecast_world( world
, pa
, pb
,
549 w
->collider
.radius
, &t
, n
, 0 ) != -1 ){
550 if( player_walk_normal_standable(n
) ){
551 v3_lerp( pa
, pb
, t
, localplayer
.rb
.co
);
552 v3_muladds( localplayer
.rb
.co
, localplayer
.basis
[1],
553 -w
->collider
.radius
- k_penetration_slop
,
555 w
->state
.activity
= k_walk_activity_ground
;
557 float d
= -v3_dot(n
,localplayer
.rb
.v
),
558 g
= -k_gravity
* k_rb_delta
;
559 v3_muladds( localplayer
.rb
.v
, n
, d
, localplayer
.rb
.v
);
560 v3_muladds( localplayer
.rb
.v
, localplayer
.basis
[1], g
,
570 rb_depenetrate( manifold
, len
, dt
);
571 v3_add( dt
, localplayer
.rb
.co
, localplayer
.rb
.co
);
574 if( w
->state
.activity
== k_walk_activity_air
){
575 v3_muladds( localplayer
.rb
.v
, localplayer
.basis
[1], -k_gravity
*k_rb_delta
,
579 if( localplayer
.immobile
){
580 localplayer
.rb
.v
[0] = 0.0f
;
581 localplayer
.rb
.v
[2] = 0.0f
;
584 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.v
, k_rb_delta
,
586 v3_add( localplayer
.rb
.co
, localplayer
.basis
[1], mtx
[3] );
587 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__GREEN
);
591 * ---------------------------------------------------
596 lwr_offs
= { 0.0f
, w
->collider
.radius
, 0.0f
};
598 v3_add( lwr_offs
, w
->state
.prev_pos
, lwr_prev
);
599 v3_add( lwr_offs
, localplayer
.rb
.co
, lwr_now
);
602 v3_sub( localplayer
.rb
.co
, w
->state
.prev_pos
, movedelta
);
604 float movedist
= v3_length( movedelta
);
606 if( movedist
> 0.3f
){
607 float t
, sr
= w
->collider
.radius
-0.04f
;
610 if( spherecast_world( world
, lwr_prev
, lwr_now
, sr
, &t
, n
, 0 ) != -1 ){
611 v3_lerp( lwr_prev
, lwr_now
, vg_maxf(0.01f
,t
), localplayer
.rb
.co
);
612 localplayer
.rb
.co
[1] -= w
->collider
.radius
;
613 rb_update_transform( &localplayer
.rb
);
615 v3_add( localplayer
.rb
.co
, localplayer
.basis
[1], mtx
[3] );
616 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__RED
);
621 world_intersect_gates( world
, localplayer
.rb
.co
, w
->state
.prev_pos
);
623 m4x3_mulv( gate
->transport
, localplayer
.rb
.co
, localplayer
.rb
.co
);
624 m3x3_mulv( gate
->transport
, localplayer
.rb
.v
, localplayer
.rb
.v
);
626 v4f transport_rotation
;
627 m3x3_q( gate
->transport
, transport_rotation
);
628 q_mul( transport_rotation
, localplayer
.rb
.q
, localplayer
.rb
.q
);
630 rb_update_transform( &localplayer
.rb
);
631 player__pass_gate( gate
);
633 rb_update_transform( &localplayer
.rb
);
636 static void player__walk_post_update(void){
637 struct player_walk
*w
= &player_walk
;
640 m3x3_copy( localplayer
.rb
.to_world
, mtx
);
641 v3_add( localplayer
.rb
.co
, localplayer
.basis
[1], mtx
[3] );
643 float substep
= vg
.time_fixed_extrapolate
;
644 v3_muladds( mtx
[3], localplayer
.rb
.v
, k_rb_delta
*substep
, mtx
[3] );
645 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__YELOW
);
648 /* Calculate header */
650 if( player_xyspeed2() > 0.1f
*0.1f
)
653 m3x3_mulv( localplayer
.invbasis
, localplayer
.rb
.v
, v_xy
);
654 float a
= atan2f( v_xy
[0], v_xy
[2] );
656 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, a
);
657 q_mul( localplayer
.qbasis
, localplayer
.rb
.q
, localplayer
.rb
.q
);
658 q_normalize( localplayer
.rb
.q
);
661 vg_line_point( w
->state
.drop_in_target
, 0.1f
, VG__GREEN
);
663 v3_muladds( w
->state
.drop_in_target
, w
->state
.drop_in_normal
, 0.3f
, p1
);
664 vg_line( w
->state
.drop_in_target
, p1
, VG__GREEN
);
665 v3_muladds( w
->state
.drop_in_target
, localplayer
.rb
.to_world
[1], 0.3f
, p1
);
666 vg_line( w
->state
.drop_in_target
, p1
, VG__GREEN
);
668 vg_line( w
->state
.drop_in_target
, w
->state
.drop_in_foot_anchor
, VG__WHITE
);
669 vg_line_point( w
->state
.drop_in_foot_anchor
, 0.08f
, VG__PINK
);
672 float a
= player_get_heading_yaw();
676 m3x3_mulv( localplayer
.basis
, p1
, p1
);
678 v3_add( localplayer
.rb
.co
, p1
, p1
);
679 vg_line( localplayer
.rb
.co
, p1
, VG__PINK
);
683 if( vg_fractf(w
->state
.walk_timer
) > 0.5f
)
688 if( (w
->state
.step_phase
!= walk_phase
) &&
689 (w
->state
.activity
== k_walk_activity_ground
) )
692 if( w
->surface
== k_surface_prop_concrete
){
694 &audio_footsteps
[vg_randu32()%vg_list_size(audio_footsteps
)],
695 localplayer
.rb
.co
, 40.0f
, 1.0f
698 else if( w
->surface
== k_surface_prop_grass
){
700 &audio_footsteps_grass
[ vg_randu32()%
701 vg_list_size(audio_footsteps_grass
)],
702 localplayer
.rb
.co
, 40.0f
, 1.0f
705 else if( w
->surface
== k_surface_prop_wood
){
707 &audio_footsteps_wood
[ vg_randu32()%
708 vg_list_size(audio_footsteps_wood
)],
709 localplayer
.rb
.co
, 40.0f
, 1.0f
715 w
->state
.step_phase
= walk_phase
;
718 static void player__walk_animate(void){
719 struct player_walk
*w
= &player_walk
;
720 player_pose
*pose
= &localplayer
.pose
;
721 struct player_walk_animator
*animator
= &w
->animator
;
723 animator
->outro_type
= w
->state
.outro_type
;
726 f32 fly
= (w
->state
.activity
== k_walk_activity_air
)? 1.0f
: 0.0f
,
729 if( w
->state
.activity
== k_walk_activity_air
) rate
= 2.4f
;
732 animator
->fly
= vg_lerpf( animator
->fly
, fly
, rate
*vg
.time_delta
);
733 animator
->run
= vg_lerpf( animator
->run
, w
->move_speed
,
737 if( w
->move_speed
> 0.025f
){
739 float walk_norm
= 30.0f
/(float)w
->anim_walk
->length
,
740 run_norm
= 30.0f
/(float)w
->anim_run
->length
,
741 walk_adv
= vg_lerpf( walk_norm
, run_norm
, w
->move_speed
);
743 w
->state
.walk_timer
+= walk_adv
* vg
.time_delta
;
746 w
->state
.walk_timer
= 0.0f
;
747 animator
->walk_timer
= w
->state
.walk_timer
;
749 if( !localplayer
.immobile
)
750 rb_extrapolate( &localplayer
.rb
, animator
->root_co
, animator
->root_q
);
752 v3_copy( localplayer
.rb
.co
, animator
->root_co
);
753 v4_copy( localplayer
.rb
.q
, animator
->root_q
);
756 f32 walk_yaw
= player_get_heading_yaw();
757 if( w
->state
.outro_type
){
758 struct player_avatar
*av
= localplayer
.playeravatar
;
759 struct skeleton_anim
*anim
=
760 player_walk_outro_anim( w
->state
.outro_type
);
761 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
762 outro_time
= vg
.time
- w
->state
.outro_start_time
;
763 animator
->outro_t
= outro_time
/ outro_length
;
765 if( w
->state
.outro_type
== k_walk_outro_drop_in
){
766 float inv_rate
= 1.0f
/ anim
->rate
,
767 anim_frames
= anim
->length
* inv_rate
,
768 step_frames
= 12.0f
* inv_rate
,
769 commit_frames
= 6.0f
* inv_rate
,
770 drop_frames
= anim_frames
- step_frames
,
771 step_t
= vg_minf( 1.0f
, outro_time
/ step_frames
),
772 remaind_time
= vg_maxf( 0.0f
, outro_time
- step_frames
),
773 dop_t
= vg_minf( 1.0f
, remaind_time
/ drop_frames
);
774 animator
->commit_t
= vg_minf( 1.0f
, remaind_time
/ commit_frames
);
776 walk_yaw
= vg_alerpf( w
->state
.drop_in_start_angle
,
777 w
->state
.drop_in_angle
, step_t
);
779 v3_lerp( w
->state
.drop_in_start
, w
->state
.drop_in_target
,
780 step_t
, localplayer
.rb
.co
);
781 q_axis_angle( animator
->root_q
, (v3f
){0.0f
,1.0f
,0.0f
},
784 v3_copy( w
->state
.drop_in_foot_anchor
, animator
->foot_anchor
);
786 /* the drop in bit */
787 if( step_t
>= 1.0f
){
789 player_walk_drop_in_overhang_transform( dop_t
, localplayer
.rb
.co
,
791 q_mul( final_q
, animator
->root_q
, animator
->root_q
);
793 v4_copy( animator
->root_q
, localplayer
.rb
.q
);
794 v3_muladds( animator
->root_co
, localplayer
.rb
.to_world
[1],
795 -0.1f
*dop_t
, animator
->root_co
);
800 v3_muladds( animator
->root_co
, localplayer
.rb
.to_world
[1],
801 -0.1f
*animator
->outro_t
, animator
->root_co
);
805 q_axis_angle( animator
->root_q
, (v3f
){0.0f
,1.0f
,0.0f
}, walk_yaw
+ VG_PIf
);
806 q_mul( localplayer
.qbasis
, animator
->root_q
, animator
->root_q
);
807 q_normalize( animator
->root_q
);
810 static void player__walk_pose( void *_animator
, player_pose
*pose
){
811 struct player_walk
*w
= &player_walk
;
812 struct player_walk_animator
*animator
= _animator
;
813 struct skeleton
*sk
= &localplayer
.playeravatar
->sk
;
814 struct player_avatar
*av
= localplayer
.playeravatar
;
816 v3_copy( animator
->root_co
, pose
->root_co
);
817 v4_copy( animator
->root_q
, pose
->root_q
);
818 pose
->board
.lean
= 0.0f
;
819 pose
->type
= k_player_pose_type_ik
;
821 float walk_norm
= (float)w
->anim_walk
->length
/30.0f
,
822 run_norm
= (float)w
->anim_run
->length
/30.0f
,
823 t
= animator
->walk_timer
,
824 l
= vg_clampf( animator
->run
*15.0f
, 0.0f
, 1.0f
),
825 idle_walk
= vg_clampf( (animator
->run
-0.1f
)/(1.0f
-0.1f
), 0.0f
, 1.0f
);
828 mdl_keyframe apose
[32], bpose
[32];
829 skeleton_sample_anim( sk
, w
->anim_walk
, t
*walk_norm
, apose
);
830 skeleton_sample_anim( sk
, w
->anim_run
, t
*run_norm
, bpose
);
832 skeleton_lerp_pose( sk
, apose
, bpose
, l
, apose
);
835 skeleton_sample_anim( sk
, w
->anim_idle
, vg
.time
*0.1f
, bpose
);
836 skeleton_lerp_pose( sk
, apose
, bpose
, 1.0f
-idle_walk
, apose
);
839 skeleton_sample_anim( sk
, w
->anim_jump
, vg
.time
*0.6f
, bpose
);
840 skeleton_lerp_pose( sk
, apose
, bpose
, animator
->fly
, apose
);
842 if( animator
->outro_type
){
843 struct skeleton_anim
*anim
= player_walk_outro_anim(animator
->outro_type
);
845 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
846 outro_time
= animator
->outro_t
*outro_length
;
848 skeleton_sample_anim_clamped( sk
, anim
, outro_time
, bpose
);
849 skeleton_lerp_pose( sk
, apose
, bpose
, animator
->outro_t
*10.0f
,
852 if( animator
->outro_type
== k_walk_outro_drop_in
){
853 m4x3f transform
, inverse
;
854 q_m3x3( pose
->root_q
, transform
);
855 v3_copy( pose
->root_co
, transform
[3] );
856 m4x3_invert_affine( transform
, inverse
);
859 m4x3_mulv( inverse
, animator
->foot_anchor
, anchored_pos
);
861 v3_lerp( pose
->keyframes
[ av
->id_ik_foot_r
-1 ].co
, anchored_pos
,
862 1.0f
-animator
->commit_t
,
863 pose
->keyframes
[ av
->id_ik_foot_r
-1 ].co
);
867 skeleton_copy_pose( sk
, apose
, pose
->keyframes
);
870 static void player__walk_post_animate(void){
874 struct player_walk
*w
= &player_walk
;
875 struct player_avatar
*av
= localplayer
.playeravatar
;
877 if( w
->state
.outro_type
){
878 struct skeleton_anim
*anim
= player_walk_outro_anim(w
->state
.outro_type
);
880 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
881 outro_time
= vg
.time
- w
->state
.outro_start_time
,
882 outro_t
= outro_time
/ outro_length
;
884 localplayer
.cam_velocity_influence
= outro_t
;
887 localplayer
.cam_velocity_influence
= 0.0f
;
890 static void player__walk_im_gui(void){
891 struct player_walk
*w
= &player_walk
;
892 player__debugtext( 1, "V: %5.2f %5.2f %5.2f",localplayer
.rb
.v
[0],
894 localplayer
.rb
.v
[2] );
895 player__debugtext( 1, "CO: %5.2f %5.2f %5.2f",localplayer
.rb
.co
[0],
896 localplayer
.rb
.co
[1],
897 localplayer
.rb
.co
[2] );
898 player__debugtext( 1, "activity: %s\n",
899 (const char *[]){ "k_walk_activity_air",
900 "k_walk_activity_ground",
901 "k_walk_activity_sleep",
902 "k_walk_activity_lockedmove" }
903 [w
->state
.activity
] );
904 player__debugtext( 1, "surface: %s\n",
905 (const char *[]){ "concrete",
912 if( w
->state
.outro_type
){
913 struct skeleton_anim
*anim
=
914 player_walk_outro_anim( w
->state
.outro_type
);
916 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
917 outro_time
= vg
.time
- w
->state
.outro_start_time
;
918 player__debugtext( 1, "outro time: %f / %f", outro_time
, outro_length
);
922 static void player__walk_bind(void){
923 struct player_walk
*w
= &player_walk
;
924 struct player_avatar
*av
= localplayer
.playeravatar
;
925 struct skeleton
*sk
= &av
->sk
;
927 w
->anim_idle
= skeleton_get_anim( sk
, "idle_cycle+y" );
928 w
->anim_walk
= skeleton_get_anim( sk
, "walk+y" );
929 w
->anim_run
= skeleton_get_anim( sk
, "run+y" );
930 w
->anim_jump
= skeleton_get_anim( sk
, "jump+y" );
931 w
->anim_jump_to_air
= skeleton_get_anim( sk
, "jump_to_air" );
932 w
->anim_drop_in
= skeleton_get_anim( sk
, "drop_in" );
933 w
->anim_intro
= skeleton_get_anim( sk
, "into_skate" );
936 static void player__walk_transition(void){
937 struct player_walk
*w
= &player_walk
;
938 w
->state
.activity
= k_walk_activity_air
;
939 w
->state
.outro_type
= k_walk_outro_none
;
940 w
->state
.outro_start_time
= 0.0;
941 w
->state
.jump_queued
= 0;
942 w
->state
.jump_input_time
= 0.0;
943 w
->state
.walk_timer
= 0.0f
;
944 w
->state
.step_phase
= 0;
946 v3f fwd
= { 0.0f
, 0.0f
, 1.0f
};
947 q_mulv( localplayer
.rb
.q
, fwd
, fwd
);
948 m3x3_mulv( localplayer
.invbasis
, fwd
, fwd
);
950 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
951 atan2f(fwd
[0], fwd
[2]) );
952 q_mul( localplayer
.qbasis
, localplayer
.rb
.q
, localplayer
.rb
.q
);
953 q_normalize( localplayer
.rb
.q
);
955 rb_update_transform( &localplayer
.rb
);
958 static void player__walk_reset( ent_spawn
*rp
){
959 struct player_walk
*w
= &player_walk
;
960 w
->state
.activity
= k_walk_activity_air
;
961 w
->state
.outro_type
= k_walk_outro_none
;
962 w
->state
.outro_start_time
= 0.0;
965 #endif /* PLAYER_DEVICE_WALK_H */