2 * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
5 #define PLAYER_PHYSICS_WALK_H
6 #ifndef PLAYER_PHYSICS_WALK_H
7 #define PLAYER_PHYSICS_WALK_H
12 VG_STATIC
struct player_walk
16 enum walk_activityaaaaaa
18 k_walk_activity_airaaaa
,
19 k_walk_activity_groundaaaaaa
25 rigidbody capsule
; /* TODO: rigidbody::collider_capsule */
29 .capsule
= { .inf
.capsule
.height
= 2.0f
, .inf
.capsule
.radius
= 0.3f
}
32 VG_STATIC
void player_walk_collider_configuration(void)
34 v3_add( player
.rb
.co
, (v3f
){0.0f
,1.0f
,0.0f
}, player_walky
.capsule
.co
);
35 rb_update_transform( &player_walky
.capsule
);
41 rigidbody
*rbf
= &player
.collide_front
,
42 *rbb
= &player
.collide_back
;
44 v3_add( phys
->rb
.co
, (v3f
){0.0f
,h0
,0.0f
}, rbf
->co
);
45 v3_add( phys
->rb
.co
, (v3f
){0.0f
,h1
,0.0f
}, rbb
->co
);
46 v3_copy( rbf
->co
, rbf
->to_world
[3] );
47 v3_copy( rbb
->co
, rbb
->to_world
[3] );
48 m4x3_invert_affine( rbf
->to_world
, rbf
->to_local
);
49 m4x3_invert_affine( rbb
->to_world
, rbb
->to_local
);
51 rb_update_bounds( rbf
);
52 rb_update_bounds( rbb
);
56 __attribute__ ((deprecated
))
57 VG_STATIC
int player_walk_surface_standable( v3f n
)
59 return v3_dot( n
, (v3f
){0.0f
,1.0f
,0.0f
} ) > 0.5f
;
62 __attribute__ ((deprecated
))
63 VG_STATIC
void player_walk_stepdown( struct player_walk
*w
)
65 float max_dist
= 0.4f
;
68 v3_copy( player
.rb
.co
, pa
);
71 v3_muladds( pa
, (v3f
){0.01f
,1.0f
,0.01f
}, -max_dist
, pb
);
72 vg_line( pa
, pb
, 0xff000000 );
74 /* TODO: Make #define */
79 if( spherecast_world( pa
, pb
, r
, &t
, n
) != -1 )
81 if( player_walk_surface_standable( n
) )
83 w
->state
.activity
= k_walk_activity_ground
;
84 v3_lerp( pa
, pb
, t
+0.001f
, player
.rb
.co
);
85 player
.rb
.co
[1] -= 0.3f
;
90 __attribute__ ((deprecated
))
91 VG_STATIC
void player_walk_physics( struct player_walk
*w
)
93 v3_zero( player
.rb
.w
);
94 q_axis_angle( player
.rb
.q
, (v3f
){0.0f
,1.0f
,0.0f
}, -player
.angles
[0] );
99 v3f forward_dir
= { sinf(player
.angles
[0]),0.0f
,-cosf(player
.angles
[0]) };
100 v3f right_dir
= { -forward_dir
[2], 0.0f
, forward_dir
[0] };
102 v2f walk
= { player
.input_walkh
->axis
.value
,
103 player
.input_walkv
->axis
.value
};
108 if( v2_length2(walk
) > 0.001f
)
109 v2_normalize_clamp( walk
);
111 if( w
->state
.activity
== k_walk_activity_air
)
113 player_walk_collider_configuration();
115 /* allow player to accelerate a bit */
117 v3_muls( forward_dir
, walk
[1], walk_3d
);
118 v3_muladds( walk_3d
, right_dir
, walk
[0], walk_3d
);
120 float current_vel
= fabsf(v3_dot( walk_3d
, player
.rb
.v
)),
121 new_vel
= current_vel
+ VG_TIMESTEP_FIXED
*999999.0f
,
122 clamped_new
= vg_clampf( new_vel
, 0.0f
, k_walkspeed
),
123 vel_diff
= vg_maxf( 0.0f
, clamped_new
- current_vel
);
125 v3_muladds( player
.rb
.v
, right_dir
, walk
[0] * vel_diff
, player
.rb
.v
);
126 v3_muladds( player
.rb
.v
, forward_dir
, walk
[1] * vel_diff
, player
.rb
.v
);
128 len
= rb_capsule_scene( &w
->capsule
, &world
.rb_geo
, manifold
);
129 rb_presolve_contacts( manifold
, len
);
131 for( int i
=0; i
<len
; i
++ )
133 struct contact
*ct
= &manifold
[i
];
134 if( v3_dot( ct
->n
, (v3f
){0.0f
,1.0f
,0.0f
} ) > 0.5f
)
135 w
->state
.activity
= k_walk_activity_ground
;
141 for( int j
=0; j
<5; j
++ )
143 for( int i
=0; i
<len
; i
++ )
145 struct contact
*ct
= &manifold
[i
];
148 float vn
= -v3_dot( player
.rb
.v
, ct
->n
);
151 float temp
= ct
->norm_impulse
;
152 ct
->norm_impulse
= vg_maxf( temp
+ vn
, 0.0f
);
153 vn
= ct
->norm_impulse
- temp
;
156 v3_muls( ct
->n
, vn
, impulse
);
158 v3_add( impulse
, player
.rb
.v
, player
.rb
.v
);
161 for( int j
=0; j
<2; j
++ )
163 float f
= k_friction
* ct
->norm_impulse
,
164 vt
= v3_dot( player
.rb
.v
, ct
->t
[j
] ),
167 float temp
= ct
->tangent_impulse
[j
];
168 ct
->tangent_impulse
[j
] = vg_clampf( temp
+ lambda
, -f
, f
);
169 lambda
= ct
->tangent_impulse
[j
] - temp
;
171 v3_muladds( player
.rb
.v
, ct
->t
[j
], lambda
, player
.rb
.v
);
176 player
.rb
.v
[1] += -k_gravity
* k_rb_delta
;
177 v3_muladds( player
.rb
.co
, player
.rb
.v
, k_rb_delta
, player
.rb
.co
);
181 player
.walk
= v2_length( walk
);
183 if( player
.input_walk
->button
.value
)
184 v2_muls( walk
, 0.5f
, walk
);
186 v2_muls( walk
, k_walkspeed
* VG_TIMESTEP_FIXED
, walk
);
188 /* Do XY translation */
189 v3f walk_apply
, walk_measured
;
190 v3_zero( walk_apply
);
191 v3_muladds( walk_apply
, right_dir
, walk
[0], walk_apply
);
192 v3_muladds( walk_apply
, forward_dir
, walk
[1], walk_apply
);
193 v3_add( walk_apply
, player
.rb
.co
, player
.rb
.co
);
195 /* Directly resolve collisions */
196 player_walk_collider_configuration();
197 len
= rb_capsule_scene( &w
->capsule
, &world
.rb_geo
, manifold
);
201 for( int j
=0; j
<8; j
++ )
203 for( int i
=0; i
<len
; i
++ )
205 struct contact
*ct
= &manifold
[i
];
207 float resolved_amt
= v3_dot( ct
->n
, dt
),
208 remaining
= (ct
->p
-k_penetration_slop
) - resolved_amt
,
209 apply
= vg_maxf( remaining
, 0.0f
) * 0.3f
;
211 v3_muladds( dt
, ct
->n
, apply
, dt
);
214 v3_add( dt
, player
.rb
.co
, player
.rb
.co
);
216 v3_add( dt
, walk_apply
, walk_measured
);
217 v3_divs( walk_measured
, VG_TIMESTEP_FIXED
, player
.rb
.v
);
221 struct world_material
*surface_mat
= world_contact_material(manifold
);
222 player
.surface_prop
= surface_mat
->info
.surface_prop
;
225 w
->state
.activity
= k_walk_activity_air
;
228 if( player
.input_jump
->button
.value
)
230 player
.rb
.v
[1] = 5.0f
;
234 /* Check if grounded by current manifold */
235 for( int i
=0; i
<len
; i
++ )
237 struct contact
*ct
= &manifold
[i
];
238 if( player_walk_surface_standable( ct
->n
) )
239 w
->state
.activity
= k_walk_activity_ground
;
243 if( w
->state
.activity
== k_walk_activity_air
)
244 player_walk_stepdown( w
);
248 __attribute__ ((deprecated
))
249 VG_STATIC
void player_walk_animate( void *_w
,
250 struct skeleton
*sk
, player_pose pose
)
252 struct player_walk
*w
= _w
;
255 float fly
= (w
->state
.activity
== k_walk_activity_air
)? 1.0f
: 0.0f
,
258 if( w
->state
.activity
== k_walk_activity_air
)
263 player
.ffly
= vg_lerpf( player
.ffly
, fly
, rate
*vg
.time_delta
);
264 player
.frun
= vg_lerpf( player
.frun
,
266 (1.0f
+ player
.input_walk
->button
.value
*0.5f
),
267 2.0f
*vg
.time_delta
);
270 player_pose apose
, bpose
;
272 if( player
.walk
> 0.025f
)
275 float walk_norm
= 30.0f
/(float)player
.mdl
.anim_walk
->length
,
276 run_norm
= 30.0f
/(float)player
.mdl
.anim_run
->length
,
277 walk_adv
= vg_lerpf( walk_norm
, run_norm
, player
.walk
);
279 player
.walk_timer
+= walk_adv
* vg
.time_delta
;
283 player
.walk_timer
= 0.0f
;
286 float walk_norm
= (float)player
.mdl
.anim_walk
->length
/30.0f
,
287 run_norm
= (float)player
.mdl
.anim_run
->length
/30.0f
,
288 t
= player
.walk_timer
,
289 l
= vg_clampf( player
.frun
*15.0f
, 0.0f
, 1.0f
),
290 idle_walk
= vg_clampf( (player
.frun
-0.1f
)/(1.0f
-0.1f
), 0.0f
, 1.0f
);
293 skeleton_sample_anim( sk
, player
.mdl
.anim_walk
, t
*walk_norm
, apose
);
294 skeleton_sample_anim( sk
, player
.mdl
.anim_run
, t
*run_norm
, bpose
);
296 skeleton_lerp_pose( sk
, apose
, bpose
, l
, apose
);
299 skeleton_sample_anim( sk
, player
.mdl
.anim_idle
, vg
.time
*0.1f
, bpose
);
300 skeleton_lerp_pose( sk
, apose
, bpose
, 1.0f
-idle_walk
, apose
);
303 skeleton_sample_anim( sk
, player
.mdl
.anim_jump
, vg
.time
*0.6f
, bpose
);
304 skeleton_lerp_pose( sk
, apose
, bpose
, player
.ffly
, apose
);
306 skeleton_apply_pose( &player
.mdl
.sk
, apose
, k_anim_apply_defer_ik
);
307 skeleton_apply_ik_pass( &player
.mdl
.sk
);
308 skeleton_apply_pose( &player
.mdl
.sk
, apose
, k_anim_apply_deffered_only
);
310 v3_copy( player
.mdl
.sk
.final_mtx
[player
.mdl
.id_head
-1][3],
311 player
.mdl
.cam_pos
);
315 skeleton_apply_inverses( &player
.mdl
.sk
);
319 q_axis_angle( rot
, (v3f
){0.0f
,1.0f
,0.0f
}, -player
.angles
[0] - VG_PIf
*0.5f
);
321 v3_copy( player
.visual_transform
[3], mtx
[3] );
323 skeleton_apply_transform( &player
.mdl
.sk
, mtx
);
324 skeleton_debug( &player
.mdl
.sk
);
327 #endif /* PLAYER_PHYSICS_WALK_H */