1 #ifndef PLAYER_DEVICE_WALK_H
2 #define PLAYER_DEVICE_WALK_H
4 #include "player_interface.h"
5 #include "player_device_common.h"
7 #include "player_model.h"
10 struct player_device_walk
22 k_walk_activity_ground
,
30 enum mdl_surface_prop surface
;
31 struct skeleton_anim
*anim_walk
, *anim_run
, *anim_idle
, *anim_jump
;
42 localplayer_device_walk
;
44 VG_STATIC
void player_walk_pre_update( player_device
*dev
,
45 player_interface
*player
)
47 struct player_device_walk
*w
= dev
->storage
;
48 player_look( player
, w
->state
.angles
);
50 if( vg_input_button_down( player
->input_use
) )
52 struct device_transition_skateboard inf
;
55 v3_copy( player
->rb
.v
, xy_speed
);
58 if( v3_length2( xy_speed
) > 0.1f
* 0.1f
)
60 v3_copy( player
->rb
.v
, inf
.dir
);
64 inf
.dir
[0] = -sinf( -w
->state
.angles
[0] );
66 inf
.dir
[2] = -cosf( -w
->state
.angles
[0] );
67 v3_muls( inf
.dir
, 1.6f
, player
->rb
.v
);
70 player_transition_to_device( player
, w
->device_id_skate
, &inf
);
75 v3f walk
= { player
->input_walkh
->axis
.value
,
77 -player
->input_walkv
->axis
.value
};
79 v3_muls( walk
, 10.0f
* vg
.time_delta
, walk
);
82 euler_m3x3( w
->angles
, m
);
83 v3_muladds( player
->rb
.co
, m
[0], walk
[0], player
->rb
.co
);
84 v3_muladds( player
->rb
.co
, m
[1], walk
[1], player
->rb
.co
);
85 v3_muladds( player
->rb
.co
, m
[2], walk
[2], player
->rb
.co
);
89 VG_STATIC
int player_walk_normal_standable( v3f n
)
91 return n
[1] > 0.70710678118f
;
94 VG_STATIC
void player_accelerate( v3f v
, v3f movedir
, float speed
, float accel
)
96 float currentspeed
= v3_dot( v
, movedir
),
97 addspeed
= speed
- currentspeed
;
102 float accelspeed
= accel
* k_rb_delta
* speed
;
104 if( accelspeed
> addspeed
)
105 accelspeed
= addspeed
;
107 v3_muladds( v
, movedir
, accelspeed
, v
);
110 VG_STATIC
void player_friction( v3f v
)
112 float speed
= v3_length( v
),
114 control
= vg_maxf( speed
, k_stopspeed
);
119 drop
+= control
* k_walk_friction
* k_rb_delta
;
121 float newspeed
= vg_maxf( 0.0f
, speed
- drop
);
124 v3_muls( v
, newspeed
, v
);
127 VG_STATIC
void player_walk_update( player_device
*dev
,
128 player_interface
*player
)
130 struct player_device_walk
*w
= dev
->storage
;
131 v3_copy( player
->rb
.co
, w
->state
.prev_pos
);
133 w
->collider
.height
= 2.0f
;
134 w
->collider
.radius
= 0.3f
;
137 m3x3_identity( mtx
);
138 v3_add( player
->rb
.co
, (v3f
){0.0f
, 1.0f
, 0.0f
}, mtx
[3] );
140 debug_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__WHITE
);
145 float yaw
= w
->state
.angles
[0];
147 v3f forward_dir
= { sinf(yaw
), 0.0f
, -cosf(yaw
) };
148 v3f right_dir
= { -forward_dir
[2], 0.0f
, forward_dir
[0] };
150 v2f walk
= { player
->input_walkh
->axis
.value
,
151 player
->input_walkv
->axis
.value
};
153 if( v2_length2(walk
) > 0.001f
)
154 v2_normalize_clamp( walk
);
156 w
->move_speed
= v2_length( walk
);
159 * Collision detection
161 len
= rb_capsule__scene( mtx
, &w
->collider
, NULL
,
162 &world
.rb_geo
.inf
.scene
, manifold
);
163 rb_manifold_filter_coplanar( manifold
, len
, 0.01f
);
164 len
= rb_manifold_apply_filtered( manifold
, len
);
166 v3f surface_avg
= { 0.0f
, 0.0f
, 0.0f
};
167 w
->state
.activity
= k_walk_activity_air
;
169 for( int i
=0; i
<len
; i
++ )
171 struct contact
*ct
= &manifold
[i
];
172 rb_debug_contact( ct
);
174 if( player_walk_normal_standable( ct
->n
) )
176 w
->state
.activity
= k_walk_activity_ground
;
177 v3_add( surface_avg
, ct
->n
, surface_avg
);
180 rb_prepare_contact( ct
);
187 float accel_speed
= 0.0f
, nominal_speed
= 0.0f
;
189 v3_muls( right_dir
, walk
[0], movedir
);
190 v3_muladds( movedir
, forward_dir
, walk
[1], movedir
);
192 if( w
->state
.activity
== k_walk_activity_ground
)
194 v3_normalize( surface_avg
);
197 rb_tangent_basis( surface_avg
, tx
, ty
);
199 if( v2_length2(walk
) > 0.001f
)
201 /* clip movement to the surface */
202 float d
= v3_dot(surface_avg
,movedir
);
203 v3_muladds( movedir
, surface_avg
, -d
, movedir
);
206 accel_speed
= k_walk_accel
;
207 nominal_speed
= k_walkspeed
;
210 if( player
->input_jump
->button
.value
)
212 player
->rb
.v
[1] = 5.0f
;
213 w
->state
.activity
= k_walk_activity_air
;
214 accel_speed
= k_walk_air_accel
;
215 nominal_speed
= k_airspeed
;
219 player_friction( player
->rb
.v
);
221 struct world_material
*surface_mat
= world_contact_material(manifold
);
222 w
->surface
= surface_mat
->info
.surface_prop
;
227 accel_speed
= k_walk_air_accel
;
228 nominal_speed
= k_airspeed
;
231 if( v2_length2(walk
) > 0.001f
)
233 player_accelerate( player
->rb
.v
, movedir
, nominal_speed
, accel_speed
);
234 v3_normalize( movedir
);
238 * Resolve velocity constraints
240 for( int j
=0; j
<5; j
++ )
242 for( int i
=0; i
<len
; i
++ )
244 struct contact
*ct
= &manifold
[i
];
247 float vn
= -v3_dot( player
->rb
.v
, ct
->n
);
249 float temp
= ct
->norm_impulse
;
250 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
251 vn
= ct
->norm_impulse
- temp
;
253 v3_muladds( player
->rb
.v
, ct
->n
, vn
, player
->rb
.v
);
262 for( int j
=0; j
<8; j
++ )
264 for( int i
=0; i
<len
; i
++ )
266 struct contact
*ct
= &manifold
[i
];
268 float resolved_amt
= v3_dot( ct
->n
, dt
),
269 remaining
= (ct
->p
-k_penetration_slop
) - resolved_amt
,
270 apply
= vg_maxf( remaining
, 0.0f
) * 0.3f
;
272 v3_muladds( dt
, ct
->n
, apply
, dt
);
275 v3_add( dt
, player
->rb
.co
, player
->rb
.co
);
277 /* TODO: Stepping......
279 * ideas; walkgrid style steps
282 if( w
->state
.activity
== k_walk_activity_ground
)
285 float max_dist
= 0.4f
;
288 v3_copy( player
->rb
.co
, pa
);
289 pa
[1] += w
->collider
.radius
+ max_dist
;
291 v3_muladds( pa
, (v3f
){0.0f
,1.0f
,0.0f
}, -max_dist
* 2.0f
, pb
);
292 vg_line( pa
, pb
, 0xff000000 );
296 if( spherecast_world( pa
, pb
, w
->collider
.radius
, &t
, n
) != -1 )
298 if( player_walk_normal_standable( n
) )
300 v3_lerp( pa
, pb
, t
, player
->rb
.co
);
301 player
->rb
.co
[1] -= w
->collider
.radius
;
309 if( w
->state
.activity
== k_walk_activity_air
)
310 player
->rb
.v
[1] += -k_gravity
* k_rb_delta
;
312 v3_muladds( player
->rb
.co
, player
->rb
.v
, k_rb_delta
, player
->rb
.co
);
315 v3_add( player
->rb
.co
, (v3f
){0.0f
, 1.0f
, 0.0f
}, mtx
[3] );
316 debug_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__GREEN
);
320 * ---------------------------------------------------
325 lwr_offs
= { 0.0f
, w
->collider
.radius
, 0.0f
};
327 v3_add( lwr_offs
, w
->state
.prev_pos
, lwr_prev
);
328 v3_add( lwr_offs
, player
->rb
.co
, lwr_now
);
331 v3_sub( player
->rb
.co
, w
->state
.prev_pos
, movedelta
);
333 float movedist
= v3_length( movedelta
);
335 if( movedist
> 0.3f
)
337 float t
, sr
= w
->collider
.radius
-0.04f
;
340 if( spherecast_world( lwr_prev
, lwr_now
, sr
, &t
, n
) != -1 )
342 v3_lerp( lwr_prev
, lwr_now
, vg_maxf(0.01f
,t
), player
->rb
.co
);
343 player
->rb
.co
[1] -= w
->collider
.radius
;
344 rb_update_transform( &player
->rb
);
346 v3_add( player
->rb
.co
, (v3f
){0.0f
, 1.0f
, 0.0f
}, mtx
[3] );
347 debug_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__RED
);
352 if( (gate
= world_intersect_gates( player
->rb
.co
, w
->state
.prev_pos
)) )
354 struct player_device_walk
*w
= dev
->storage
;
356 m4x3_mulv( gate
->transport
, player
->rb
.co
, player
->rb
.co
);
357 m3x3_mulv( gate
->transport
, player
->rb
.v
, player
->rb
.v
);
358 rb_update_transform( &player
->rb
);
360 /* analytical rotation of yaw */
361 v3f fwd_dir
= { cosf(w
->state
.angles
[0]),
363 sinf(w
->state
.angles
[0])};
364 m3x3_mulv( gate
->transport
, fwd_dir
, fwd_dir
);
365 w
->state
.angles
[0] = atan2f( fwd_dir
[2], fwd_dir
[0] );
367 w
->state_gate_storage
= w
->state
;
368 player_pass_gate( player
, gate
);
372 VG_STATIC
void player_walk_post_update( player_device
*dev
,
373 player_interface
*player
)
375 struct player_device_walk
*w
= dev
->storage
;
378 m3x3_identity( mtx
);
379 v3_add( player
->rb
.co
, (v3f
){0.0f
, 1.0f
, 0.0f
}, mtx
[3] );
381 float substep
= vg_clampf( vg
.accumulator
/ k_rb_delta
, 0.0f
, 1.0f
);
382 v3_muladds( mtx
[3], player
->rb
.v
, k_rb_delta
*substep
, mtx
[3] );
383 debug_capsule( mtx
, w
->collider
.radius
, w
->collider
.height
, VG__YELOW
);
386 player_apply_transport_to_cam( gate
->transport
);
391 VG_STATIC
void player_walk_animate( player_device
*dev
,
392 player_interface
*player
)
394 struct player_device_walk
*w
= dev
->storage
;
395 struct skeleton
*sk
= &player
->playeravatar
->sk
;
398 float fly
= (w
->state
.activity
== k_walk_activity_air
)? 1.0f
: 0.0f
,
401 if( w
->state
.activity
== k_walk_activity_air
)
406 w
->blend_fly
= vg_lerpf( w
->blend_fly
, fly
, rate
*vg
.time_delta
);
407 w
->blend_run
= vg_lerpf( w
->blend_run
,
409 (1.0f
+ player
->input_walk
->button
.value
*0.5f
),
410 2.0f
*vg
.time_delta
);
413 player_pose apose
, bpose
;
415 if( w
->move_speed
> 0.025f
)
418 float walk_norm
= 30.0f
/(float)w
->anim_walk
->length
,
419 run_norm
= 30.0f
/(float)w
->anim_run
->length
,
420 walk_adv
= vg_lerpf( walk_norm
, run_norm
, w
->move_speed
);
422 w
->walk_timer
+= walk_adv
* vg
.time_delta
;
426 w
->walk_timer
= 0.0f
;
429 float walk_norm
= (float)w
->anim_walk
->length
/30.0f
,
430 run_norm
= (float)w
->anim_run
->length
/30.0f
,
432 l
= vg_clampf( w
->blend_run
*15.0f
, 0.0f
, 1.0f
),
433 idle_walk
= vg_clampf( (w
->blend_run
-0.1f
)/(1.0f
-0.1f
), 0.0f
, 1.0f
);
436 skeleton_sample_anim( sk
, w
->anim_walk
, t
*walk_norm
, apose
);
437 skeleton_sample_anim( sk
, w
->anim_run
, t
*run_norm
, bpose
);
439 skeleton_lerp_pose( sk
, apose
, bpose
, l
, apose
);
442 skeleton_sample_anim( sk
, w
->anim_idle
, vg
.time
*0.1f
, bpose
);
443 skeleton_lerp_pose( sk
, apose
, bpose
, 1.0f
-idle_walk
, apose
);
446 skeleton_sample_anim( sk
, w
->anim_jump
, vg
.time
*0.6f
, bpose
);
447 skeleton_lerp_pose( sk
, apose
, bpose
, w
->blend_fly
, dev
->pose
);
449 /* Create transform */
450 rb_extrapolate( &player
->rb
, dev
->pose_root_co
, dev
->pose_root_q
);
451 q_axis_angle( dev
->pose_root_q
, (v3f
){0.0f
,1.0f
,0.0f
},
452 -w
->state
.angles
[0]-VG_PIf
*0.5f
);
455 VG_STATIC
void player_walk_post_animate( player_device
*dev
,
456 player_interface
*player
)
461 struct player_device_walk
*w
= dev
->storage
;
462 struct player_avatar
*av
= player
->playeravatar
;
466 euler_m3x3( w
->state
.angles
, angles
);
468 v3f cast_dir
, origin
;
470 v3_add( player
->rb
.co
, (v3f
){0.0f
,2.0f
,0.0f
}, origin
);
472 v3_muladds( origin
, angles
[2], 2.0f
, dev
->cam_3rd
.pos
);
473 v3_muladds( dev
->cam_3rd
.pos
, angles
[0], 0.5f
, dev
->cam_3rd
.pos
);
477 if( spherecast_world( origin
, dev
->cam_3rd
.pos
, 0.1f
, &t
, n
) != -1 )
478 v3_lerp( origin
, dev
->cam_3rd
.pos
, t
, dev
->cam_3rd
.pos
);
479 v3_copy( w
->state
.angles
, dev
->cam_3rd
.angles
);
480 dev
->cam_3rd
.fov
= 90.0f
;
484 /* FIXME: viewpoint entity */
485 v3f vp
= {-0.1f
,1.8f
,0.0f
};
486 m4x3_mulv( av
->sk
.final_mtx
[ av
->id_head
-1 ], vp
, dev
->cam_1st
.pos
);
487 v3_copy( w
->state
.angles
, dev
->cam_1st
.angles
);
488 dev
->cam_1st
.fov
= 90.0f
;
490 /* FIXME: Organize this. Its int wrong fucking place */
491 v3f vp0
= {0.0f
,0.1f
, 0.6f
},
492 vp1
= {0.0f
,0.1f
,-0.6f
};
494 m4x3_mulv( av
->sk
.final_mtx
[ av
->id_board
], vp0
, TEMP_BOARD_0
);
495 m4x3_mulv( av
->sk
.final_mtx
[ av
->id_board
], vp1
, TEMP_BOARD_1
);
499 VG_STATIC
void player_walk_ui( player_device
*dev
, player_interface
*player
)
501 player_debugtext( 1, "V: %5.2f %5.2f %5.2f",player
->rb
.v
[0],
504 player_debugtext( 1, "CO: %5.2f %5.2f %5.2f",player
->rb
.co
[0],
509 VG_STATIC
void player_walk_bind( player_device
*dev
, player_interface
*player
)
511 struct player_device_walk
*w
= dev
->storage
;
512 struct player_avatar
*av
= player
->playeravatar
;
513 struct skeleton
*sk
= &av
->sk
;
515 w
->anim_idle
= skeleton_get_anim( sk
, "idle_cycle" );
516 w
->anim_walk
= skeleton_get_anim( sk
, "walk" );
517 w
->anim_run
= skeleton_get_anim( sk
, "run" );
518 w
->anim_jump
= skeleton_get_anim( sk
, "jump" );
520 w
->device_id_skate
= player_get_device( player
, "skateboard" );
523 VG_STATIC
int player_walk_event( player_device
*dev
, player_interface
*player
,
524 enum player_device_event_type ev
, void *data
)
526 struct player_device_walk
*w
= dev
->storage
;
528 if( ev
== k_player_device_event_bind
)
530 player_walk_bind( dev
, player
);
532 else if( ev
== k_player_device_event_custom_transition
)
534 struct device_transition_walk
*inf
= data
;
535 v3_copy( inf
->angles
, w
->state
.angles
);
537 else if( ev
== k_player_device_event_pre_update
)
539 player_walk_pre_update( dev
, player
);
541 else if( ev
== k_player_device_event_update
)
543 player_walk_update( dev
, player
);
545 else if( ev
== k_player_device_event_post_update
)
547 player_walk_post_update( dev
, player
);
549 else if( ev
== k_player_device_event_animate
)
551 player_walk_animate( dev
, player
);
553 else if( ev
== k_player_device_event_post_animate
)
555 player_walk_post_animate( dev
, player
);
557 else if( ev
== k_player_device_event_debug_ui
)
559 player_walk_ui( dev
, player
);
567 VG_STATIC player_device player_device_walk
=
570 .event
= player_walk_event
,
571 .storage
= &localplayer_device_walk
574 #endif /* PLAYER_DEVICE_WALK_H */