From 93b04f4f1f7a10b1c50d213fffd755ba9223eee0 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Thu, 8 Aug 2024 16:54:42 -0700 Subject: [PATCH] physics: recalculate touching parts in set_position --- src/model_physics.rs | 17 ++ src/physics.rs | 575 ++++++++++++++++++++++++++++--------------- 2 files changed, 400 insertions(+), 192 deletions(-) diff --git a/src/model_physics.rs b/src/model_physics.rs index 566c507..0815e4f 100644 --- a/src/model_physics.rs +++ b/src/model_physics.rs @@ -751,6 +751,23 @@ impl MinkowskiMesh<'_>{ } best_edge.map(|e|(e.as_undirected(),best_time)) } + fn infinity_in(&self,infinity_body:crate::physics::Body)->Option<(MinkowskiFace,integer::Time)>{ + let infinity_fev=self.infinity_fev(-infinity_body.velocity,infinity_body.position); + match crate::face_crawler::crawl_fev(infinity_fev,self,&infinity_body,integer::Time::MIN,infinity_body.time){ + crate::face_crawler::CrawlResult::Miss(_)=>None, + crate::face_crawler::CrawlResult::Hit(face,time)=>Some((face,time)), + } + } + pub fn is_point_in_mesh(&self,point:Planar64Vec3)->bool{ + let infinity_body=crate::physics::Body::new(point,Planar64Vec3::Y,Planar64Vec3::ZERO,integer::Time::ZERO); + //movement must escape the mesh forwards and backwards in time, + //otherwise the point is not inside the mesh + self.infinity_in(infinity_body) + .is_some_and(|_| + self.infinity_in(-infinity_body) + .is_some() + ) + } } impl MeshQuery for MinkowskiMesh<'_>{ fn face_nd(&self,face_id:MinkowskiFace)->(Planar64Vec3,Planar64){ diff --git a/src/physics.rs b/src/physics.rs index 0c5d325..273e7fc 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -579,6 +579,38 @@ impl MoveState{ MoveState::Fly=>None, } } + //lmao idk this is convenient + fn apply_enum_and_input_and_body(&mut self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){ + self.apply_enum(body,touching,models,hitbox_mesh,style,camera,input_state); + self.apply_input(body,touching,models,hitbox_mesh,style,camera,input_state); + self.apply_to_body(body,touching,models,hitbox_mesh,style,camera,input_state); + } + fn apply_enum_and_body(&mut self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){ + self.apply_enum(body,touching,models,hitbox_mesh,style,camera,input_state); + self.apply_to_body(body,touching,models,hitbox_mesh,style,camera,input_state); + } + fn apply_input_and_body(&mut self,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){ + self.apply_input(body,touching,models,hitbox_mesh,style,camera,input_state); + self.apply_to_body(body,touching,models,hitbox_mesh,style,camera,input_state); + } + fn set_move_state(&mut self,move_state:MoveState,body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){ + *self=move_state; + //this function call reads the above state that was just set + self.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state); + } + fn cull_velocity(&mut self,velocity:Planar64Vec3,body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState){ + //TODO: be more precise about contacts + if set_velocity_cull(body,touching,models,hitbox_mesh,velocity){ + //TODO do better + match self.get_walk_state(){ + //did you stop touching the thing you were walking on? + Some(walk_state)=>if !touching.contacts.contains(&walk_state.contact){ + self.set_move_state(MoveState::Air,body,touching,models,hitbox_mesh,style,camera,input_state); + }, + None=>self.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state), + } + } + } } #[derive(Clone,Default)] @@ -956,39 +988,15 @@ impl PhysicsState{ fn next_move_instruction(&self)->Option>{ self.move_state.next_move_instruction(&self.style.strafe,self.time) } - //lmao idk this is convenient - fn apply_enum_and_input_and_body(&mut self,data:&PhysicsData){ - self.move_state.apply_enum(&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); - self.move_state.apply_input(&self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); - self.move_state.apply_to_body(&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); - } - fn apply_enum_and_body(&mut self,data:&PhysicsData){ - self.move_state.apply_enum(&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); - self.move_state.apply_to_body(&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); - } - fn apply_input_and_body(&mut self,data:&PhysicsData){ - self.move_state.apply_input(&self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); - self.move_state.apply_to_body(&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); + fn cull_velocity(&mut self,data:&PhysicsData,velocity:Planar64Vec3){ + self.move_state.cull_velocity(velocity,&mut self.body,&mut self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); } fn set_move_state(&mut self,data:&PhysicsData,move_state:MoveState){ - self.move_state=move_state; - //this function call reads the above state that was just set - self.apply_enum_and_body(data); + self.move_state.set_move_state(move_state,&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); } - fn cull_velocity(&mut self,data:&PhysicsData,velocity:Planar64Vec3){ - //TODO: be more precise about contacts - if set_velocity_cull(&mut self.body,&mut self.touching,&data.models,&data.hitbox_mesh,velocity){ - //TODO do better - match self.move_state.get_walk_state(){ - //did you stop touching the thing you were walking on? - Some(walk_state)=>if !self.touching.contacts.contains(&walk_state.contact){ - self.set_move_state(data,MoveState::Air); - }, - None=>self.apply_enum_and_body(data), - } - } + fn apply_input_and_body(&mut self,data:&PhysicsData){ + self.move_state.apply_input_and_body(&mut self.body,&self.touching,&data.models,&data.hitbox_mesh,&self.style,&self.camera,&self.input_state); } - //state mutated on collision: //Accelerator //stair step-up @@ -1254,14 +1262,80 @@ fn contact_normal(models:&PhysicsModels,hitbox_mesh:&HitboxMesh,contact:&Contact minkowski.face_nd(contact.face_id).0 } -fn set_position(body:&mut Body,touching:&mut TouchingState,point:Planar64Vec3)->Planar64Vec3{ +fn recalculate_touching( + move_state:&mut MoveState, + body:&mut Body, + touching:&mut TouchingState, + run:&mut run::Run, + mode_state:&mut ModeState, + mode:Option<&gameplay_modes::Mode>, + models:&PhysicsModels, + hitbox_mesh:&HitboxMesh, + bvh:&bvh::BvhNode, + style:&StyleModifiers, + camera:&PhysicsCamera, + input_state:&InputState, + time:Time, +){ + //collision_end all existing contacts + //I would have preferred while let Some(contact)=contacts.pop() + //but there is no such method + while let Some(&contact)=touching.contacts.iter().next(){ + collision_end_contact(move_state,body,touching,models,hitbox_mesh,style,camera,input_state,models.contact_attr(contact.model_id),contact) + } + while let Some(&intersect)=touching.intersects.iter().next(){ + collision_end_intersect(touching,mode,run,models.intersect_attr(intersect.model_id),intersect,time); + } + //find all models in the teleport region + let mut aabb=aabb::Aabb::default(); + aabb.grow(body.position); + aabb.inflate(hitbox_mesh.halfsize); + //relative to moving platforms + //let relative_body=&VirtualBody::relative(&Body::default(),&state.body).body(state.time); + bvh.the_tester(&aabb,&mut |&convex_mesh_id|{ + //no checks are needed because of the time limits. + let model_mesh=models.mesh(convex_mesh_id); + let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh()); + if minkowski.is_point_in_mesh(body.position){ + match convex_mesh_id.model_id{ + //being inside of contact objects is an invalid physics state + //but the physics isn't advanced enough to do anything about it yet + //TODO: PushSolve and search for the closest valid position + PhysicsModelId::Contact(_)=>(), + PhysicsModelId::Intersect(model_id)=> + collision_start_intersect(move_state,body,mode_state,touching,mode,run,models,hitbox_mesh,bvh,style,camera,input_state, + models.intersect_attr(model_id), + IntersectCollision{ + model_id, + submesh_id:convex_mesh_id.submesh_id, + }, + time, + ), + } + } + }); +} +fn set_position( + point:Planar64Vec3, + move_state:&mut MoveState, + body:&mut Body, + touching:&mut TouchingState, + run:&mut run::Run, + mode_state:&mut ModeState, + mode:Option<&gameplay_modes::Mode>, + models:&PhysicsModels, + hitbox_mesh:&HitboxMesh, + bvh:&bvh::BvhNode, + style:&StyleModifiers, + camera:&PhysicsCamera, + input_state:&InputState, + time:Time, +)->Planar64Vec3{ //test intersections at new position //hovering above the surface 0 units is not intersecting. you will fall into it just fine body.position=point; - //manual clear //for c in contacts{process_instruction(CollisionEnd(c))} - touching.clear(); - //TODO: calculate contacts and determine the actual state - //touching.recalculate(body); + //calculate contacts and determine the actual state + recalculate_touching(move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); point } fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,v:Planar64Vec3)->bool{ @@ -1303,31 +1377,71 @@ fn set_acceleration(body:&mut Body,touching:&TouchingState,models:&PhysicsModels body.acceleration=a; } -fn teleport(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,style:&StyleModifiers,hitbox_mesh:&HitboxMesh,point:Planar64Vec3)->MoveState{ - set_position(body,touching,point); +fn teleport( + point:Planar64Vec3, + move_state:&mut MoveState, + body:&mut Body, + touching:&mut TouchingState, + run:&mut run::Run, + mode_state:&mut ModeState, + mode:Option<&gameplay_modes::Mode>, + models:&PhysicsModels, + hitbox_mesh:&HitboxMesh, + bvh:&bvh::BvhNode, + style:&StyleModifiers, + camera:&PhysicsCamera, + input_state:&InputState, + time:Time, +){ + set_position(point,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); set_acceleration(body,touching,models,hitbox_mesh,style.gravity); - MoveState::Air } -fn teleport_to_spawn(body:&mut Body,touching:&mut TouchingState,style:&StyleModifiers,hitbox_mesh:&HitboxMesh,mode:&gameplay_modes::Mode,models:&PhysicsModels,stage_id:gameplay_modes::StageId)->Option{ - let transform=models.get_model_transform(mode.get_spawn_model_id(stage_id)?)?; +enum TeleportToSpawnError{ + NoModel, +} +fn teleport_to_spawn( + stage:&gameplay_modes::Stage, + move_state:&mut MoveState, + body:&mut Body, + touching:&mut TouchingState, + run:&mut run::Run, + mode_state:&mut ModeState, + mode:&gameplay_modes::Mode, + models:&PhysicsModels, + hitbox_mesh:&HitboxMesh, + bvh:&bvh::BvhNode, + style:&StyleModifiers, + camera:&PhysicsCamera, + input_state:&InputState, + time:Time, +)->Result<(),TeleportToSpawnError>{ + let transform=models.get_model_transform(stage.spawn()).ok_or(TeleportToSpawnError::NoModel)?; let point=transform.vertex.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(style.hitbox.halfsize.y()+Planar64::ONE/16); - Some(teleport(body,touching,models,style,hitbox_mesh,point)) + teleport(point,move_state,body,touching,run,mode_state,Some(mode),models,hitbox_mesh,bvh,style,camera,input_state,time); + Ok(()) } fn run_teleport_behaviour( - wormhole:&Option, - models:&PhysicsModels, - mode:&gameplay_modes::Mode, - style:&StyleModifiers, - hitbox_mesh:&HitboxMesh, - mode_state:&mut ModeState, - touching:&mut TouchingState, - body:&mut Body, model_id:ModelId, -)->Option{ + wormhole:Option<&gameplay_attributes::Wormhole>, + mode:Option<&gameplay_modes::Mode>, + move_state:&mut MoveState, + body:&mut Body, + touching:&mut TouchingState, + run:&mut run::Run, + mode_state:&mut ModeState, + models:&PhysicsModels, + hitbox_mesh:&HitboxMesh, + bvh:&bvh::BvhNode, + style:&StyleModifiers, + camera:&PhysicsCamera, + input_state:&InputState, + time:Time, +){ //TODO: jump count and checkpoints are always reset on teleport. //Map makers are expected to use tools to prevent //multi-boosting on JumpLimit boosters such as spawning into a SetVelocity + if let Some(mode)=mode{ if let Some(stage_element)=mode.get_element(model_id){ if let Some(stage)=mode.get_stage(stage_element.stage_id()){ if mode_state.get_stage_id()if !stage.is_empty(){ + mode_state.set_stage_id(stage_id); + let _=teleport_to_spawn(stage,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); + return; + }, + None=>{ + //no such stage! set to last existing stage and break loop + mode_state.set_stage_id(StageId::new(stage_id.get()-1)); + loop_unbroken=false; + break; + }, } - } + }; //notably you do not get teleported for touching ordered checkpoints in the wrong order within the same stage. - mode_state.set_stage_id(stage_element.stage_id()); + if loop_unbroken{ + mode_state.set_stage_id(stage_element.stage_id()); + } }else if stage_element.force(){ //forced stage_element will set the stage_id even if the stage has already been passed mode_state.set_stage_id(stage_element.stage_id()); @@ -1357,9 +1484,10 @@ fn run_teleport_behaviour( match stage_element.behaviour(){ gameplay_modes::StageElementBehaviour::SpawnAt=>(), gameplay_modes::StageElementBehaviour::Trigger - |gameplay_modes::StageElementBehaviour::Teleport=>{ + |gameplay_modes::StageElementBehaviour::Teleport=>if let Some(mode_state_stage)=mode.get_stage(mode_state.get_stage_id()){ //I guess this is correct behaviour when trying to teleport to a non-existent spawn but it's still weird - return teleport_to_spawn(body,touching,style,hitbox_mesh,mode,models,mode_state.get_stage_id()); + let _=teleport_to_spawn(mode_state_stage,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); + return; }, gameplay_modes::StageElementBehaviour::Platform=>(), gameplay_modes::StageElementBehaviour::Check=>(),//this is to run the checkpoint check behaviour without any other side effects @@ -1373,158 +1501,185 @@ fn run_teleport_behaviour( } } } - match wormhole{ - &Some(gameplay_attributes::Wormhole{destination_model})=>{ - let origin=models.get_model_transform(model_id)?; - let destination=models.get_model_transform(destination_model)?; - //ignore the transform for now - Some(teleport(body,touching,models,style,hitbox_mesh,body.position-origin.vertex.translation+destination.vertex.translation)) + } + if let Some(&gameplay_attributes::Wormhole{destination_model})=wormhole{ + if let (Some(origin),Some(destination))=(models.get_model_transform(model_id),models.get_model_transform(destination_model)){ + let point=body.position-origin.vertex.translation+destination.vertex.translation; + //TODO: camera angles + teleport(point,move_state,body,touching,run,mode_state,mode,models,hitbox_mesh,bvh,style,camera,input_state,time); } - None=>None, } } fn collision_start_contact( - state:&mut PhysicsState, - data:&PhysicsData, + move_state:&mut MoveState, + body:&mut Body, + mode_state:&mut ModeState, + touching:&mut TouchingState, + run:&mut run::Run, + mode:Option<&gameplay_modes::Mode>, + models:&PhysicsModels, + hitbox_mesh:&HitboxMesh, + bvh:&bvh::BvhNode, + style:&StyleModifiers, + camera:&PhysicsCamera, + input_state:&InputState, attr:&gameplay_attributes::ContactAttributes, contact:ContactCollision, + time:Time, ){ - let incident_velocity=state.body.velocity; - //add to touching - state.touching.insert(Collision::Contact(contact)); - //clip v - set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,incident_velocity); - match &attr.contacting.contact_behaviour{ - Some(gameplay_attributes::ContactingBehaviour::Surf)=>println!("I'm surfing!"), - Some(gameplay_attributes::ContactingBehaviour::Cling)=>println!("Unimplemented!"), - &Some(gameplay_attributes::ContactingBehaviour::Elastic(elasticity))=>{ - let reflected_velocity=state.body.velocity+(state.body.velocity-incident_velocity)*Planar64::raw(elasticity as i64+1); - set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,reflected_velocity); - }, - Some(gameplay_attributes::ContactingBehaviour::Ladder(contacting_ladder))=> - if let Some(ladder_settings)=&state.style.ladder{ - if contacting_ladder.sticky{ - //kill v - //actually you could do this with a booster attribute :thinking: - //it's a little bit different because maybe you want to chain ladders together - set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,Planar64Vec3::ZERO);//model.velocity - } - //ladder walkstate - let (gravity,target_velocity)=ladder_things(ladder_settings,&contact,&state.touching,&data.models,&data.hitbox_mesh,&state.style,&state.camera,&state.input_state); - let walk_state=ContactMoveState::ladder(ladder_settings,&state.body,gravity,target_velocity,contact); - state.set_move_state(data,MoveState::Ladder(walk_state)); - }, - Some(gameplay_attributes::ContactingBehaviour::NoJump)=>todo!("nyi"), - None=>if let Some(walk_settings)=&state.style.walk{ - if walk_settings.is_slope_walkable(contact_normal(&data.models,&data.hitbox_mesh,&contact),Planar64Vec3::Y){ - //ground - let (gravity,target_velocity)=ground_things(walk_settings,&contact,&state.touching,&data.models,&data.hitbox_mesh,&state.style,&state.camera,&state.input_state); - let walk_state=ContactMoveState::ground(walk_settings,&state.body,gravity,target_velocity,contact); - state.set_move_state(data,MoveState::Walk(walk_state)); - } - }, - } - //I love making functions with 10 arguments to dodge the borrow checker - if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){ - run_teleport_behaviour(&attr.general.wormhole,&data.models,mode,&state.style,&data.hitbox_mesh,&mut state.mode_state,&mut state.touching,&mut state.body,contact.model_id.into()); - } - if state.style.get_control(Controls::Jump,state.input_state.controls){ - if let (Some(jump_settings),Some(walk_state))=(&state.style.jump,state.move_state.get_walk_state()){ - let jump_dir=walk_state.jump_direction.direction(&data.models,&data.hitbox_mesh,&walk_state.contact); - let jumped_velocity=jump_settings.jumped_velocity(&state.style,jump_dir,state.body.velocity,attr.general.booster.as_ref()); - state.cull_velocity(data,jumped_velocity); - } - } - match &attr.general.trajectory{ - Some(trajectory)=>{ - match trajectory{ - gameplay_attributes::SetTrajectory::AirTime(_)=>todo!(), - gameplay_attributes::SetTrajectory::Height(_)=>todo!(), - gameplay_attributes::SetTrajectory::TargetPointTime { target_point: _, time: _ }=>todo!(), - gameplay_attributes::SetTrajectory::TargetPointSpeed { target_point: _, speed: _, trajectory_choice: _ }=>todo!(), - &gameplay_attributes::SetTrajectory::Velocity(velocity)=>{ - state.cull_velocity(data,velocity); - }, - gameplay_attributes::SetTrajectory::DotVelocity { direction: _, dot: _ }=>todo!(), - } - }, - None=>(), - } - //doing enum to set the acceleration when surfing - //doing input_and_body to refresh the walk state if you hit a wall while accelerating - state.apply_enum_and_input_and_body(data); + let incident_velocity=body.velocity; + //add to touching + touching.insert(Collision::Contact(contact)); + //clip v + set_velocity(body,touching,models,hitbox_mesh,incident_velocity); + match &attr.contacting.contact_behaviour{ + Some(gameplay_attributes::ContactingBehaviour::Surf)=>println!("I'm surfing!"), + Some(gameplay_attributes::ContactingBehaviour::Cling)=>println!("Unimplemented!"), + &Some(gameplay_attributes::ContactingBehaviour::Elastic(elasticity))=>{ + let reflected_velocity=body.velocity+(body.velocity-incident_velocity)*Planar64::raw(elasticity as i64+1); + set_velocity(body,touching,models,hitbox_mesh,reflected_velocity); + }, + Some(gameplay_attributes::ContactingBehaviour::Ladder(contacting_ladder))=> + if let Some(ladder_settings)=&style.ladder{ + if contacting_ladder.sticky{ + //kill v + //actually you could do this with a booster attribute :thinking: + //it's a little bit different because maybe you want to chain ladders together + set_velocity(body,touching,models,hitbox_mesh,Planar64Vec3::ZERO);//model.velocity + } + //ladder walkstate + let (gravity,target_velocity)=ladder_things(ladder_settings,&contact,touching,models,hitbox_mesh,style,camera,input_state); + let walk_state=ContactMoveState::ladder(ladder_settings,body,gravity,target_velocity,contact); + move_state.set_move_state(MoveState::Ladder(walk_state),body,touching,models,hitbox_mesh,style,camera,input_state); + }, + Some(gameplay_attributes::ContactingBehaviour::NoJump)=>todo!("nyi"), + None=>if let Some(walk_settings)=&style.walk{ + if walk_settings.is_slope_walkable(contact_normal(models,hitbox_mesh,&contact),Planar64Vec3::Y){ + //ground + let (gravity,target_velocity)=ground_things(walk_settings,&contact,touching,models,hitbox_mesh,style,camera,input_state); + let walk_state=ContactMoveState::ground(walk_settings,body,gravity,target_velocity,contact); + move_state.set_move_state(MoveState::Walk(walk_state),body,touching,models,hitbox_mesh,style,camera,input_state); + } + }, + } + //I love making functions with 10 arguments to dodge the borrow checker + run_teleport_behaviour(contact.model_id.into(),attr.general.wormhole.as_ref(),mode,move_state,body,touching,run,mode_state,models,hitbox_mesh,bvh,style,camera,input_state,time); + if style.get_control(Controls::Jump,input_state.controls){ + if let (Some(jump_settings),Some(walk_state))=(&style.jump,move_state.get_walk_state()){ + let jump_dir=walk_state.jump_direction.direction(models,hitbox_mesh,&walk_state.contact); + let jumped_velocity=jump_settings.jumped_velocity(style,jump_dir,body.velocity,attr.general.booster.as_ref()); + move_state.cull_velocity(jumped_velocity,body,touching,models,hitbox_mesh,style,camera,input_state); + } + } + match &attr.general.trajectory{ + Some(trajectory)=>{ + match trajectory{ + gameplay_attributes::SetTrajectory::AirTime(_)=>todo!(), + gameplay_attributes::SetTrajectory::Height(_)=>todo!(), + gameplay_attributes::SetTrajectory::TargetPointTime { target_point: _, time: _ }=>todo!(), + gameplay_attributes::SetTrajectory::TargetPointSpeed { target_point: _, speed: _, trajectory_choice: _ }=>todo!(), + &gameplay_attributes::SetTrajectory::Velocity(velocity)=>{ + move_state.cull_velocity(velocity,body,touching,models,hitbox_mesh,style,camera,input_state); + }, + gameplay_attributes::SetTrajectory::DotVelocity { direction: _, dot: _ }=>todo!(), + } + }, + None=>(), + } + //doing enum to set the acceleration when surfing + //doing input_and_body to refresh the walk state if you hit a wall while accelerating + move_state.apply_enum_and_input_and_body(body,touching,models,hitbox_mesh,style,camera,input_state); } fn collision_start_intersect( - state:&mut PhysicsState, - data:&PhysicsData, + move_state:&mut MoveState, + body:&mut Body, + mode_state:&mut ModeState, + touching:&mut TouchingState, + mode:Option<&gameplay_modes::Mode>, + run:&mut run::Run, + models:&PhysicsModels, + hitbox_mesh:&HitboxMesh, + bvh:&bvh::BvhNode, + style:&StyleModifiers, + camera:&PhysicsCamera, + input_state:&InputState, attr:&gameplay_attributes::IntersectAttributes, intersect:IntersectCollision, + time:Time, ){ - //I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop - state.touching.insert(Collision::Intersect(intersect)); - //insta booster! - if let Some(booster)=&attr.general.booster{ - state.cull_velocity(data,booster.boost(state.body.velocity)); - } - if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){ - let zone=mode.get_zone(intersect.model_id.into()); - match zone{ - Some(gameplay_modes::Zone::Start)=>{ - println!("@@@@ Starting new run!"); - state.run=run::Run::new(); - }, - Some(gameplay_modes::Zone::Finish)=>{ - match state.run.finish(state.time){ - Ok(())=>println!("@@@@ Finished run time={}",state.run.time(state.time)), - Err(e)=>println!("@@@@ Run Finish error:{e:?}"), - } - }, - Some(gameplay_modes::Zone::Anticheat)=>state.run.flag(run::FlagReason::Anticheat), - None=>(), - } - run_teleport_behaviour(&attr.general.wormhole,&data.models,mode,&state.style,&data.hitbox_mesh,&mut state.mode_state,&mut state.touching,&mut state.body,intersect.model_id.into()); - } + //I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop + touching.insert(Collision::Intersect(intersect)); + //insta booster! + if let Some(booster)=&attr.general.booster{ + move_state.cull_velocity(booster.boost(body.velocity),body,touching,models,hitbox_mesh,style,camera,input_state); + } + if let Some(mode)=mode{ + let zone=mode.get_zone(intersect.model_id.into()); + match zone{ + Some(gameplay_modes::Zone::Start)=>{ + println!("@@@@ Starting new run!"); + *run=run::Run::new(); + }, + Some(gameplay_modes::Zone::Finish)=>{ + match run.finish(time){ + Ok(())=>println!("@@@@ Finished run time={}",run.time(time)), + Err(e)=>println!("@@@@ Run Finish error:{e:?}"), + } + }, + Some(gameplay_modes::Zone::Anticheat)=>run.flag(run::FlagReason::Anticheat), + None=>(), + } + } + run_teleport_behaviour(intersect.model_id.into(),attr.general.wormhole.as_ref(),mode,move_state,body,touching,run,mode_state,models,hitbox_mesh,bvh,style,camera,input_state,time); } fn collision_end_contact( - state:&mut PhysicsState, - data:&PhysicsData, + move_state:&mut MoveState, + body:&mut Body, + touching:&mut TouchingState, + models:&PhysicsModels, + hitbox_mesh:&HitboxMesh, + style:&StyleModifiers, + camera:&PhysicsCamera, + input_state:&InputState, _attr:&gameplay_attributes::ContactAttributes, contact:ContactCollision, ){ - state.touching.remove(&Collision::Contact(contact));//remove contact before calling contact_constrain_acceleration - //check ground - //TODO do better - //this is inner code from state.cull_velocity - match state.move_state.get_walk_state(){ - //did you stop touching the thing you were walking on? - Some(walk_state)=>if walk_state.contact==contact{ - state.set_move_state(data,MoveState::Air); - }, - None=>state.apply_enum_and_body(data), - } + touching.remove(&Collision::Contact(contact));//remove contact before calling contact_constrain_acceleration + //check ground + //TODO do better + //this is inner code from move_state.cull_velocity + match move_state.get_walk_state(){ + //did you stop touching the thing you were walking on? + Some(walk_state)=>if walk_state.contact==contact{ + move_state.set_move_state(MoveState::Air,body,touching,models,hitbox_mesh,style,camera,input_state); + }, + None=>move_state.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state), + } } fn collision_end_intersect( - state:&mut PhysicsState, - data:&PhysicsData, + touching:&mut TouchingState, + mode:Option<&gameplay_modes::Mode>, + run:&mut run::Run, _attr:&gameplay_attributes::IntersectAttributes, intersect:IntersectCollision, + time:Time, ){ - state.touching.remove(&Collision::Intersect(intersect)); - if let Some(mode)=data.modes.get_mode(state.mode_state.get_mode_id()){ - let zone=mode.get_zone(intersect.model_id.into()); - match zone{ - Some(gameplay_modes::Zone::Start)=>{ - match state.run.start(state.time){ - Ok(())=>println!("@@@@ Started run"), - Err(e)=>println!("@@@@ Run Start error:{e:?}"), - } - }, - _=>(), - } - } + touching.remove(&Collision::Intersect(intersect)); + if let Some(mode)=mode{ + let zone=mode.get_zone(intersect.model_id.into()); + match zone{ + Some(gameplay_modes::Zone::Start)=>{ + match run.start(time){ + Ok(())=>println!("@@@@ Started run"), + Err(e)=>println!("@@@@ Run Start error:{e:?}"), + } + }, + _=>(), + } + } } fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedInstruction){ state.time=ins.time; @@ -1538,13 +1693,41 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim state.body.advance_time(state.time); } match ins.instruction{ - PhysicsInternalInstruction::CollisionStart(collision)=>match collision{ - Collision::Contact(contact)=>collision_start_contact(state,data,data.models.contact_attr(contact.model_id),contact), - Collision::Intersect(intersect)=>collision_start_intersect(state,data,data.models.intersect_attr(intersect.model_id),intersect), + PhysicsInternalInstruction::CollisionStart(collision)=>{ + let mode=data.modes.get_mode(state.mode_state.get_mode_id()); + match collision{ + Collision::Contact(contact)=>collision_start_contact( + &mut state.move_state,&mut state.body,&mut state.mode_state,&mut state.touching,&mut state.run, + mode, + &data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state, + data.models.contact_attr(contact.model_id), + contact, + state.time, + ), + Collision::Intersect(intersect)=>collision_start_intersect( + &mut state.move_state,&mut state.body,&mut state.mode_state,&mut state.touching, + mode, + &mut state.run,&data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state, + data.models.intersect_attr(intersect.model_id), + intersect, + state.time, + ), + } }, PhysicsInternalInstruction::CollisionEnd(collision)=>match collision{ - Collision::Contact(contact)=>collision_end_contact(state,data,data.models.contact_attr(contact.model_id),contact), - Collision::Intersect(intersect)=>collision_end_intersect(state,data,data.models.intersect_attr(intersect.model_id),intersect), + Collision::Contact(contact)=>collision_end_contact( + &mut state.move_state,&mut state.body,&mut state.touching,&data.models,&data.hitbox_mesh,&state.style,&state.camera,&state.input_state, + data.models.contact_attr(contact.model_id), + contact + ), + Collision::Intersect(intersect)=>collision_end_intersect( + &mut state.touching, + data.modes.get_mode(state.mode_state.get_mode_id()), + &mut state.run, + data.models.intersect_attr(intersect.model_id), + intersect, + state.time + ), }, PhysicsInternalInstruction::StrafeTick=>{ //TODO make this less huge @@ -1667,14 +1850,15 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI }, PhysicsInputInstruction::Restart=>{ //teleport to start zone - let spawn_point=data.modes.get_mode(state.mode_state.get_mode_id()).and_then(|mode| + let mode=data.modes.get_mode(state.mode_state.get_mode_id()); + let spawn_point=mode.and_then(|mode| //TODO: spawn at the bottom of the start zone plus the hitbox size //TODO: set camera andles to face the same way as the start zone data.models.get_model_transform(mode.get_start().into()).map(|transform| transform.vertex.translation ) ).unwrap_or(Planar64Vec3::ZERO); - set_position(&mut state.body,&mut state.touching,spawn_point); + set_position(spawn_point,&mut state.move_state,&mut state.body,&mut state.touching,&mut state.run,&mut state.mode_state,mode,&data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state,state.time); set_velocity(&mut state.body,&state.touching,&data.models,&data.hitbox_mesh,Planar64Vec3::ZERO); state.set_move_state(data,MoveState::Air); b_refresh_walk_target=false; @@ -1682,7 +1866,14 @@ fn atomic_input_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:TimedI PhysicsInputInstruction::Spawn(mode_id,stage_id)=>{ //spawn at a particular stage if let Some(mode)=data.modes.get_mode(mode_id){ - teleport_to_spawn(&mut state.body,&mut state.touching,&state.style,&data.hitbox_mesh,mode,&data.models,stage_id); + if let Some(stage)=mode.get_stage(stage_id){ + let _=teleport_to_spawn( + stage, + &mut state.move_state,&mut state.body,&mut state.touching,&mut state.run,&mut state.mode_state, + mode, + &data.models,&data.hitbox_mesh,&data.bvh,&state.style,&state.camera,&state.input_state,state.time + ); + } } b_refresh_walk_target=false; },