SetControlDir + contact constrain + walk.state enum instead of hash
This commit is contained in:
parent
1dc98d9c2d
commit
17e71d884f
132
src/body.rs
132
src/body.rs
@ -4,9 +4,11 @@ use crate::{instruction::{InstructionEmitter, InstructionConsumer, TimedInstruct
|
|||||||
pub enum PhysicsInstruction {
|
pub enum PhysicsInstruction {
|
||||||
CollisionStart(RelativeCollision),
|
CollisionStart(RelativeCollision),
|
||||||
CollisionEnd(RelativeCollision),
|
CollisionEnd(RelativeCollision),
|
||||||
|
SetControlDir(glam::Vec3),
|
||||||
StrafeTick,
|
StrafeTick,
|
||||||
Jump,
|
Jump,
|
||||||
SetWalkTargetVelocity(glam::Vec3),
|
SetWalkTargetVelocity(glam::Vec3),
|
||||||
|
RefreshWalkTarget,
|
||||||
ReachWalkTargetVelocity,
|
ReachWalkTargetVelocity,
|
||||||
// Water,
|
// Water,
|
||||||
// Spawn(
|
// Spawn(
|
||||||
@ -108,17 +110,22 @@ impl MouseInterpolationState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum WalkEnum{
|
||||||
|
Reached,
|
||||||
|
Transient,
|
||||||
|
Invalid,
|
||||||
|
}
|
||||||
pub struct WalkState {
|
pub struct WalkState {
|
||||||
pub target_velocity: glam::Vec3,
|
pub target_velocity: glam::Vec3,
|
||||||
pub target_time: TIME,
|
pub target_time: TIME,
|
||||||
pub body_hash: u64,
|
pub state: WalkEnum,
|
||||||
}
|
}
|
||||||
impl WalkState {
|
impl WalkState {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self{
|
Self{
|
||||||
target_velocity:glam::Vec3::ZERO,
|
target_velocity:glam::Vec3::ZERO,
|
||||||
target_time:0,
|
target_time:0,
|
||||||
body_hash:0,//oh no, hash collisions
|
state:WalkEnum::Invalid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -359,6 +366,25 @@ impl PhysicsState {
|
|||||||
self.time=time;
|
self.time=time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn contact_constrain_velocity(&self,velocity:&mut glam::Vec3){
|
||||||
|
for contact in self.contacts.iter() {
|
||||||
|
let n=contact.normal(&self.models_cringe_clone);
|
||||||
|
let d=velocity.dot(n);
|
||||||
|
if d<0f32{
|
||||||
|
(*velocity)-=d/n.length_squared()*n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn contact_constrain_acceleration(&self,acceleration:&mut glam::Vec3){
|
||||||
|
for contact in self.contacts.iter() {
|
||||||
|
let n=contact.normal(&self.models_cringe_clone);
|
||||||
|
let d=acceleration.dot(n);
|
||||||
|
if d<0f32{
|
||||||
|
(*acceleration)-=d/n.length_squared()*n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn next_strafe_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
|
fn next_strafe_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
|
||||||
return Some(TimedInstruction{
|
return Some(TimedInstruction{
|
||||||
time:(self.time*self.strafe_tick_num/self.strafe_tick_den+1)*self.strafe_tick_den/self.strafe_tick_num,
|
time:(self.time*self.strafe_tick_num/self.strafe_tick_den+1)*self.strafe_tick_den/self.strafe_tick_num,
|
||||||
@ -400,11 +426,18 @@ impl PhysicsState {
|
|||||||
|
|
||||||
fn next_walk_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
|
fn next_walk_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
|
||||||
//check if you have a valid walk state and create an instruction
|
//check if you have a valid walk state and create an instruction
|
||||||
if self.grounded&&self.walk.body_hash==self.body.hash(){
|
if self.grounded{
|
||||||
Some(TimedInstruction{
|
match self.walk.state{
|
||||||
|
WalkEnum::Transient=>Some(TimedInstruction{
|
||||||
time:self.walk.target_time,
|
time:self.walk.target_time,
|
||||||
instruction:PhysicsInstruction::ReachWalkTargetVelocity
|
instruction:PhysicsInstruction::ReachWalkTargetVelocity
|
||||||
})
|
}),
|
||||||
|
WalkEnum::Invalid=>Some(TimedInstruction{
|
||||||
|
time:self.time,
|
||||||
|
instruction:PhysicsInstruction::RefreshWalkTarget,
|
||||||
|
}),
|
||||||
|
WalkEnum::Reached=>None,
|
||||||
|
}
|
||||||
}else{
|
}else{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -704,70 +737,107 @@ impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState
|
|||||||
|
|
||||||
impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsState {
|
impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsState {
|
||||||
fn process_instruction(&mut self, ins:TimedInstruction<PhysicsInstruction>) {
|
fn process_instruction(&mut self, ins:TimedInstruction<PhysicsInstruction>) {
|
||||||
//mutate position and velocity and time
|
match &ins.instruction {
|
||||||
self.advance_time(ins.time);//should this be in run?
|
PhysicsInstruction::StrafeTick => (),
|
||||||
|
_=>println!("{:?}",ins),
|
||||||
|
}
|
||||||
|
//selectively update body
|
||||||
|
match &ins.instruction {
|
||||||
|
PhysicsInstruction::SetWalkTargetVelocity(_) => (),//TODO: queue instructions and do self.time=ins.time,
|
||||||
|
PhysicsInstruction::RefreshWalkTarget
|
||||||
|
|PhysicsInstruction::ReachWalkTargetVelocity
|
||||||
|
|PhysicsInstruction::CollisionStart(_)
|
||||||
|
|PhysicsInstruction::CollisionEnd(_)
|
||||||
|
|PhysicsInstruction::StrafeTick
|
||||||
|
|PhysicsInstruction::SetControlDir(_)
|
||||||
|
|PhysicsInstruction::Jump => self.advance_time(ins.time),
|
||||||
|
}
|
||||||
match ins.instruction {
|
match ins.instruction {
|
||||||
PhysicsInstruction::CollisionStart(c) => {
|
PhysicsInstruction::CollisionStart(c) => {
|
||||||
//flatten v
|
|
||||||
let n=c.normal(&self.models_cringe_clone);
|
|
||||||
let d=self.body.velocity.dot(n)/n.length_squared();
|
|
||||||
self.body.velocity-=d*n;
|
|
||||||
//check ground
|
//check ground
|
||||||
match c.face {
|
match &c.face {
|
||||||
AabbFace::Top => {
|
AabbFace::Top => {
|
||||||
//ground
|
//ground
|
||||||
self.grounded=true;
|
self.grounded=true;
|
||||||
self.body.acceleration=glam::Vec3::ZERO;
|
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
self.contacts.insert(c);
|
self.contacts.insert(c);
|
||||||
|
//flatten v
|
||||||
|
let mut v=self.body.velocity;
|
||||||
|
self.contact_constrain_velocity(&mut v);
|
||||||
|
self.body.velocity=v;
|
||||||
|
self.walk.state=WalkEnum::Invalid;
|
||||||
},
|
},
|
||||||
PhysicsInstruction::CollisionEnd(c) => {
|
PhysicsInstruction::CollisionEnd(c) => {
|
||||||
|
self.contacts.remove(&c);//remove contact before calling contact_constrain_acceleration
|
||||||
|
let mut a=self.gravity;
|
||||||
|
self.contact_constrain_acceleration(&mut a);
|
||||||
|
self.body.acceleration=a;
|
||||||
|
self.walk.state=WalkEnum::Invalid;
|
||||||
//check ground
|
//check ground
|
||||||
match c.face {
|
match &c.face {
|
||||||
AabbFace::Top => {
|
AabbFace::Top => {
|
||||||
//this needs to be ContactConstrainAcceleration(gravity)
|
self.grounded=false;
|
||||||
self.body.acceleration=self.gravity;
|
|
||||||
},
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
self.contacts.remove(&c);
|
},
|
||||||
|
PhysicsInstruction::SetControlDir(control_dir)=>{
|
||||||
|
self.temp_control_dir=control_dir;
|
||||||
|
self.walk.state=WalkEnum::Invalid;
|
||||||
},
|
},
|
||||||
PhysicsInstruction::StrafeTick => {
|
PhysicsInstruction::StrafeTick => {
|
||||||
//let control_dir=self.get_control_dir();//this should respect your mouse interpolation settings
|
//let control_dir=self.get_control_dir();//this should respect your mouse interpolation settings
|
||||||
let d=self.body.velocity.dot(self.temp_control_dir);
|
let d=self.body.velocity.dot(self.temp_control_dir);
|
||||||
if d<self.mv {
|
if d<self.mv {
|
||||||
self.body.velocity+=(self.mv-d)*self.temp_control_dir;
|
let mut v=self.body.velocity+(self.mv-d)*self.temp_control_dir;
|
||||||
|
self.contact_constrain_velocity(&mut v);
|
||||||
|
self.body.velocity=v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PhysicsInstruction::Jump => {
|
PhysicsInstruction::Jump => {
|
||||||
self.grounded=false;//do I need this?
|
self.grounded=false;//do I need this?
|
||||||
self.body.velocity+=glam::Vec3::new(0.0,0.715588/2.0*100.0,0.0);
|
let mut v=self.body.velocity+glam::Vec3::new(0.0,0.715588/2.0*100.0,0.0);
|
||||||
}
|
self.contact_constrain_velocity(&mut v);
|
||||||
|
self.body.velocity=v;
|
||||||
|
self.walk.state=WalkEnum::Invalid;
|
||||||
|
},
|
||||||
PhysicsInstruction::ReachWalkTargetVelocity => {
|
PhysicsInstruction::ReachWalkTargetVelocity => {
|
||||||
//precisely set velocity
|
//precisely set velocity
|
||||||
self.body.acceleration=glam::Vec3::ZERO;
|
let mut a=glam::Vec3::ZERO;
|
||||||
self.body.velocity=self.walk.target_velocity;
|
self.contact_constrain_acceleration(&mut a);
|
||||||
//what if it's exactly the same, and the time delta is 0?
|
self.body.acceleration=a;
|
||||||
//the hash will succeed and it will poll the same instruction infinitely...
|
let mut v=self.walk.target_velocity;
|
||||||
}
|
self.contact_constrain_velocity(&mut v);
|
||||||
PhysicsInstruction::SetWalkTargetVelocity(v) => {
|
self.body.velocity=v;
|
||||||
|
self.walk.state=WalkEnum::Reached;
|
||||||
|
},
|
||||||
|
PhysicsInstruction::RefreshWalkTarget => {
|
||||||
//calculate acceleration yada yada
|
//calculate acceleration yada yada
|
||||||
if self.grounded{
|
if self.grounded{
|
||||||
let target_diff=v-self.body.velocity;
|
let mut target_diff=self.walk.target_velocity-self.body.velocity;
|
||||||
|
target_diff.y=0f32;
|
||||||
if target_diff==glam::Vec3::ZERO{
|
if target_diff==glam::Vec3::ZERO{
|
||||||
self.body.acceleration=glam::Vec3::ZERO;
|
let mut a=glam::Vec3::ZERO;
|
||||||
|
self.contact_constrain_acceleration(&mut a);
|
||||||
|
self.body.acceleration=a;
|
||||||
|
self.walk.state=WalkEnum::Reached;
|
||||||
}else{
|
}else{
|
||||||
let accel=self.walk_accel.min(self.gravity.length()*self.friction);
|
let accel=self.walk_accel.min(self.gravity.length()*self.friction);
|
||||||
let time_delta=target_diff.length()/accel;
|
let time_delta=target_diff.length()/accel;
|
||||||
self.body.acceleration=target_diff/time_delta;
|
let mut a=target_diff/time_delta;
|
||||||
self.walk.target_velocity=v;
|
self.contact_constrain_acceleration(&mut a);
|
||||||
|
self.body.acceleration=a;
|
||||||
self.walk.target_time=self.body.time+((time_delta as f64)*1_000_000_000f64) as TIME;
|
self.walk.target_time=self.body.time+((time_delta as f64)*1_000_000_000f64) as TIME;
|
||||||
self.walk.body_hash=self.body.hash();//hash check to see if walk target is valid
|
self.walk.state=WalkEnum::Transient;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
PhysicsInstruction::SetWalkTargetVelocity(v) => {
|
||||||
|
self.walk.target_velocity=v;
|
||||||
|
self.walk.state=WalkEnum::Invalid;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -640,7 +640,7 @@ impl strafe_client::framework::Example for Skybox {
|
|||||||
|
|
||||||
let walk_target_velocity=self.physics.walkspeed*control_dir;
|
let walk_target_velocity=self.physics.walkspeed*control_dir;
|
||||||
//autohop (already pressing spacebar; the signal to begin trying to jump is different)
|
//autohop (already pressing spacebar; the signal to begin trying to jump is different)
|
||||||
if walk_target_velocity!=self.physics.walk.target_velocity {
|
if self.physics.grounded&&walk_target_velocity!=self.physics.walk.target_velocity {
|
||||||
//scroll will be implemented with InputInstruction::Jump(true) but it blocks setting self.jump_trying=true
|
//scroll will be implemented with InputInstruction::Jump(true) but it blocks setting self.jump_trying=true
|
||||||
strafe_client::instruction::InstructionConsumer::process_instruction(&mut self.physics, strafe_client::instruction::TimedInstruction{
|
strafe_client::instruction::InstructionConsumer::process_instruction(&mut self.physics, strafe_client::instruction::TimedInstruction{
|
||||||
time,//this is in the past when there is no instructions!
|
time,//this is in the past when there is no instructions!
|
||||||
@ -648,7 +648,12 @@ impl strafe_client::framework::Example for Skybox {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
self.physics.temp_control_dir=control_dir;
|
if control_dir!=self.physics.temp_control_dir {
|
||||||
|
strafe_client::instruction::InstructionConsumer::process_instruction(&mut self.physics, strafe_client::instruction::TimedInstruction{
|
||||||
|
time,
|
||||||
|
instruction:strafe_client::body::PhysicsInstruction::SetControlDir(control_dir)
|
||||||
|
});
|
||||||
|
}
|
||||||
self.physics.jump_trying=self.camera.controls&CONTROL_JUMP!=0;
|
self.physics.jump_trying=self.camera.controls&CONTROL_JUMP!=0;
|
||||||
self.physics.run(time);
|
self.physics.run(time);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user