diff --git a/src/physics.rs b/src/physics.rs index fa8a410..9ae6c4f 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -138,59 +138,61 @@ impl JumpDirection{ } } } -enum WalkEnum{ +enum WalkTarget{ Reached, - Transient(WalkTarget), -} -struct WalkTarget{ - velocity:Planar64Vec3, - time:Time, + Reachable{ + acceleration:Planar64Vec3, + time:Time, + }, + //walk target will never be reached + Unreachable{ + acceleration:Planar64Vec3, + } } struct WalkState{ jump_direction:JumpDirection, contact:ContactCollision, - state:WalkEnum, + target:WalkTarget, } -impl WalkEnum{ - //args going crazy - //(walk_enum,body.acceleration)=with_target_velocity(); - fn with_target_velocity(body:&Body,style:&StyleModifiers,velocity:Planar64Vec3,normal:&Planar64Vec3,speed:Planar64,normal_accel:Planar64)->(WalkEnum,Planar64Vec3){ - let mut target_diff=velocity-body.velocity; - //remove normal component - target_diff-=normal.clone()*(normal.dot(target_diff)/normal.dot(normal.clone())); +impl WalkTarget{ + fn with_target_diff(target_diff:Planar64Vec3,accel:Planar64,time:Time)->Self{ if target_diff==Planar64Vec3::ZERO{ - (WalkEnum::Reached,Planar64Vec3::ZERO) + WalkTarget::Reached }else{ //normal friction acceleration is clippedAcceleration.dot(normal)*friction - let diff_len=target_diff.length(); - let friction=if diff_lenPlanar64Vec3{ + match self{ + WalkTarget::Reached=>Planar64Vec3::ZERO, + &WalkTarget::Reachable{acceleration,time:_}=>acceleration, + &WalkTarget::Unreachable{acceleration}=>acceleration, } } } impl WalkState{ - fn ground(body:&Body,style:&StyleModifiers,gravity:Planar64Vec3,velocity:Planar64Vec3,contact:ContactCollision,normal:&Planar64Vec3)->(Self,Planar64Vec3){ - let (walk_enum,a)=WalkEnum::with_target_velocity(body,style,velocity,&Planar64Vec3::Y,style.walk_speed,-normal.dot(gravity)); - (Self{ - state:walk_enum, + fn ground(body:&Body,walk_settings:&gameplay_style::WalkSettings,gravity:Planar64Vec3,velocity:Planar64Vec3,contact:ContactCollision,normal:Planar64Vec3)->Self{ + let target_diff=velocity-body.velocity; + //precalculate accel + let accel=walk_settings.accel(target_diff,gravity); + Self{ + target:WalkTarget::with_target_diff(target_diff,accel,body.time), contact, jump_direction:JumpDirection::Exactly(Planar64Vec3::Y), - },a) + } } - fn ladder(body:&Body,style:&StyleModifiers,gravity:Planar64Vec3,velocity:Planar64Vec3,contact:ContactCollision,normal:&Planar64Vec3)->(Self,Planar64Vec3){ - let (walk_enum,a)=WalkEnum::with_target_velocity(body,style,velocity,normal,style.ladder_speed,style.ladder_accel); - (Self{ - state:walk_enum, + fn ladder(body:&Body,ladder_settings:&gameplay_style::LadderSettings,gravity:Planar64Vec3,velocity:Planar64Vec3,contact:ContactCollision,normal:Planar64Vec3)->Self{ + let target_diff=velocity-body.velocity; + let accel=ladder_settings.accel(target_diff,gravity); + Self{//,style,velocity,normal,style.ladder_speed,style.ladder_accel + target:WalkTarget::with_target_diff(target_diff,accel,body.time), contact, jump_direction:JumpDirection::FromContactNormal, - },a) + } } } @@ -481,6 +483,59 @@ impl MoveState{ }, } } + /// Returns whether the MoveState was changed + fn apply_input(&mut self,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&mut Body){ + match self{ + MoveState::Fly=>(), + MoveState::Air|MoveState::Water=>s.touching.base_acceleration(models,&s.style,&s.camera,&s.input_state), + MoveState::Walk(WalkState{target: state,contact,jump_direction:_})=>{ + let n=contact_normal(models,hitbox_mesh,contact); + let gravity=s.touching.base_acceleration(models,&s.style,&s.camera,&s.input_state); + let a; + let mut v=s.style.get_walk_target_velocity(&s.camera,&s.input_state,&n); + s.touching.constrain_velocity(models,hitbox_mesh,&mut v); + let normal_accel=-n.dot(gravity)/n.length(); + (*state,a)=WalkTarget::with_target_velocity(&s.body,&s.style,v,&n,s.style.walk_speed,normal_accel); + a + }, + MoveState::Ladder(WalkState{target: state,contact,jump_direction:_})=>{ + let n=contact_normal(models,hitbox_mesh,contact); + //let gravity=s.touching.base_acceleration(&data.models,&s.style,&s.camera,s.controls,&s.next_mouse,s.time); + let a; + let mut v=s.style.get_ladder_target_velocity(&s.camera,&s.input_state,&n); + s.touching.constrain_velocity(models,hitbox_mesh,&mut v); + (*state,a)=WalkTarget::with_target_velocity(&s.body,&s.style,v,&n,s.style.ladder_speed,s.style.ladder_accel); + a + }, + } + self.apply_to_body(touching,models,hitbox_mesh,body); + } + fn get_walk_state(&self)->Option<&WalkState>{ + match self{ + MoveState::Walk(walk_state) + |MoveState::Ladder(walk_state) + =>Some(walk_state), + MoveState::Air + |MoveState::Water + |MoveState::Fly + =>None, + } + } + fn next_move_instruction(&self)->Option>{ + //check if you have a valid walk state and create an instruction + match self{ + MoveState::Walk(walk_state)|MoveState::Ladder(walk_state)=>match &walk_state.target{ + WalkTarget::Reachable(walk_target)=>Some(TimedInstruction{ + time:walk_target.time, + instruction:PhysicsInstruction::ReachWalkTargetVelocity + }), + WalkTarget::Reached=>None, + } + MoveState::Air=>self.next_strafe_instruction(), + MoveState::Water=>None,//TODO + MoveState::Fly=>None, + } + } } #[derive(Clone,Default)] @@ -620,9 +675,7 @@ impl TouchingState{ fn base_acceleration(&self,models:&PhysicsModels,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState)->Planar64Vec3{ let mut a=style.gravity; if let Some(rocket_settings)=style.rocket{ - if rocket_settings.activates(input_state.controls){ - a+=rocket_settings.acceleration(style.get_propulsion_control_dir(camera,input_state)); - } + a+=rocket_settings.acceleration(style.get_propulsion_control_dir(camera,input_state.controls)); } //add accelerators for contact in &self.contacts{ @@ -647,7 +700,7 @@ impl TouchingState{ _=>panic!("impossible touching state"), } } - //add water../? + //TODO: add water a } fn constrain_velocity(&self,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,velocity:&mut Planar64Vec3){ @@ -954,23 +1007,8 @@ impl PhysicsState { // instruction:PhysicsInstruction::Water // }); // } - - fn next_move_instruction(&self)->Option>{ - //check if you have a valid walk state and create an instruction - match &self.move_state{ - MoveState::Walk(walk_state)|MoveState::Ladder(walk_state)=>match &walk_state.state{ - WalkEnum::Transient(walk_target)=>Some(TimedInstruction{ - time:walk_target.time, - instruction:PhysicsInstruction::ReachWalkTargetVelocity - }), - WalkEnum::Reached=>None, - } - MoveState::Air=>self.next_strafe_instruction(), - MoveState::Water=>None,//TODO - MoveState::Fly=>None, - } - } } + #[derive(Default)] pub struct PhysicsContext{ pub state:PhysicsState,//this captures the entire state of the physics. @@ -1074,33 +1112,6 @@ impl PhysicsContext{ } } - //TODO get rid of this trash - fn refresh_walk_target(s:&mut PhysicsState,data:&PhysicsData)->Planar64Vec3{ - match &mut s.move_state{ - MoveState::Fly=>Planar64Vec3::ZERO, - MoveState::Air|MoveState::Water=>s.touching.base_acceleration(&data.models,&s.style,&s.camera,&s.input_state), - MoveState::Walk(WalkState{state,contact,jump_direction:_})=>{ - let n=contact_normal(&data.models,&data.hitbox_mesh,contact); - let gravity=s.touching.base_acceleration(&data.models,&s.style,&s.camera,&s.input_state); - let a; - let mut v=s.style.get_walk_target_velocity(&s.camera,&s.input_state,&n); - s.touching.constrain_velocity(&data.models,&data.hitbox_mesh,&mut v); - let normal_accel=-n.dot(gravity)/n.length(); - (*state,a)=WalkEnum::with_target_velocity(&s.body,&s.style,v,&n,s.style.walk_speed,normal_accel); - a - }, - MoveState::Ladder(WalkState{state,contact,jump_direction:_})=>{ - let n=contact_normal(&data.models,&data.hitbox_mesh,contact); - //let gravity=s.touching.base_acceleration(&data.models,&s.style,&s.camera,s.controls,&s.next_mouse,s.time); - let a; - let mut v=s.style.get_ladder_target_velocity(&s.camera,&s.input_state,&n); - s.touching.constrain_velocity(&data.models,&data.hitbox_mesh,&mut v); - (*state,a)=WalkEnum::with_target_velocity(&s.body,&s.style,v,&n,s.style.ladder_speed,s.style.ladder_accel); - a - }, - } - } - fn literally_next_instruction_but_with_context(state:&PhysicsState,data:&PhysicsData,time_limit:Time)->Option>{ //JUST POLLING!!! NO MUTATION let mut collector = instruction::InstructionCollector::new(time_limit); @@ -1132,17 +1143,6 @@ impl PhysicsContext{ collector.instruction() } -fn get_walk_state(move_state:&MoveState)->Option<&WalkState>{ - match move_state{ - MoveState::Walk(walk_state) - |MoveState::Ladder(walk_state) - =>Some(walk_state), - MoveState::Air - |MoveState::Water - |MoveState::Fly - =>None, - } -} fn contact_normal(models:&PhysicsModels,hitbox_mesh:&HitboxMesh,contact:&ContactCollision)->Planar64Vec3{ let model_mesh=models.mesh(contact.convex_mesh_id); @@ -1350,7 +1350,7 @@ fn run_teleport_behaviour(wormhole:&Option,models } let calc_move=if state.style.get_control(Controls::Jump,state.input_state.controls){ state.style.jump.is_some_and(|jump_settings|{ - get_walk_state(&state.move_state).is_some_and(|walk_state|{ + state.move_state.get_walk_state().is_some_and(|walk_state|{ let jump_dir=walk_state.jump_direction.direction(&data.models,&data.hitbox_mesh,&walk_state.contact); v=jump_settings.jumped_velocity(&state.style,jump_dir,v); set_velocity_cull(&mut state.body,&mut state.touching,&data.models,&data.hitbox_mesh,v) @@ -1375,8 +1375,9 @@ fn run_teleport_behaviour(wormhole:&Option,models if calc_move||Planar64::ZERO{ //I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop @@ -1427,15 +1428,15 @@ fn run_teleport_behaviour(wormhole:&Option,models |MoveState::Fly =>println!("ReachWalkTargetVelocity fired for non-walking MoveState"), MoveState::Walk(walk_state)|MoveState::Ladder(walk_state)=>{ - match &mut walk_state.state{ - WalkEnum::Reached=>(), - WalkEnum::Transient(walk_target)=>{ + match &mut walk_state.target{ + WalkTarget::Reached=>(), + WalkTarget::Reachable(walk_target)=>{ //precisely set velocity let a=Planar64Vec3::ZERO;//ignore gravity for now. set_acceleration(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,a); let v=walk_target.velocity; set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,v); - walk_state.state=WalkEnum::Reached; + walk_state.target=WalkTarget::Reached; }, } } @@ -1491,10 +1492,7 @@ fn run_teleport_behaviour(wormhole:&Option,models PhysicsInputInstruction::Idle=>{b_refresh_walk_target=false;},//literally idle! } if b_refresh_walk_target{ - let a=refresh_walk_target(state,data); - if set_acceleration_cull(&mut state.body,&mut state.touching,&data.models,&data.hitbox_mesh,a){ - (state.move_state,state.body.acceleration)=state.touching.get_move_state(&state.body,&data.models,&state.style,&data.hitbox_mesh,&state.camera,&state.input_state,state.time); - } + state.move_state.apply_input(&mut state.body); } }, }