8 static void player_walk_drop_in_vector( v3f vec
){
10 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, 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
, 4.25f
, vec
);
16 static float player_xyspeed2(void){
17 return v3_length2( (v3f
){localplayer
.rb
.v
[0], 0.0f
, localplayer
.rb
.v
[2]} );
20 static void player_walk_generic_to_skate( enum skate_activity init
, f32 yaw
){
21 localplayer
.subsystem
= k_player_subsystem_skate
;
25 if( player_xyspeed2() < 0.1f
* 0.1f
)
26 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,0.0f
,1.6f
}, v
);
28 v3_copy( localplayer
.rb
.v
, v
);
30 player_skate
.state
.activity_prev
= k_skate_activity_ground
;
31 player_skate
.state
.activity
= init
;
37 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
38 atan2f(-dir
[0],-dir
[2]) );
39 q_normalize( localplayer
.rb
.q
);
41 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, player_skate
.state
.cog
);
42 v3_add( player_skate
.state
.cog
, localplayer
.rb
.co
, player_skate
.state
.cog
);
44 v3_copy( v
, player_skate
.state
.cog_v
);
45 v3_copy( v
, localplayer
.rb
.v
);
47 player__begin_holdout( (v3f
){0.0f
,0.0f
,0.0f
} );
48 player__skate_reset_animator();
49 player__skate_clear_mechanics();
50 rb_update_transform( &localplayer
.rb
);
51 v3_copy( (v3f
){yaw
,0.0f
,0.0f
}, player_skate
.state
.trick_euler
);
53 if( init
== k_skate_activity_air
)
54 player__approximate_best_trajectory();
57 static void player_walk_drop_in_to_skate(void){
58 localplayer
.immobile
= 0;
59 localplayer
.subsystem
= k_player_subsystem_skate
;
61 player_skate
.state
.activity_prev
= k_skate_activity_ground
;
62 player_skate
.state
.activity
= k_skate_activity_ground
;
64 player__begin_holdout( (v3f
){0.0f
,0.0f
,0.0f
} );
65 player__skate_clear_mechanics();
66 player__skate_reset_animator();
69 player_walk_drop_in_vector( init_velocity
);
71 rb_update_transform( &localplayer
.rb
);
72 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.to_world
[1], 1.0f
,
73 player_skate
.state
.cog
);
74 v3_copy( init_velocity
, player_skate
.state
.cog_v
);
75 v3_copy( init_velocity
, localplayer
.rb
.v
);
76 v3_copy( init_velocity
, localplayer
.cam_control
.cam_velocity_smooth
);
77 v3_copy( (v3f
){1.0f
,0.0f
,0.0f
}, player_skate
.state
.trick_euler
);
80 static void player_walk_drop_in_overhang_transform( f32 t
, v3f co
, v4f q
){
82 v3_cross( (v3f
){0,1,0}, player_walk
.state
.drop_in_normal
, axis
);
85 float a
= acosf( player_walk
.state
.drop_in_normal
[1] ) * t
;
86 q_axis_angle( q
, axis
, a
);
89 heading_angle
= player_walk
.state
.drop_in_angle
;
92 overhang
[0] = sinf( heading_angle
) * l
;
93 overhang
[1] = 0.28f
* l
;
94 overhang
[2] = cosf( heading_angle
) * l
;
96 q_mulv( q
, overhang
, overhang
);
97 v3_add( player_walk
.state
.drop_in_target
, overhang
, co
);
100 static int player_walk_scan_for_drop_in(void){
101 world_instance
*world
= world_current_instance();
104 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,0.0f
,1.0f
}, dir
);
105 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.to_world
[1], -1.0f
, center
);
108 int sample_count
= 0;
110 for( int i
=0; i
<20; i
++ ){
111 float t
= (float)i
* (1.0f
/19.0f
),
112 s
= sinf( t
* VG_PIf
* 0.25f
),
113 c
= cosf( t
* VG_PIf
* 0.25f
);
116 v3_muls ( localplayer
.rb
.to_world
[1], -c
, ray_dir
);
117 v3_muladds( ray_dir
, dir
, -s
, ray_dir
);
118 v3_muladds( center
, ray_dir
, -2.0f
, pos
);
120 ray_hit
*ray
= &samples
[ sample_count
];
123 if( ray_world( world
, pos
, ray_dir
, ray
, 0 ) ){
124 vg_line( pos
, ray
->pos
, VG__RED
);
125 vg_line_point( ray
->pos
, 0.025f
, VG__BLACK
);
131 float min_a
= 0.70710678118654752f
;
132 ray_hit
*candidate
= NULL
;
134 if( sample_count
>= 2 ){
135 for( int i
=0; i
<sample_count
-1; i
++ ){
136 ray_hit
*s0
= &samples
[i
],
139 float a
= v3_dot( s0
->normal
, s1
->normal
);
141 if( (a
< min_a
) && (a
>= -0.1f
) && (s0
->normal
[1]>s1
->normal
[1]) ){
151 ray_hit
*s0
= candidate
,
154 vg_line( s0
->pos
, s1
->pos
, VG__WHITE
);
156 v3_copy( s0
->normal
, pa
);
157 v3_copy( s1
->normal
, pb
);
158 v3_cross( localplayer
.rb
.to_world
[1], dir
, pc
);
161 pa
[3] = v3_dot( pa
, s0
->pos
);
162 pb
[3] = v3_dot( pb
, s1
->pos
);
163 pc
[3] = v3_dot( pc
, localplayer
.rb
.co
);
166 if( plane_intersect3( pa
, pb
, pc
, edge
) ){
167 v3_copy( edge
, player_walk
.state
.drop_in_target
);
168 v3_copy( s1
->normal
, player_walk
.state
.drop_in_normal
);
169 v3_copy( localplayer
.rb
.co
, player_walk
.state
.drop_in_start
);
171 player_walk
.state
.drop_in_start_angle
= player_get_heading_yaw();
172 player_walk
.state
.drop_in_angle
=
173 atan2f( player_walk
.state
.drop_in_normal
[0],
174 player_walk
.state
.drop_in_normal
[2] );
176 /* TODO: scan multiple of these? */
179 player_walk_drop_in_overhang_transform( 1.0f
, oco
, oq
);
181 v3f va
= {0.0f
,0.0f
,-k_board_length
- 0.3f
},
182 vb
= {0.0f
,0.0f
, k_board_length
+ 0.3f
};
184 q_mulv( oq
, va
, va
);
185 q_mulv( oq
, vb
, vb
);
186 v3_add( oco
, va
, va
);
187 v3_add( oco
, vb
, vb
);
190 v3_sub( vb
, va
, v0
);
194 ray
.dist
= k_board_length
*2.0f
+ 0.6f
;
196 if( ray_world( world
, va
, v0
, &ray
, 0 ) ){
197 vg_line( va
, vb
, VG__RED
);
198 vg_line_point( ray
.pos
, 0.1f
, VG__RED
);
199 vg_error( "invalidated\n" );
203 v3_muls( v0
, -1.0f
, v0
);
204 if( ray_world( world
, vb
, v0
, &ray
, 0 ) ){
205 vg_line( va
, vb
, VG__RED
);
206 vg_line_point( ray
.pos
, 0.1f
, VG__RED
);
207 vg_error( "invalidated\n" );
211 player_walk_drop_in_vector( localplayer
.rb
.v
);
215 vg_error( "failed to find intersection of drop in\n" );
222 static struct skeleton_anim
*player_walk_outro_anim( enum walk_outro type
){
223 struct player_walk
*w
= &player_walk
;
225 if( type
>= k_walk_outro_max
)
228 return (struct skeleton_anim
*[]){
229 [k_walk_outro_none
] = NULL
,
230 [k_walk_outro_jump_to_air
] = w
->anim_jump_to_air
,
231 [k_walk_outro_regular
] = w
->anim_intro
,
232 [k_walk_outro_drop_in
] = w
->anim_drop_in
237 static void player__walk_pre_update(void){
238 struct player_walk
*w
= &player_walk
;
240 if( !localplayer
.immobile
)
241 player_look( localplayer
.angles
, skaterift
.time_rate
);
244 joystick_state( k_srjoystick_steer
, steer
);
246 if( w
->state
.activity
== k_walk_activity_sit
){
247 if( w
->state
.sit_t
< 1.0f
)
248 w
->state
.sit_t
= vg_minf( 1.0f
, w
->state
.sit_t
+ vg
.time_delta
);
250 if( button_down(k_srbind_sit
) || (v2_length2(steer
)>0.2f
) ||
251 button_down(k_srbind_jump
) ){
252 w
->state
.activity
= k_walk_activity_sit_up
;
256 else if( w
->state
.activity
== k_walk_activity_sit_up
){
257 if( w
->state
.sit_t
> 0.0f
)
258 w
->state
.sit_t
= vg_maxf( 0.0f
, w
->state
.sit_t
- vg
.time_delta
);
260 w
->state
.activity
= k_walk_activity_ground
;
262 if( button_down(k_srbind_sit
) )
263 w
->state
.activity
= k_walk_activity_sit
;
267 else if( w
->state
.activity
== k_walk_activity_ground
){
268 if( button_down(k_srbind_sit
) ){
269 v3_zero( localplayer
.rb
.v
);
270 w
->state
.activity
= k_walk_activity_sit
;
275 w
->state
.sit_t
= 0.0f
;
277 if( w
->state
.outro_type
){
278 struct skeleton_anim
*anim
= player_walk_outro_anim(w
->state
.outro_type
);
280 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
281 outro_time
= vg
.time
- w
->state
.outro_start_time
;
283 if( outro_time
>= outro_length
){
284 if( w
->state
.outro_type
== k_walk_outro_drop_in
){
285 player_walk_drop_in_to_skate();
287 else if( w
->state
.outro_type
== k_walk_outro_jump_to_air
){
288 player_walk_generic_to_skate( k_skate_activity_air
, 0.0f
);
291 player_walk_generic_to_skate( k_skate_activity_ground
, 1.0f
);
294 w
->state
.outro_type
= k_walk_outro_none
;
298 else if( button_down( k_srbind_use
) && !localplayer
.immobile
){
299 if( 0 && (v3_dist2(localplayer
.rb
.co
,gzoomer
.obj
.rb
.co
) <= 4.0f
*4.0f
) ){
300 localplayer
.subsystem
= k_player_subsystem_drive
;
303 struct player_board
*board
=
304 addon_cache_item_if_loaded( k_addon_type_board
,
305 localplayer
.board_view_slot
);
309 if( w
->state
.activity
== k_walk_activity_ground
){
310 if( player_walk_scan_for_drop_in() ){
311 w
->state
.outro_type
= k_walk_outro_drop_in
;
312 w
->state
.outro_start_time
= vg
.time
;
313 localplayer
.immobile
= 1;
315 u32 foot_id
= localplayer
.id_ik_foot_r
;
317 m4x3_mulv( localplayer
.final_mtx
[ foot_id
],
318 localplayer
.skeleton
.bones
[ foot_id
].co
,
319 w
->state
.drop_in_foot_anchor
);
322 w
->state
.outro_type
= k_walk_outro_regular
;
323 w
->state
.outro_start_time
= vg
.time
;
324 w
->state
.activity
= k_walk_activity_lockedmove
;
326 if( player_xyspeed2() < 0.1f
* 0.1f
){
327 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,0.0f
,1.6f
},
333 w
->state
.outro_type
= k_walk_outro_jump_to_air
;
334 w
->state
.outro_start_time
= vg
.time
;
339 else if( button_down( k_srbind_jump
) && !localplayer
.immobile
){
340 w
->state
.jump_queued
= 1;
341 w
->state
.jump_input_time
= vg
.time
;
345 static int player_walk_normal_standable( v3f n
){
346 return n
[1] > 0.70710678118f
;
349 static void player_accelerate( v3f v
, v3f movedir
, f32 speed
, f32 accel
){
350 float currentspeed
= v3_dot( v
, movedir
),
351 addspeed
= speed
- currentspeed
;
356 float accelspeed
= accel
* k_rb_delta
* speed
;
358 if( accelspeed
> addspeed
)
359 accelspeed
= addspeed
;
361 v3_muladds( v
, movedir
, accelspeed
, v
);
364 static void player_friction( v3f v
){
365 float speed
= v3_length( v
),
367 control
= vg_maxf( speed
, k_stopspeed
);
372 drop
+= control
* k_walk_friction
* k_rb_delta
;
374 float newspeed
= vg_maxf( 0.0f
, speed
- drop
);
377 v3_muls( v
, newspeed
, v
);
380 static void player_walk_custom_filter( world_instance
*world
,
381 rb_ct
*man
, int len
, f32 w
){
382 for( int i
=0; i
<len
; i
++ ){
384 if( ci
->type
== k_contact_type_disabled
||
385 ci
->type
== k_contact_type_edge
)
389 float d1
= v3_dot( ci
->co
, ci
->n
);
391 for( int j
=0; j
<len
; j
++ ){
396 if( cj
->type
== k_contact_type_disabled
)
399 struct world_surface
*si
= world_contact_surface( world
, ci
),
400 *sj
= world_contact_surface( world
, cj
);
402 if( (sj
->info
.flags
& k_material_flag_walking
) &&
403 !(si
->info
.flags
& k_material_flag_walking
)){
407 float d2
= v3_dot( cj
->co
, ci
->n
),
410 if( fabsf( d
) <= w
){
411 cj
->type
= k_contact_type_disabled
;
417 static void player__walk_update(void){
418 struct player_walk
*w
= &player_walk
;
421 joystick_state( k_srjoystick_steer
, steer
);
423 if( (w
->state
.activity
== k_walk_activity_sit
) ||
424 (w
->state
.activity
== k_walk_activity_sit_up
) ){
428 v3_copy( localplayer
.rb
.co
, w
->state
.prev_pos
);
429 v3_zero( localplayer
.rb
.w
);
431 world_instance
*world
= world_current_instance();
433 if( world
->water
.enabled
){
434 if( localplayer
.rb
.co
[1]+0.4f
< world
->water
.height
){
435 player__networked_sfx( k_player_subsystem_walk
, 32,
436 k_player_walk_soundeffect_splash
,
437 localplayer
.rb
.co
, 1.0f
);
438 player__dead_transition();
443 enum walk_activity prev_state
= w
->state
.activity
;
445 w
->collider
.height
= 2.0f
;
446 w
->collider
.radius
= 0.3f
;
449 m3x3_copy( localplayer
.rb
.to_world
, mtx
);
450 v3_add( localplayer
.rb
.co
, (v3f
){0,1,0}, mtx
[3] );
452 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__WHITE
);
457 float yaw
= localplayer
.angles
[0];
459 v3f forward_dir
= { -sinf(yaw
), 0.0f
, cosf(yaw
) };
460 v3f right_dir
= { forward_dir
[2], 0.0f
, -forward_dir
[0] };
462 w
->move_speed
= localplayer
.immobile
? 0.0f
: v2_length( steer
);
465 * Collision detection
468 len
= rb_capsule__scene( mtx
, &w
->collider
, NULL
,
469 &world
->rb_geo
.inf
.scene
, manifold
, 0 );
470 player_walk_custom_filter( world
, manifold
, len
, 0.01f
);
471 len
= rb_manifold_apply_filtered( manifold
, len
);
473 v3f surface_avg
= { 0.0f
, 0.0f
, 0.0f
};
475 if( w
->state
.activity
!= k_walk_activity_lockedmove
)
476 w
->state
.activity
= k_walk_activity_air
;
478 w
->surface
= k_surface_prop_concrete
;
480 for( int i
=0; i
<len
; i
++ ){
481 struct contact
*ct
= &manifold
[i
];
482 rb_debug_contact( ct
);
484 if( player_walk_normal_standable( ct
->n
) ){
485 if( w
->state
.activity
!= k_walk_activity_lockedmove
)
486 w
->state
.activity
= k_walk_activity_ground
;
488 v3_add( surface_avg
, ct
->n
, surface_avg
);
490 struct world_surface
*surf
= world_contact_surface( world
, ct
);
491 if( surf
->info
.surface_prop
> w
->surface
)
492 w
->surface
= surf
->info
.surface_prop
;
495 rb_prepare_contact( ct
, k_rb_delta
);
501 float accel_speed
= 0.0f
, nominal_speed
= 0.0f
;
504 v3_muls( right_dir
, steer
[0], movedir
);
505 v3_muladds( movedir
, forward_dir
, steer
[1], movedir
);
507 if( w
->state
.activity
== k_walk_activity_ground
){
508 v3_normalize( surface_avg
);
511 v3_tangent_basis( surface_avg
, tx
, ty
);
513 if( v2_length2(steer
) > 0.001f
){
514 /* clip movement to the surface */
515 float d
= v3_dot(surface_avg
,movedir
);
516 v3_muladds( movedir
, surface_avg
, -d
, movedir
);
519 accel_speed
= k_walk_accel
;
520 nominal_speed
= k_walkspeed
;
523 if( w
->state
.jump_queued
){
524 w
->state
.jump_queued
= 0;
526 f32 t
= vg
.time
- w
->state
.jump_input_time
;
527 if( t
< PLAYER_JUMP_EPSILON
){
528 localplayer
.rb
.v
[1] = 5.0f
;
529 w
->state
.activity
= k_walk_activity_air
;
530 prev_state
= k_walk_activity_air
;
531 accel_speed
= k_walk_air_accel
;
532 nominal_speed
= k_airspeed
;
536 player_friction( localplayer
.rb
.v
);
540 accel_speed
= k_walk_air_accel
;
541 nominal_speed
= k_airspeed
;
544 if( v2_length2( steer
) > 0.001f
){
545 player_accelerate( localplayer
.rb
.v
, movedir
,
546 nominal_speed
, accel_speed
);
547 v3_normalize( movedir
);
551 * Resolve velocity constraints
553 for( int j
=0; j
<5; j
++ ){
554 for( int i
=0; i
<len
; i
++ ){
555 struct contact
*ct
= &manifold
[i
];
558 float vn
= -v3_dot( localplayer
.rb
.v
, ct
->n
);
560 float temp
= ct
->norm_impulse
;
561 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
562 vn
= ct
->norm_impulse
- temp
;
564 v3_muladds( localplayer
.rb
.v
, ct
->n
, vn
, localplayer
.rb
.v
);
569 if( w
->state
.activity
== k_walk_activity_ground
||
570 prev_state
== k_walk_activity_ground
){
571 float max_dist
= 0.4f
;
574 v3_copy( localplayer
.rb
.co
, pa
);
575 pa
[1] += w
->collider
.radius
+ max_dist
;
576 v3_add( pa
, (v3f
){0, -max_dist
* 2.0f
, 0}, pb
);
577 vg_line( pa
, pb
, 0xff000000 );
581 if( spherecast_world( world
, pa
, pb
,
582 w
->collider
.radius
, &t
, n
, 0 ) != -1 ){
583 if( player_walk_normal_standable(n
) ){
584 v3_lerp( pa
, pb
, t
, localplayer
.rb
.co
);
585 localplayer
.rb
.co
[1] += -w
->collider
.radius
- k_penetration_slop
;
586 w
->state
.activity
= k_walk_activity_ground
;
588 float d
= -v3_dot(n
,localplayer
.rb
.v
);
589 v3_muladds( localplayer
.rb
.v
, n
, d
, localplayer
.rb
.v
);
590 localplayer
.rb
.v
[1] += -k_gravity
* k_rb_delta
;
599 rb_depenetrate( manifold
, len
, dt
);
600 v3_add( dt
, localplayer
.rb
.co
, localplayer
.rb
.co
);
603 if( w
->state
.activity
== k_walk_activity_air
){
604 localplayer
.rb
.v
[1] += -k_gravity
*k_rb_delta
;
607 if( localplayer
.immobile
){
608 localplayer
.rb
.v
[0] = 0.0f
;
609 localplayer
.rb
.v
[2] = 0.0f
;
612 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.v
, k_rb_delta
,
614 v3_add( localplayer
.rb
.co
, (v3f
){0,1,0}, mtx
[3] );
615 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__GREEN
);
619 * ---------------------------------------------------
624 lwr_offs
= { 0.0f
, w
->collider
.radius
, 0.0f
};
626 v3_add( lwr_offs
, w
->state
.prev_pos
, lwr_prev
);
627 v3_add( lwr_offs
, localplayer
.rb
.co
, lwr_now
);
630 v3_sub( localplayer
.rb
.co
, w
->state
.prev_pos
, movedelta
);
632 float movedist
= v3_length( movedelta
);
634 if( movedist
> 0.3f
){
635 float t
, sr
= w
->collider
.radius
-0.04f
;
638 if( spherecast_world( world
, lwr_prev
, lwr_now
, sr
, &t
, n
, 0 ) != -1 ){
639 v3_lerp( lwr_prev
, lwr_now
, vg_maxf(0.01f
,t
), localplayer
.rb
.co
);
640 localplayer
.rb
.co
[1] -= w
->collider
.radius
;
641 rb_update_transform( &localplayer
.rb
);
643 v3_add( localplayer
.rb
.co
, (v3f
){0,1,0}, mtx
[3] );
644 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__RED
);
648 u32 id
= world_intersect_gates(world
, localplayer
.rb
.co
, w
->state
.prev_pos
);
650 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, mdl_entity_id_id(id
) );
651 m4x3_mulv( gate
->transport
, localplayer
.rb
.co
, localplayer
.rb
.co
);
652 m3x3_mulv( gate
->transport
, localplayer
.rb
.v
, localplayer
.rb
.v
);
654 v4f transport_rotation
;
655 m3x3_q( gate
->transport
, transport_rotation
);
656 q_mul( transport_rotation
, localplayer
.rb
.q
, localplayer
.rb
.q
);
658 rb_update_transform( &localplayer
.rb
);
659 player__pass_gate( id
);
661 rb_update_transform( &localplayer
.rb
);
664 static void player__walk_post_update(void){
665 struct player_walk
*w
= &player_walk
;
668 m3x3_copy( localplayer
.rb
.to_world
, mtx
);
669 v3_add( localplayer
.rb
.co
, (v3f
){0,1,0}, mtx
[3] );
671 float substep
= vg
.time_fixed_extrapolate
;
672 v3_muladds( mtx
[3], localplayer
.rb
.v
, k_rb_delta
*substep
, mtx
[3] );
673 vg_line_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__YELOW
);
676 /* Calculate header */
678 if( player_xyspeed2() > 0.1f
*0.1f
){
679 float a
= atan2f( localplayer
.rb
.v
[0], localplayer
.rb
.v
[2] );
680 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, a
);
683 vg_line_point( w
->state
.drop_in_target
, 0.1f
, VG__GREEN
);
685 v3_muladds( w
->state
.drop_in_target
, w
->state
.drop_in_normal
, 0.3f
, p1
);
686 vg_line( w
->state
.drop_in_target
, p1
, VG__GREEN
);
687 v3_muladds( w
->state
.drop_in_target
, localplayer
.rb
.to_world
[1], 0.3f
, p1
);
688 vg_line( w
->state
.drop_in_target
, p1
, VG__GREEN
);
690 vg_line( w
->state
.drop_in_target
, w
->state
.drop_in_foot_anchor
, VG__WHITE
);
691 vg_line_point( w
->state
.drop_in_foot_anchor
, 0.08f
, VG__PINK
);
694 float a
= player_get_heading_yaw();
699 v3_add( localplayer
.rb
.co
, p1
, p1
);
700 vg_line( localplayer
.rb
.co
, p1
, VG__PINK
);
703 if( vg_fractf(w
->state
.walk_timer
) > 0.5f
)
708 if( (w
->state
.step_phase
!= walk_phase
) &&
709 (w
->state
.activity
== k_walk_activity_ground
) )
712 if( w
->surface
== k_surface_prop_concrete
){
714 &audio_footsteps
[vg_randu32()%vg_list_size(audio_footsteps
)],
715 localplayer
.rb
.co
, 40.0f
, 1.0f
718 else if( w
->surface
== k_surface_prop_grass
){
720 &audio_footsteps_grass
[ vg_randu32()%
721 vg_list_size(audio_footsteps_grass
)],
722 localplayer
.rb
.co
, 40.0f
, 1.0f
725 else if( w
->surface
== k_surface_prop_wood
){
727 &audio_footsteps_wood
[ vg_randu32()%
728 vg_list_size(audio_footsteps_wood
)],
729 localplayer
.rb
.co
, 40.0f
, 1.0f
735 w
->state
.step_phase
= walk_phase
;
738 static void player__walk_animate(void){
739 struct player_walk
*w
= &player_walk
;
740 player_pose
*pose
= &localplayer
.pose
;
741 struct player_walk_animator
*animator
= &w
->animator
;
743 animator
->outro_type
= w
->state
.outro_type
;
746 f32 fly
= (w
->state
.activity
== k_walk_activity_air
)? 1.0f
: 0.0f
,
749 if( w
->state
.activity
== k_walk_activity_air
) rate
= 2.4f
;
752 animator
->fly
= vg_lerpf( animator
->fly
, fly
, rate
*vg
.time_delta
);
753 animator
->run
= vg_lerpf( animator
->run
, w
->move_speed
,
757 if( w
->move_speed
> 0.025f
){
759 float walk_norm
= 30.0f
/(float)w
->anim_walk
->length
,
760 run_norm
= 30.0f
/(float)w
->anim_run
->length
,
761 walk_adv
= vg_lerpf( walk_norm
, run_norm
, w
->move_speed
);
763 w
->state
.walk_timer
+= walk_adv
* vg
.time_delta
;
766 w
->state
.walk_timer
= 0.0f
;
767 animator
->walk_timer
= w
->state
.walk_timer
;
770 if( localplayer
.immobile
|| (w
->state
.outro_type
== k_walk_outro_drop_in
) ){
771 v3_copy( localplayer
.rb
.co
, animator
->root_co
);
772 v4_copy( localplayer
.rb
.q
, animator
->root_q
);
775 rb_extrapolate( &localplayer
.rb
, animator
->root_co
, animator
->root_q
);
778 f32 walk_yaw
= player_get_heading_yaw();
781 animator
->sit_t
= w
->state
.sit_t
;
784 f32 head_yaw
= localplayer
.angles
[0] + VG_PIf
,
785 y
= vg_angle_diff( head_yaw
, -walk_yaw
),
786 p
= vg_clampf( localplayer
.angles
[1],
787 -k_sit_pitch_limit
, k_sit_pitch_limit
);
789 if( fabsf(y
) > k_sit_yaw_limit
){
793 animator
->yaw
= vg_lerpf( animator
->yaw
, y
, vg
.time_delta
*2.0f
);
794 animator
->pitch
= vg_lerpf( animator
->pitch
, p
, vg
.time_delta
*2.8f
);
797 if( w
->state
.outro_type
){
798 struct skeleton_anim
*anim
=
799 player_walk_outro_anim( w
->state
.outro_type
);
800 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
801 outro_time
= vg
.time
- w
->state
.outro_start_time
;
802 animator
->outro_t
= outro_time
/ outro_length
;
804 if( w
->state
.outro_type
== k_walk_outro_drop_in
){
805 float inv_rate
= 1.0f
/ anim
->rate
,
806 anim_frames
= anim
->length
* inv_rate
,
807 step_frames
= 12.0f
* inv_rate
,
808 commit_frames
= 6.0f
* inv_rate
,
809 drop_frames
= anim_frames
- step_frames
,
810 step_t
= vg_minf( 1.0f
, outro_time
/ step_frames
),
811 remaind_time
= vg_maxf( 0.0f
, outro_time
- step_frames
),
812 dop_t
= vg_minf( 1.0f
, remaind_time
/ drop_frames
);
813 animator
->commit_t
= vg_minf( 1.0f
, remaind_time
/ commit_frames
);
815 walk_yaw
= vg_alerpf( w
->state
.drop_in_start_angle
,
816 w
->state
.drop_in_angle
, step_t
);
818 v3_lerp( w
->state
.drop_in_start
, w
->state
.drop_in_target
,
819 step_t
, localplayer
.rb
.co
);
820 v3_copy( localplayer
.rb
.co
, animator
->root_co
);
822 /* for the camera purposes only */
824 player_walk_drop_in_vector( init_velocity
);
825 v3_muls( init_velocity
, dop_t
, localplayer
.rb
.v
);
826 v3_copy( localplayer
.rb
.v
,
827 localplayer
.cam_control
.cam_velocity_smooth
);
829 q_axis_angle( animator
->root_q
, (v3f
){0.0f
,1.0f
,0.0f
},
832 v3_copy( w
->state
.drop_in_foot_anchor
, animator
->foot_anchor
);
834 /* the drop in bit */
835 if( step_t
>= 1.0f
){
838 player_walk_drop_in_overhang_transform( dop_t
, final_co
, final_q
);
840 q_mul( final_q
, animator
->root_q
, animator
->root_q
);
841 v3_copy( final_co
, animator
->root_co
);
844 v4_copy( animator
->root_q
, localplayer
.rb
.q
);
845 rb_update_transform( &localplayer
.rb
);
847 v3_muladds( animator
->root_co
, localplayer
.rb
.to_world
[1],
848 -0.1f
*dop_t
, animator
->root_co
);
849 v3_copy( animator
->root_co
, localplayer
.rb
.co
);
855 v3_muladds( animator
->root_co
, localplayer
.rb
.to_world
[1],
856 -0.1f
*animator
->outro_t
, animator
->root_co
);
860 q_axis_angle( animator
->root_q
, (v3f
){0.0f
,1.0f
,0.0f
}, walk_yaw
+ VG_PIf
);
863 static void player__walk_pose( void *_animator
, player_pose
*pose
){
864 struct player_walk
*w
= &player_walk
;
865 struct player_walk_animator
*animator
= _animator
;
866 struct skeleton
*sk
= &localplayer
.skeleton
;
868 v3_copy( animator
->root_co
, pose
->root_co
);
869 v4_copy( animator
->root_q
, pose
->root_q
);
870 pose
->board
.lean
= 0.0f
;
871 pose
->type
= k_player_pose_type_ik
;
873 float walk_norm
= (float)w
->anim_walk
->length
/30.0f
,
874 run_norm
= (float)w
->anim_run
->length
/30.0f
,
875 t
= animator
->walk_timer
,
876 l
= vg_clampf( animator
->run
*15.0f
, 0.0f
, 1.0f
),
877 idle_walk
= vg_clampf( (animator
->run
-0.1f
)/(1.0f
-0.1f
), 0.0f
, 1.0f
);
880 mdl_keyframe apose
[32], bpose
[32];
881 skeleton_sample_anim( sk
, w
->anim_walk
, t
*walk_norm
, apose
);
882 skeleton_sample_anim( sk
, w
->anim_run
, t
*run_norm
, bpose
);
884 skeleton_lerp_pose( sk
, apose
, bpose
, l
, apose
);
887 skeleton_sample_anim( sk
, w
->anim_idle
, vg
.time
*0.1f
, bpose
);
888 skeleton_lerp_pose( sk
, apose
, bpose
, 1.0f
-idle_walk
, apose
);
891 skeleton_sample_anim( sk
, w
->anim_jump
, vg
.time
*0.6f
, bpose
);
892 skeleton_lerp_pose( sk
, apose
, bpose
, animator
->fly
, apose
);
895 if( animator
->sit_t
> 0.0f
){
896 f32 sit_norm
= (f32
)(w
->anim_sit
->length
-1)/30.0f
,
897 st
= vg_minf( 1.0f
, animator
->sit_t
);
898 skeleton_sample_anim( sk
, w
->anim_sit
, st
*sit_norm
, bpose
);
901 f32
*qh
= bpose
[localplayer
.id_head
-1].q
;
902 q_axis_angle( qy
, (v3f
){0.0f
,1.0f
,0.0f
}, animator
->yaw
*0.5f
*st
);
903 q_axis_angle( qp
, (v3f
){0.0f
,0.0f
,1.0f
}, animator
->pitch
*st
);
908 qh
= bpose
[localplayer
.id_chest
-1].q
;
909 q_axis_angle( qy
, (v3f
){0.0f
,1.0f
,0.0f
}, animator
->yaw
*0.5f
*st
);
913 skeleton_lerp_pose( sk
, apose
, bpose
, vg_minf(1.0f
,st
*10.0f
), apose
);
916 if( animator
->outro_type
){
917 struct skeleton_anim
*anim
= player_walk_outro_anim(animator
->outro_type
);
920 skeleton_copy_pose( sk
, apose
, pose
->keyframes
);
924 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
925 outro_time
= animator
->outro_t
*outro_length
;
927 skeleton_sample_anim_clamped( sk
, anim
, outro_time
, bpose
);
928 skeleton_lerp_pose( sk
, apose
, bpose
, animator
->outro_t
*10.0f
,
931 if( animator
->outro_type
== k_walk_outro_drop_in
){
932 m4x3f transform
, inverse
;
933 q_m3x3( pose
->root_q
, transform
);
934 v3_copy( pose
->root_co
, transform
[3] );
935 m4x3_invert_affine( transform
, inverse
);
938 m4x3_mulv( inverse
, animator
->foot_anchor
, anchored_pos
);
940 v3_lerp( pose
->keyframes
[ localplayer
.id_ik_foot_r
-1 ].co
,
942 1.0f
-animator
->commit_t
,
943 pose
->keyframes
[ localplayer
.id_ik_foot_r
-1 ].co
);
947 skeleton_copy_pose( sk
, apose
, pose
->keyframes
);
950 static void player__walk_post_animate(void){
954 struct player_walk
*w
= &player_walk
;
956 if( w
->state
.outro_type
){
957 struct skeleton_anim
*anim
= player_walk_outro_anim(w
->state
.outro_type
);
959 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
960 outro_time
= vg
.time
- w
->state
.outro_start_time
,
961 outro_t
= outro_time
/ outro_length
;
963 localplayer
.cam_velocity_influence
= outro_t
;
966 localplayer
.cam_velocity_influence
= 0.0f
;
969 static void player__walk_im_gui(void){
970 struct player_walk
*w
= &player_walk
;
971 player__debugtext( 1, "V: %5.2f %5.2f %5.2f",localplayer
.rb
.v
[0],
973 localplayer
.rb
.v
[2] );
974 player__debugtext( 1, "CO: %5.2f %5.2f %5.2f",localplayer
.rb
.co
[0],
975 localplayer
.rb
.co
[1],
976 localplayer
.rb
.co
[2] );
977 player__debugtext( 1, "activity: %s\n",
978 (const char *[]){ "k_walk_activity_air",
979 "k_walk_activity_ground",
980 "k_walk_activity_sleep",
981 "k_walk_activity_lockedmove",
982 "k_walk_activity_sit",
983 "k_walk_activity_sit_up" }
984 [w
->state
.activity
] );
985 player__debugtext( 1, "surface: %s\n",
986 (const char *[]){ "concrete",
993 if( w
->state
.outro_type
){
994 struct skeleton_anim
*anim
=
995 player_walk_outro_anim( w
->state
.outro_type
);
997 f32 outro_length
= (f32
)anim
->length
/ anim
->rate
,
998 outro_time
= vg
.time
- w
->state
.outro_start_time
;
999 player__debugtext( 1, "outro time: %f / %f", outro_time
, outro_length
);
1003 static void player__walk_bind(void){
1004 struct player_walk
*w
= &player_walk
;
1005 struct skeleton
*sk
= &localplayer
.skeleton
;
1007 w
->anim_idle
= skeleton_get_anim( sk
, "idle_cycle+y" );
1008 w
->anim_walk
= skeleton_get_anim( sk
, "walk+y" );
1009 w
->anim_run
= skeleton_get_anim( sk
, "run+y" );
1010 w
->anim_jump
= skeleton_get_anim( sk
, "jump+y" );
1011 w
->anim_jump_to_air
= skeleton_get_anim( sk
, "jump_to_air" );
1012 w
->anim_drop_in
= skeleton_get_anim( sk
, "drop_in" );
1013 w
->anim_intro
= skeleton_get_anim( sk
, "into_skate" );
1014 w
->anim_sit
= skeleton_get_anim( sk
, "sit" );
1017 static void player__walk_transition(void){
1018 struct player_walk
*w
= &player_walk
;
1019 w
->state
.activity
= k_walk_activity_air
;
1020 w
->state
.outro_type
= k_walk_outro_none
;
1021 w
->state
.outro_start_time
= 0.0;
1022 w
->state
.jump_queued
= 0;
1023 w
->state
.jump_input_time
= 0.0;
1024 w
->state
.walk_timer
= 0.0f
;
1025 w
->state
.step_phase
= 0;
1027 v3f fwd
= { 0.0f
, 0.0f
, 1.0f
};
1028 q_mulv( localplayer
.rb
.q
, fwd
, fwd
);
1029 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
1030 atan2f(fwd
[0], fwd
[2]) );
1032 rb_update_transform( &localplayer
.rb
);
1035 static void player__walk_reset(void){
1036 struct player_walk
*w
= &player_walk
;
1037 w
->state
.activity
= k_walk_activity_air
;
1038 w
->state
.outro_type
= k_walk_outro_none
;
1039 w
->state
.outro_start_time
= 0.0;
1041 v3f fwd
= { 0.0f
, 0.0f
, 1.0f
};
1042 q_mulv( localplayer
.rb
.q
, fwd
, fwd
);
1043 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
1044 atan2f(fwd
[0], fwd
[2]) );
1046 rb_update_transform( &localplayer
.rb
);
1049 static void player__walk_animator_exchange( bitpack_ctx
*ctx
, void *data
){
1050 struct player_walk_animator
*animator
= data
;
1052 bitpack_qv3f( ctx
, 24, -1024.0f
, 1024.0f
, animator
->root_co
);
1053 bitpack_qquat( ctx
, animator
->root_q
);
1054 bitpack_qf32( ctx
, 8, 0.0f
, 1.0f
, &animator
->fly
);
1055 bitpack_qf32( ctx
, 8, 0.0f
, 1.0f
, &animator
->run
);
1056 bitpack_qf32( ctx
, 8, 0.0f
, 1.0f
, &animator
->walk
);
1057 bitpack_qf32( ctx
, 16, 0.0f
, 120.0f
, &animator
->walk_timer
);
1059 for( int i
=0; i
<1; i
++ ){ /* without this you get a warning from gcc. lol */
1060 bitpack_bytes( ctx
, 8, &animator
->outro_type
);
1061 if( animator
->outro_type
){
1062 bitpack_bytes( ctx
, sizeof(animator
->foot_anchor
),
1063 animator
->foot_anchor
);
1064 bitpack_qf32( ctx
, 8, 0.0f
, 1.0f
, &animator
->outro_t
);
1065 bitpack_qf32( ctx
, 8, 0.0f
, 1.0f
, &animator
->commit_t
);
1069 u32 code
= bitpack_qf32( ctx
, 8, 0.0f
, 1.0f
, &animator
->sit_t
);
1071 bitpack_qf32( ctx
, 8, -k_sit_yaw_limit
, k_sit_yaw_limit
, &animator
->yaw
);
1072 bitpack_qf32( ctx
, 8, -k_sit_pitch_limit
, k_sit_pitch_limit
,
1077 static void player__walk_sfx_oneshot( u8 id
, v3f pos
, f32 volume
){
1080 if( id
== k_player_walk_soundeffect_splash
){
1081 audio_oneshot_3d( &audio_splash
, pos
, 40.0f
, 1.0f
);
1086 #endif /* PLAYER_DEVICE_WALK_H */