1 #include "vg/vg_rigidbody_collision.h"
4 #include "player_walk.h"
5 #include "player_skate.h"
6 #include "player_dead.h"
10 #include "scene_rigidbody.h"
12 struct player_walk player_walk
;
13 struct player_subsystem_interface player_subsystem_walk
=
15 .system_register
= player__walk_register
,
16 .bind
= player__walk_bind
,
17 .pre_update
= player__walk_pre_update
,
18 .update
= player__walk_update
,
19 .post_update
= player__walk_post_update
,
20 .im_gui
= player__walk_im_gui
,
21 .animate
= player__walk_animate
,
22 .post_animate
= player__walk_post_animate
,
23 .pose
= player__walk_pose
,
24 .network_animator_exchange
= player__walk_animator_exchange
,
26 .animator_data
= &player_walk
.animator
,
27 .animator_size
= sizeof(player_walk
.animator
),
32 static void player_walk_drop_in_vector( v3f vec
){
34 v3_cross( (v3f
){0.0f
,1.0f
,0.0f
}, player_walk
.state
.drop_in_normal
, axis
);
35 v3_cross( axis
, player_walk
.state
.drop_in_normal
, init_dir
);
36 v3_normalize( init_dir
);
37 v3_muls( init_dir
, 4.25f
, vec
);
40 static float player_xyspeed2(void){
41 return v3_length2( (v3f
){localplayer
.rb
.v
[0], 0.0f
, localplayer
.rb
.v
[2]} );
44 static void player_walk_generic_to_skate( enum skate_activity init
, f32 yaw
){
45 localplayer
.subsystem
= k_player_subsystem_skate
;
49 if( player_xyspeed2() < 0.1f
* 0.1f
)
50 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,0.0f
,1.6f
}, v
);
52 v3_copy( localplayer
.rb
.v
, v
);
54 player_skate
.state
.activity_prev
= k_skate_activity_ground
;
55 player_skate
.state
.activity
= init
;
61 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
62 atan2f(-dir
[0],-dir
[2]) );
63 q_normalize( localplayer
.rb
.q
);
65 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, player_skate
.state
.cog
);
66 v3_add( player_skate
.state
.cog
, localplayer
.rb
.co
, player_skate
.state
.cog
);
68 v3_copy( v
, player_skate
.state
.cog_v
);
69 v3_copy( v
, localplayer
.rb
.v
);
71 player__begin_holdout( (v3f
){0.0f
,0.0f
,0.0f
} );
72 player__skate_reset_animator();
73 player__skate_clear_mechanics();
74 rb_update_matrices( &localplayer
.rb
);
75 v3_copy( (v3f
){yaw
,0.0f
,0.0f
}, player_skate
.state
.trick_euler
);
77 if( init
== k_skate_activity_air
)
78 player__approximate_best_trajectory();
81 static void player_walk_drop_in_to_skate(void){
82 localplayer
.immobile
= 0;
83 localplayer
.subsystem
= k_player_subsystem_skate
;
85 player_skate
.state
.activity_prev
= k_skate_activity_ground
;
86 player_skate
.state
.activity
= k_skate_activity_ground
;
88 player__begin_holdout( (v3f
){0,0,0} );
89 player__skate_clear_mechanics();
90 player__skate_reset_animator();
93 player_walk_drop_in_vector( init_velocity
);
95 rb_update_matrices( &localplayer
.rb
);
96 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.to_world
[1], 1.0f
,
97 player_skate
.state
.cog
);
98 v3_copy( init_velocity
, player_skate
.state
.cog_v
);
99 v3_copy( init_velocity
, localplayer
.rb
.v
);
100 v3_copy( init_velocity
, localplayer
.cam_control
.cam_velocity_smooth
);
101 v3_copy( (v3f
){player_walk
.animator
.board_yaw
+1.0f
,0,0},
102 player_skate
.state
.trick_euler
);
105 static void player_walk_drop_in_overhang_transform( f32 t
, v3f co
, v4f q
){
107 v3_cross( (v3f
){0,1,0}, player_walk
.state
.drop_in_normal
, axis
);
108 v3_normalize( axis
);
110 float a
= acosf( player_walk
.state
.drop_in_normal
[1] ) * t
;
111 q_axis_angle( q
, axis
, a
);
114 heading_angle
= player_walk
.state
.drop_in_angle
;
117 overhang
[0] = sinf( heading_angle
) * l
;
118 overhang
[1] = 0.28f
* l
;
119 overhang
[2] = cosf( heading_angle
) * l
;
121 q_mulv( q
, overhang
, overhang
);
122 v3_add( player_walk
.state
.drop_in_target
, overhang
, co
);
125 static int player_walk_scan_for_drop_in(void){
126 world_instance
*world
= world_current_instance();
129 q_mulv( localplayer
.rb
.q
, (v3f
){0.0f
,0.0f
,1.0f
}, dir
);
130 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.to_world
[1], -1.0f
, center
);
133 int sample_count
= 0;
135 for( int i
=0; i
<20; i
++ ){
136 float t
= (float)i
* (1.0f
/19.0f
),
137 s
= sinf( t
* VG_PIf
* 0.25f
),
138 c
= cosf( t
* VG_PIf
* 0.25f
);
141 v3_muls ( localplayer
.rb
.to_world
[1], -c
, ray_dir
);
142 v3_muladds( ray_dir
, dir
, -s
, ray_dir
);
143 v3_muladds( center
, ray_dir
, -2.0f
, pos
);
145 ray_hit
*ray
= &samples
[ sample_count
];
148 if( ray_world( world
, pos
, ray_dir
, ray
, 0 ) ){
149 vg_line( pos
, ray
->pos
, VG__RED
);
150 vg_line_point( ray
->pos
, 0.025f
, VG__BLACK
);
156 float min_a
= 0.70710678118654752f
;
157 ray_hit
*candidate
= NULL
;
159 if( sample_count
>= 2 ){
160 for( int i
=0; i
<sample_count
-1; i
++ ){
161 ray_hit
*s0
= &samples
[i
],
164 float a
= v3_dot( s0
->normal
, s1
->normal
);
166 if( (a
< min_a
) && (a
>= -0.1f
) && (s0
->normal
[1]>s1
->normal
[1]) ){
176 ray_hit
*s0
= candidate
,
179 vg_line( s0
->pos
, s1
->pos
, VG__WHITE
);
181 v3_copy( s0
->normal
, pa
);
182 v3_copy( s1
->normal
, pb
);
183 v3_cross( localplayer
.rb
.to_world
[1], dir
, pc
);
186 pa
[3] = v3_dot( pa
, s0
->pos
);
187 pb
[3] = v3_dot( pb
, s1
->pos
);
188 pc
[3] = v3_dot( pc
, localplayer
.rb
.co
);
191 if( plane_intersect3( pa
, pb
, pc
, edge
) ){
192 v3_copy( edge
, player_walk
.state
.drop_in_target
);
193 v3_copy( s1
->normal
, player_walk
.state
.drop_in_normal
);
194 v3_copy( localplayer
.rb
.co
, player_walk
.state
.drop_in_start
);
196 player_walk
.state
.drop_in_start_angle
= player_get_heading_yaw();
197 player_walk
.state
.drop_in_angle
=
198 atan2f( player_walk
.state
.drop_in_normal
[0],
199 player_walk
.state
.drop_in_normal
[2] );
201 /* TODO: scan multiple of these? */
204 player_walk_drop_in_overhang_transform( 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( localplayer
.rb
.v
);
240 vg_error( "failed to find intersection of drop in\n" );
247 static bool player__preupdate_anim( struct skeleton_anim
*anim
, f32
*t
,
249 f32 length
= (f32
)(anim
->length
-1) / anim
->rate
;
250 *t
+= (vg
.time_delta
* speed
) / length
;
252 if( *t
>= 1.0f
) return 1;
256 static void player_walk_pre_sit(void){
257 struct player_walk
*w
= &player_walk
;
260 joystick_state( k_srjoystick_steer
, steer
);
262 vg_slewf( &w
->state
.transition_t
, 1.0f
, vg
.time_delta
);
264 if( button_down(k_srbind_sit
) || (v2_length2(steer
)>0.2f
) ||
265 button_down(k_srbind_jump
) ){
266 w
->state
.activity
= k_walk_activity_sit_up
;
271 static void player_walk_pre_sit_up(void){
272 struct player_walk
*w
= &player_walk
;
274 if( w
->state
.transition_t
> 0.0f
)
275 vg_slewf( &w
->state
.transition_t
, 0.0f
, vg
.time_delta
);
277 w
->state
.activity
= k_walk_activity_ground
;
279 if( button_down(k_srbind_sit
) )
280 w
->state
.activity
= k_walk_activity_sit
;
285 static void player_walk_pre_ground(void){
286 struct player_walk
*w
= &player_walk
;
288 if( button_down(k_srbind_sit
) ){
289 v3_zero( localplayer
.rb
.v
);
290 w
->state
.activity
= k_walk_activity_sit
;
291 w
->state
.transition_t
= 0.0f
;
295 if( button_down( k_srbind_use
) ){
296 if( player_walk_scan_for_drop_in() ){
297 w
->state
.activity
= k_walk_activity_odrop_in
;
300 w
->state
.activity
= k_walk_activity_oregular
;
303 w
->state
.transition_t
= 0.0f
;
306 if( button_down( k_srbind_jump
) ){
307 w
->state
.jump_queued
= 1;
308 w
->state
.jump_input_time
= vg
.time
;
312 static void player_walk_pre_air(void){
313 struct player_walk
*w
= &player_walk
;
314 if( button_down( k_srbind_use
) ){
315 w
->state
.activity
= k_walk_activity_oair
;
316 w
->state
.transition_t
= 0.0f
;
319 if( button_down( k_srbind_jump
) ){
320 w
->state
.jump_queued
= 1;
321 w
->state
.jump_input_time
= vg
.time
;
325 static void player_walk_pre_drop_in(void){
326 struct player_walk
*w
= &player_walk
;
327 bool finished
= player__preupdate_anim( w
->anim_drop_in
,
328 &w
->state
.transition_t
, 1.0f
);
330 player_walk_drop_in_to_skate();
333 static void player_walk_pre_caveman(void){
334 struct player_walk
*w
= &player_walk
;
335 bool finished
= player__preupdate_anim( w
->anim_jump_to_air
,
336 &w
->state
.transition_t
, 1.0f
);
338 player_walk_generic_to_skate( k_skate_activity_air
,
339 player_walk
.animator
.board_yaw
);
343 static void player_walk_pre_running_start(void){
344 struct player_walk
*w
= &player_walk
;
345 bool finished
= player__preupdate_anim( w
->anim_intro
,
346 &w
->state
.transition_t
, 1.0f
);
348 /* TODO: get the derivative of the last keyframes to calculate new
349 * velocity for player */
350 player_walk_generic_to_skate( k_skate_activity_ground
,
351 player_walk
.animator
.board_yaw
+1.0f
);
355 static void player_walk_pre_popoff(void){
356 struct player_walk
*w
= &player_walk
;
357 bool finished
= player__preupdate_anim( w
->anim_popoff
,
358 &w
->state
.transition_t
, 1.0f
);
361 w
->state
.activity
= k_walk_activity_ground
;
362 w
->animator
.board_yaw
+= 1.0f
;
366 void player__walk_pre_update(void){
367 struct player_walk
*w
= &player_walk
;
369 if( localplayer
.immobile
) return;
370 else player_look( localplayer
.angles
, skaterift
.time_rate
);
372 enum walk_activity a
= w
->state
.activity
;
374 if ( a
== k_walk_activity_sit
) player_walk_pre_sit();
375 else if( a
== k_walk_activity_sit_up
) player_walk_pre_sit_up();
376 else if( a
== k_walk_activity_ground
) player_walk_pre_ground();
377 else if( a
== k_walk_activity_air
) player_walk_pre_air();
378 else if( a
== k_walk_activity_odrop_in
) player_walk_pre_drop_in();
379 else if( a
== k_walk_activity_oair
) player_walk_pre_caveman();
380 else if( a
== k_walk_activity_oregular
) player_walk_pre_running_start();
381 else if( a
== k_walk_activity_ipopoff
) player_walk_pre_popoff();
384 static int player_walk_normal_standable( v3f n
){
385 return n
[1] > 0.70710678118f
;
388 static void player_accelerate( v3f v
, v3f movedir
, f32 speed
, f32 accel
){
389 float currentspeed
= v3_dot( v
, movedir
),
390 addspeed
= speed
- currentspeed
;
395 float accelspeed
= accel
* vg
.time_fixed_delta
* speed
;
397 if( accelspeed
> addspeed
)
398 accelspeed
= addspeed
;
400 v3_muladds( v
, movedir
, accelspeed
, v
);
403 static void player_friction( v3f v
, f32 friction
){
404 float speed
= v3_length( v
),
406 control
= vg_maxf( speed
, k_stopspeed
);
411 drop
+= control
* friction
* vg
.time_fixed_delta
;
413 float newspeed
= vg_maxf( 0.0f
, speed
- drop
);
416 v3_muls( v
, newspeed
, v
);
419 static void player_walk_custom_filter( world_instance
*world
,
420 rb_ct
*man
, int len
, f32 w
){
421 for( int i
=0; i
<len
; i
++ ){
423 if( ci
->type
== k_contact_type_disabled
||
424 ci
->type
== k_contact_type_edge
)
428 float d1
= v3_dot( ci
->co
, ci
->n
);
430 for( int j
=0; j
<len
; j
++ ){
435 if( cj
->type
== k_contact_type_disabled
)
438 struct world_surface
*si
= world_contact_surface( world
, ci
),
439 *sj
= world_contact_surface( world
, cj
);
441 if( (sj
->info
.flags
& k_material_flag_walking
) &&
442 !(si
->info
.flags
& k_material_flag_walking
)){
446 float d2
= v3_dot( cj
->co
, ci
->n
),
449 if( fabsf( d
) <= w
){
450 cj
->type
= k_contact_type_disabled
;
456 static void player_walk_update_generic(void){
457 struct player_walk
*w
= &player_walk
;
459 if( (w
->state
.activity
!= k_walk_activity_oregular
) &&
460 (w
->state
.activity
!= k_walk_activity_oair
) ){
461 joystick_state( k_srjoystick_steer
, w
->state
.steer
);
462 w
->state
.steer
[2] = button_press(k_srbind_run
)? k_runspeed
: k_walkspeed
;
463 if( v2_length2(w
->state
.steer
)>1.0f
)
464 v2_normalize(w
->state
.steer
);
467 v3_copy( localplayer
.rb
.co
, w
->state
.prev_pos
);
468 v3_zero( localplayer
.rb
.w
);
470 world_instance
*world
= world_current_instance();
472 if( world
->water
.enabled
){
473 if( localplayer
.rb
.co
[1]+0.4f
< world
->water
.height
){
474 player__networked_sfx( k_player_subsystem_walk
, 32,
475 k_player_walk_soundeffect_splash
,
476 localplayer
.rb
.co
, 1.0f
);
477 vg_info( "player fell of due to walking into walker\n" );
478 player__dead_transition( k_player_die_type_generic
);
483 enum walk_activity prev_state
= w
->state
.activity
;
485 w
->collider
.h
= 2.0f
;
486 w
->collider
.r
= 0.3f
;
489 m3x3_copy( localplayer
.rb
.to_world
, mtx
);
490 v3_add( localplayer
.rb
.co
, (v3f
){0,1,0}, mtx
[3] );
492 vg_line_capsule( mtx
, w
->collider
.r
, w
->collider
.h
, VG__WHITE
);
497 float yaw
= localplayer
.angles
[0];
499 v3f forward_dir
= { -sinf(yaw
), 0.0f
, cosf(yaw
) };
500 v3f right_dir
= { forward_dir
[2], 0.0f
, -forward_dir
[0] };
503 * Collision detection
506 len
= rb_capsule__scene( mtx
, &w
->collider
, NULL
,
507 world
->geo_bh
, manifold
, 0 );
508 player_walk_custom_filter( world
, manifold
, len
, 0.01f
);
509 len
= rb_manifold_apply_filtered( manifold
, len
);
511 v3f surface_avg
= { 0.0f
, 0.0f
, 0.0f
};
513 w
->state
.activity
= k_walk_activity_air
;
514 w
->surface
= k_surface_prop_concrete
;
516 for( int i
=0; i
<len
; i
++ ){
517 rb_ct
*ct
= &manifold
[i
];
518 rb_debug_contact( ct
);
520 if( player_walk_normal_standable( ct
->n
) ){
521 w
->state
.activity
= k_walk_activity_ground
;
523 v3_add( surface_avg
, ct
->n
, surface_avg
);
525 struct world_surface
*surf
= world_contact_surface( world
, ct
);
526 if( surf
->info
.surface_prop
> w
->surface
)
527 w
->surface
= surf
->info
.surface_prop
;
530 rb_prepare_contact( ct
, vg
.time_fixed_delta
);
536 float accel_speed
= 0.0f
, nominal_speed
= 0.0f
;
539 v3_muls( right_dir
, w
->state
.steer
[0], movedir
);
540 v3_muladds( movedir
, forward_dir
, w
->state
.steer
[1], movedir
);
542 if( w
->state
.activity
== k_walk_activity_ground
){
543 v3_normalize( surface_avg
);
546 v3_tangent_basis( surface_avg
, tx
, ty
);
548 if( v2_length2(w
->state
.steer
) > 0.001f
){
549 /* clip movement to the surface */
550 float d
= v3_dot(surface_avg
,movedir
);
551 v3_muladds( movedir
, surface_avg
, -d
, movedir
);
554 accel_speed
= k_walk_accel
;
555 nominal_speed
= w
->state
.steer
[2];
558 if( w
->state
.jump_queued
){
559 w
->state
.jump_queued
= 0;
561 f32 t
= vg
.time
- w
->state
.jump_input_time
;
562 if( t
< PLAYER_JUMP_EPSILON
){
563 localplayer
.rb
.v
[1] = 5.0f
;
564 w
->state
.activity
= k_walk_activity_air
;
565 prev_state
= k_walk_activity_air
;
566 accel_speed
= k_walk_air_accel
;
567 nominal_speed
= k_airspeed
;
571 player_friction( localplayer
.rb
.v
, k_walk_friction
);
575 accel_speed
= k_walk_air_accel
;
576 nominal_speed
= k_airspeed
;
579 if( v2_length2( w
->state
.steer
) > 0.001f
){
580 player_accelerate( localplayer
.rb
.v
, movedir
,
581 nominal_speed
, accel_speed
);
582 v3_normalize( movedir
);
586 * Resolve velocity constraints
588 for( int j
=0; j
<5; j
++ ){
589 for( int i
=0; i
<len
; i
++ ){
590 rb_ct
*ct
= &manifold
[i
];
593 float vn
= -v3_dot( localplayer
.rb
.v
, ct
->n
);
595 float temp
= ct
->norm_impulse
;
596 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
597 vn
= ct
->norm_impulse
- temp
;
599 v3_muladds( localplayer
.rb
.v
, ct
->n
, vn
, localplayer
.rb
.v
);
604 if( w
->state
.activity
== k_walk_activity_ground
||
605 prev_state
== k_walk_activity_ground
){
606 float max_dist
= 0.4f
;
609 v3_copy( localplayer
.rb
.co
, pa
);
610 pa
[1] += w
->collider
.r
+ max_dist
;
611 v3_add( pa
, (v3f
){0, -max_dist
* 2.0f
, 0}, pb
);
612 vg_line( pa
, pb
, 0xff000000 );
616 if( spherecast_world( world
, pa
, pb
,
617 w
->collider
.r
, &t
, n
, 0 ) != -1 ){
618 if( player_walk_normal_standable(n
) ){
619 v3_lerp( pa
, pb
, t
, localplayer
.rb
.co
);
620 localplayer
.rb
.co
[1] += -w
->collider
.r
- k_penetration_slop
;
621 w
->state
.activity
= k_walk_activity_ground
;
623 float d
= -v3_dot(n
,localplayer
.rb
.v
);
624 v3_muladds( localplayer
.rb
.v
, n
, d
, localplayer
.rb
.v
);
625 localplayer
.rb
.v
[1] += -k_gravity
* vg
.time_fixed_delta
;
634 rb_depenetrate( manifold
, len
, dt
);
635 v3_add( dt
, localplayer
.rb
.co
, localplayer
.rb
.co
);
638 if( w
->state
.activity
== k_walk_activity_air
){
639 localplayer
.rb
.v
[1] += -k_gravity
*vg
.time_fixed_delta
;
642 if( localplayer
.immobile
){
643 localplayer
.rb
.v
[0] = 0.0f
;
644 localplayer
.rb
.v
[2] = 0.0f
;
647 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.v
, vg
.time_fixed_delta
,
649 v3_add( localplayer
.rb
.co
, (v3f
){0,1,0}, mtx
[3] );
650 vg_line_capsule( mtx
, w
->collider
.r
, w
->collider
.h
, VG__GREEN
);
654 * ---------------------------------------------------
659 lwr_offs
= { 0.0f
, w
->collider
.r
, 0.0f
};
661 v3_add( lwr_offs
, w
->state
.prev_pos
, lwr_prev
);
662 v3_add( lwr_offs
, localplayer
.rb
.co
, lwr_now
);
665 v3_sub( localplayer
.rb
.co
, w
->state
.prev_pos
, movedelta
);
667 float movedist
= v3_length( movedelta
);
669 if( movedist
> 0.3f
){
670 float t
, sr
= w
->collider
.r
-0.04f
;
673 if( spherecast_world( world
, lwr_prev
, lwr_now
, sr
, &t
, n
, 0 ) != -1 ){
674 v3_lerp( lwr_prev
, lwr_now
, vg_maxf(0.01f
,t
), localplayer
.rb
.co
);
675 localplayer
.rb
.co
[1] -= w
->collider
.r
;
676 rb_update_matrices( &localplayer
.rb
);
677 v3_add( localplayer
.rb
.co
, (v3f
){0,1,0}, mtx
[3] );
678 vg_line_capsule( mtx
, w
->collider
.r
, w
->collider
.h
, VG__RED
);
682 u32 id
= world_intersect_gates(world
, localplayer
.rb
.co
, w
->state
.prev_pos
);
684 ent_gate
*gate
= mdl_arritm( &world
->ent_gate
, mdl_entity_id_id(id
) );
685 m4x3_mulv( gate
->transport
, localplayer
.rb
.co
, localplayer
.rb
.co
);
686 m3x3_mulv( gate
->transport
, localplayer
.rb
.v
, localplayer
.rb
.v
);
688 v4f transport_rotation
;
689 m3x3_q( gate
->transport
, transport_rotation
);
690 q_mul( transport_rotation
, localplayer
.rb
.q
, localplayer
.rb
.q
);
691 q_normalize( localplayer
.rb
.q
);
692 rb_update_matrices( &localplayer
.rb
);
693 player__pass_gate( id
);
695 rb_update_matrices( &localplayer
.rb
);
697 if( (prev_state
== k_walk_activity_oregular
) ||
698 (prev_state
== k_walk_activity_oair
) ||
699 (prev_state
== k_walk_activity_ipopoff
) ){
700 w
->state
.activity
= prev_state
;
703 w
->move_speed
= vg_minf( v2_length( (v2f
){ localplayer
.rb
.v
[0],
704 localplayer
.rb
.v
[2] } ),
708 void player__walk_post_update(void){
709 struct player_walk
*w
= &player_walk
;
712 m3x3_copy( localplayer
.rb
.to_world
, mtx
);
713 v3_add( localplayer
.rb
.co
, (v3f
){0,1,0}, mtx
[3] );
715 float substep
= vg
.time_fixed_extrapolate
;
716 v3_muladds( mtx
[3], localplayer
.rb
.v
, vg
.time_fixed_delta
*substep
, mtx
[3] );
717 vg_line_capsule( mtx
, w
->collider
.r
, w
->collider
.h
, VG__YELOW
);
719 /* Calculate header */
721 if( (player_xyspeed2() > 0.1f
*0.1f
) ){
723 if( (w
->state
.activity
== k_walk_activity_ground
) ||
724 (w
->state
.activity
== k_walk_activity_ipopoff
) ||
725 (w
->state
.activity
== k_walk_activity_oregular
) ){
729 f32 ta
= atan2f( localplayer
.rb
.v
[0], localplayer
.rb
.v
[2] );
731 q_axis_angle( qt
, (v3f
){0,1,0}, ta
);
732 q_nlerp( localplayer
.rb
.q
, qt
, vg
.time_delta
/r
, localplayer
.rb
.q
);
735 vg_line_point( w
->state
.drop_in_target
, 0.1f
, VG__GREEN
);
737 v3_muladds( w
->state
.drop_in_target
, w
->state
.drop_in_normal
, 0.3f
, p1
);
738 vg_line( w
->state
.drop_in_target
, p1
, VG__GREEN
);
739 v3_muladds( w
->state
.drop_in_target
, localplayer
.rb
.to_world
[1], 0.3f
, p1
);
740 vg_line( w
->state
.drop_in_target
, p1
, VG__GREEN
);
742 float a
= player_get_heading_yaw();
747 v3_add( localplayer
.rb
.co
, p1
, p1
);
748 vg_line( localplayer
.rb
.co
, p1
, VG__PINK
);
751 if( vg_fractf(w
->state
.walk_timer
) > 0.5f
)
756 if( (w
->state
.step_phase
!= walk_phase
) &&
757 (w
->state
.activity
== k_walk_activity_ground
) )
760 if( w
->surface
== k_surface_prop_concrete
){
762 &audio_footsteps
[vg_randu32(&vg
.rand
) % 4],
763 localplayer
.rb
.co
, 40.0f
, 1.0f
766 else if( w
->surface
== k_surface_prop_grass
){
768 &audio_footsteps_grass
[ vg_randu32(&vg
.rand
) % 6 ],
769 localplayer
.rb
.co
, 40.0f
, 1.0f
772 else if( w
->surface
== k_surface_prop_wood
){
774 &audio_footsteps_wood
[ vg_randu32(&vg
.rand
) % 6 ],
775 localplayer
.rb
.co
, 40.0f
, 1.0f
781 w
->state
.step_phase
= walk_phase
;
784 void player__walk_update(void){
785 struct player_walk
*w
= &player_walk
;
787 if( (w
->state
.activity
== k_walk_activity_air
) ||
788 (w
->state
.activity
== k_walk_activity_ground
) ||
789 (w
->state
.activity
== k_walk_activity_oair
) ||
790 (w
->state
.activity
== k_walk_activity_oregular
) ||
791 (w
->state
.activity
== k_walk_activity_ipopoff
) ){
792 player_walk_update_generic();
796 static void player_walk_animate_drop_in(void){
797 struct player_walk
*w
= &player_walk
;
798 struct player_walk_animator
*animator
= &w
->animator
;
799 struct skeleton_anim
*anim
= w
->anim_drop_in
;
801 f32 length
= (f32
)(anim
->length
-1) / anim
->rate
,
802 time
= w
->state
.transition_t
;
804 f32 walk_yaw
= vg_alerpf( w
->state
.drop_in_start_angle
,
805 w
->state
.drop_in_angle
, animator
->transition_t
);
806 v3_lerp( w
->state
.drop_in_start
, w
->state
.drop_in_target
,
807 animator
->transition_t
, localplayer
.rb
.co
);
809 q_axis_angle( localplayer
.rb
.q
, (v3f
){0,1,0}, walk_yaw
+ VG_PIf
);
811 /* the drop in bit */
814 player_walk_drop_in_overhang_transform( animator
->transition_t
,
817 q_mul( final_q
, localplayer
.rb
.q
, localplayer
.rb
.q
);
818 v3_lerp( localplayer
.rb
.co
, final_co
, animator
->transition_t
,
821 rb_update_matrices( &localplayer
.rb
);
823 v3_muladds( localplayer
.rb
.co
, localplayer
.rb
.to_world
[1],
824 -0.1f
*animator
->transition_t
, localplayer
.rb
.co
);
826 v3_copy( localplayer
.rb
.co
, animator
->root_co
);
827 v4_copy( localplayer
.rb
.q
, animator
->root_q
);
829 /* for the camera purposes only */
831 player_walk_drop_in_vector( init_velocity
);
832 v3_muls( init_velocity
, animator
->transition_t
, localplayer
.rb
.v
);
833 v3_copy( localplayer
.rb
.v
,
834 localplayer
.cam_control
.cam_velocity_smooth
);
837 static void player_walk_animate_generic(void){
838 struct player_walk
*w
= &player_walk
;
839 struct player_walk_animator
*animator
= &w
->animator
;
842 rb_extrapolate( &localplayer
.rb
, animator
->root_co
, _null
);
844 f32 walk_yaw
= player_get_heading_yaw(),
845 head_yaw
= localplayer
.angles
[0] + VG_PIf
,
846 y
= vg_angle_diff( head_yaw
, -walk_yaw
),
847 p
= vg_clampf( localplayer
.angles
[1],
848 -k_sit_pitch_limit
, k_sit_pitch_limit
);
850 if( fabsf(y
) > k_sit_yaw_limit
){
855 animator
->yaw
= vg_lerpf( animator
->yaw
, y
, vg
.time_delta
*2.0f
);
856 animator
->pitch
= vg_lerpf( animator
->pitch
, p
, vg
.time_delta
*2.8f
);
857 q_axis_angle( animator
->root_q
, (v3f
){0,1,0}, walk_yaw
+ VG_PIf
);
860 q_axis_angle( qrev
, (v3f
){0,1,0}, VG_TAUf
*0.5f
);
861 q_mul( localplayer
.rb
.q
, qrev
, animator
->root_q
);
864 void player__walk_animate(void){
865 struct player_walk
*w
= &player_walk
;
866 player_pose
*pose
= &localplayer
.pose
;
867 struct player_walk_animator
*animator
= &w
->animator
;
869 animator
->activity
= w
->state
.activity
;
870 animator
->transition_t
= w
->state
.transition_t
;
873 f32 fly
= (w
->state
.activity
== k_walk_activity_air
)? 1.0f
: 0.0f
,
876 if( w
->state
.activity
== k_walk_activity_air
) rate
= 2.4f
;
879 animator
->fly
= vg_lerpf( animator
->fly
, fly
, rate
*vg
.time_delta
);
880 animator
->run
= vg_lerpf( animator
->run
, w
->move_speed
,
884 if( animator
->run
> 0.025f
){
885 f32 walk_norm
= 30.0f
/(float)w
->anim_walk
->length
,
886 run_norm
= 30.0f
/(float)w
->anim_run
->length
,
889 if( animator
->run
<= k_walkspeed
)
890 l
= (animator
->run
/ k_walkspeed
) * walk_norm
;
892 l
= vg_lerpf( walk_norm
, run_norm
,
893 (animator
->run
-k_walkspeed
) / (k_runspeed
-k_walkspeed
) );
895 w
->state
.walk_timer
+= l
* vg
.time_delta
;
898 w
->state
.walk_timer
= 0.0f
;
900 animator
->walk_timer
= w
->state
.walk_timer
;
902 player_walk_animate_generic();
903 if( w
->state
.activity
== k_walk_activity_odrop_in
){
904 player_walk_animate_drop_in();
907 if( (w
->state
.activity
== k_walk_activity_odrop_in
) ||
908 (w
->state
.activity
== k_walk_activity_oregular
) ||
909 (w
->state
.activity
== k_walk_activity_oair
) ){
910 localplayer
.cam_velocity_influence
= w
->animator
.transition_t
;
912 else if( w
->state
.activity
== k_walk_activity_ipopoff
){
913 localplayer
.cam_velocity_influence
= 1.0f
-w
->animator
.transition_t
;
916 localplayer
.cam_velocity_influence
= 0.0f
;
918 if( w
->state
.activity
== k_walk_activity_sit
){
919 localplayer
.cam_dist
= 3.8f
;
922 localplayer
.cam_dist
= 1.8f
;
926 static void player_walk_pose_sit( struct player_walk_animator
*animator
,
928 mdl_keyframe bpose
[32];
930 struct player_walk
*w
= &player_walk
;
931 struct skeleton
*sk
= &localplayer
.skeleton
;
933 f32 t
= animator
->transition_t
,
934 st
= t
* ((f32
)(w
->anim_sit
->length
-1)/30.0f
);
935 skeleton_sample_anim( sk
, w
->anim_sit
, st
, bpose
);
938 f32
*qh
= bpose
[localplayer
.id_head
-1].q
;
939 q_axis_angle( qy
, (v3f
){0,1,0}, animator
->yaw
*0.5f
*t
);
940 q_axis_angle( qp
, (v3f
){0,0,1}, animator
->pitch
*t
);
945 qh
= bpose
[localplayer
.id_chest
-1].q
;
946 q_axis_angle( qy
, (v3f
){0,1,0}, animator
->yaw
*0.5f
*t
);
950 skeleton_lerp_pose( sk
, pose
->keyframes
, bpose
,
951 vg_minf(1.0f
,t
*10.0f
), pose
->keyframes
);
954 enum walk_transition_type
{
955 k_walk_transition_in
,
956 k_walk_transition_out
,
957 k_walk_transition_outin
,
960 static void player_walk_pose_transition(
961 struct player_walk_animator
*animator
, struct skeleton_anim
*anim
,
962 enum walk_transition_type type
,
963 mdl_keyframe apose
[32], f32
*mask
, player_pose
*pose
){
965 mdl_keyframe bpose
[32];
967 struct player_walk
*w
= &player_walk
;
968 struct skeleton
*sk
= &localplayer
.skeleton
;
970 f32 length
= (f32
)(anim
->length
-1) / anim
->rate
,
971 t
= animator
->transition_t
* length
,
974 if( type
== k_walk_transition_in
|| type
== k_walk_transition_outin
)
975 blend
= vg_minf( blend
, length
-t
);
977 if( type
== k_walk_transition_out
|| type
== k_walk_transition_outin
)
978 blend
= vg_minf( blend
, t
);
980 blend
= vg_smoothstepf( vg_minf(1,blend
/k_anim_transition
) );
982 skeleton_sample_anim_clamped( sk
, anim
, t
, bpose
);
984 mdl_keyframe
*kf_board
= &bpose
[localplayer
.id_board
-1];
985 f32 yaw
= animator
->board_yaw
* VG_TAUf
* 0.5f
;
988 q_axis_angle( qyaw
, (v3f
){0,1,0}, yaw
);
989 q_mul( kf_board
->q
, qyaw
, kf_board
->q
);
990 q_normalize( kf_board
->q
);
993 for( i32 i
=0; i
<sk
->bone_count
-1; i
++ )
994 keyframe_lerp( apose
+i
, bpose
+i
, blend
*mask
[i
], pose
->keyframes
+i
);
997 skeleton_lerp_pose( sk
, apose
, bpose
, blend
, pose
->keyframes
);
1000 void player__walk_pose( void *_animator
, player_pose
*pose
){
1001 struct player_walk
*w
= &player_walk
;
1002 struct player_walk_animator
*animator
= _animator
;
1003 struct skeleton
*sk
= &localplayer
.skeleton
;
1005 v3_copy( animator
->root_co
, pose
->root_co
);
1006 v4_copy( animator
->root_q
, pose
->root_q
);
1007 pose
->board
.lean
= 0.0f
;
1008 pose
->type
= k_player_pose_type_ik
;
1010 float walk_norm
= (float)w
->anim_walk
->length
/30.0f
,
1011 run_norm
= (float)w
->anim_run
->length
/30.0f
,
1012 t
= animator
->walk_timer
;
1015 mdl_keyframe apose
[32], bpose
[32];
1016 if( animator
->run
<= k_walkspeed
){
1018 f32 l
= vg_minf( 1, (animator
->run
/k_walkspeed
)*6.0f
);
1019 skeleton_sample_anim( sk
, w
->anim_idle
, vg
.time
*0.1f
, apose
);
1020 skeleton_sample_anim( sk
, w
->anim_walk
, t
*walk_norm
, bpose
);
1021 skeleton_lerp_pose( sk
, apose
, bpose
, l
, apose
);
1025 f32 l
= (animator
->run
-k_walkspeed
) / (k_runspeed
-k_walkspeed
);
1026 skeleton_sample_anim( sk
, w
->anim_walk
, t
*walk_norm
, apose
);
1027 skeleton_sample_anim( sk
, w
->anim_run
, t
*run_norm
, bpose
);
1028 skeleton_lerp_pose( sk
, apose
, bpose
, l
, apose
);
1032 skeleton_sample_anim( sk
, w
->anim_jump
, vg
.time
*0.6f
, bpose
);
1033 skeleton_lerp_pose( sk
, apose
, bpose
, animator
->fly
, apose
);
1035 mdl_keyframe
*kf_board
= &apose
[localplayer
.id_board
-1];
1036 f32 yaw
= animator
->board_yaw
;
1038 if( animator
->activity
== k_walk_activity_ipopoff
)
1039 if( animator
->transition_t
> 0.5f
)
1043 q_axis_angle( qyaw
, (v3f
){0,1,0}, yaw
* VG_TAUf
* 0.5f
);
1044 q_mul( kf_board
->q
, qyaw
, kf_board
->q
);
1045 q_normalize( kf_board
->q
);
1048 if( (animator
->activity
== k_walk_activity_sit
) ||
1049 (animator
->activity
== k_walk_activity_sit_up
) ){
1050 player_walk_pose_sit( animator
, pose
);
1052 else if( animator
->activity
== k_walk_activity_odrop_in
){
1053 player_walk_pose_transition(
1054 animator
, w
->anim_drop_in
, k_walk_transition_out
, apose
,
1057 else if( animator
->activity
== k_walk_activity_oair
){
1058 player_walk_pose_transition(
1059 animator
, w
->anim_jump_to_air
, k_walk_transition_out
, apose
,
1062 else if( animator
->activity
== k_walk_activity_oregular
){
1063 player_walk_pose_transition(
1064 animator
, w
->anim_intro
, k_walk_transition_out
, apose
,
1067 else if( animator
->activity
== k_walk_activity_ipopoff
){
1068 if( animator
->run
> 0.2f
){
1069 f32 t
= 1.0f
-vg_minf( animator
->run
-0.2f
, 1.0f
),
1072 for( u32 i
=0; i
<32; i
++ )
1075 mask
[ localplayer
.id_ik_foot_l
-1 ] = t
;
1076 mask
[ localplayer
.id_ik_foot_r
-1 ] = t
;
1077 mask
[ localplayer
.id_ik_knee_l
-1 ] = t
;
1078 mask
[ localplayer
.id_ik_knee_r
-1 ] = t
;
1079 mask
[ localplayer
.id_hip
-1 ] = t
;
1080 player_walk_pose_transition(
1081 animator
, w
->anim_popoff
, k_walk_transition_in
, apose
,
1085 player_walk_pose_transition(
1086 animator
, w
->anim_popoff
, k_walk_transition_in
, apose
,
1091 skeleton_copy_pose( sk
, apose
, pose
->keyframes
);
1095 void player__walk_post_animate(void){
1099 struct player_walk
*w
= &player_walk
;
1103 void player__walk_im_gui(void){
1104 struct player_walk
*w
= &player_walk
;
1105 player__debugtext( 1, "V: %5.2f %5.2f %5.2f (%5.2fm/s)",
1106 localplayer
.rb
.v
[0], localplayer
.rb
.v
[1], localplayer
.rb
.v
[2],
1107 v3_length(localplayer
.rb
.v
) );
1108 player__debugtext( 1, "CO: %5.2f %5.2f %5.2f",localplayer
.rb
.co
[0],
1109 localplayer
.rb
.co
[1],
1110 localplayer
.rb
.co
[2] );
1111 player__debugtext( 1, "transition: %5.2f ", w
->state
.transition_t
);
1112 player__debugtext( 1, "activity: %s\n",
1113 (const char *[]){ "air",
1122 [w
->state
.activity
] );
1123 player__debugtext( 1, "surface: %s\n",
1124 (const char *[]){ "concrete",
1134 void player__walk_bind(void){
1135 struct player_walk
*w
= &player_walk
;
1136 struct skeleton
*sk
= &localplayer
.skeleton
;
1138 w
->anim_idle
= skeleton_get_anim( sk
, "idle_cycle+y" );
1139 w
->anim_walk
= skeleton_get_anim( sk
, "walk+y" );
1140 w
->anim_run
= skeleton_get_anim( sk
, "run+y" );
1141 w
->anim_jump
= skeleton_get_anim( sk
, "jump+y" );
1142 w
->anim_jump_to_air
= skeleton_get_anim( sk
, "jump_to_air" );
1143 w
->anim_drop_in
= skeleton_get_anim( sk
, "drop_in" );
1144 w
->anim_intro
= skeleton_get_anim( sk
, "into_skate" );
1145 w
->anim_sit
= skeleton_get_anim( sk
, "sit" );
1146 w
->anim_popoff
= skeleton_get_anim( sk
, "pop_off_short" );
1149 void player__walk_transition( bool grounded
, f32 board_yaw
){
1150 struct player_walk
*w
= &player_walk
;
1151 w
->state
.activity
= k_walk_activity_air
;
1154 w
->state
.activity
= k_walk_activity_ipopoff
;
1157 w
->state
.transition_t
= 0.0f
;
1158 w
->state
.jump_queued
= 0;
1159 w
->state
.jump_input_time
= 0.0;
1160 w
->state
.walk_timer
= 0.0f
;
1161 w
->state
.step_phase
= 0;
1162 w
->animator
.board_yaw
= fmodf( board_yaw
, 2.0f
);
1163 rb_update_matrices( &localplayer
.rb
);
1166 void player__walk_reset(void)
1168 struct player_walk
*w
= &player_walk
;
1169 w
->state
.activity
= k_walk_activity_air
;
1170 w
->state
.transition_t
= 0.0f
;
1172 v3f fwd
= { 0.0f
, 0.0f
, 1.0f
};
1173 q_mulv( localplayer
.rb
.q
, fwd
, fwd
);
1174 q_axis_angle( localplayer
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
},
1175 atan2f(fwd
[0], fwd
[2]) );
1177 rb_update_matrices( &localplayer
.rb
);
1180 void player__walk_animator_exchange( bitpack_ctx
*ctx
, void *data
){
1181 struct player_walk_animator
*animator
= data
;
1183 bitpack_qv3f( ctx
, 24, -1024.0f
, 1024.0f
, animator
->root_co
);
1184 bitpack_qquat( ctx
, animator
->root_q
);
1185 bitpack_qf32( ctx
, 8, 0.0f
, 1.0f
, &animator
->fly
);
1186 bitpack_qf32( ctx
, 8, 0.0f
, k_runspeed
, &animator
->run
);
1187 bitpack_qf32( ctx
, 16, 0.0f
, 120.0f
, &animator
->walk_timer
);
1189 for( int i
=0; i
<1; i
++ ){ /* without this you get a warning from gcc. lol */
1190 bitpack_bytes( ctx
, 8, &animator
->activity
);
1193 bitpack_qf32( ctx
, 8, 0.0f
, 1.0f
, &animator
->transition_t
);
1195 if( (animator
->activity
== k_walk_activity_sit
) ||
1196 (animator
->activity
== k_walk_activity_sit_up
) ){
1197 bitpack_qf32( ctx
, 8, -k_sit_yaw_limit
, k_sit_yaw_limit
, &animator
->yaw
);
1198 bitpack_qf32( ctx
, 8, -k_sit_pitch_limit
, k_sit_pitch_limit
,
1202 bitpack_qf32( ctx
, 16, -100.0f
, 100.0f
, &animator
->board_yaw
);
1205 void player__walk_sfx_oneshot( u8 id
, v3f pos
, f32 volume
){
1208 if( id
== k_player_walk_soundeffect_splash
){
1209 audio_oneshot_3d( &audio_splash
, pos
, 40.0f
, 1.0f
);