diff --git a/engine/physics/src/physics.rs b/engine/physics/src/physics.rs index b226795..6750e23 100644 --- a/engine/physics/src/physics.rs +++ b/engine/physics/src/physics.rs @@ -26,6 +26,8 @@ use strafesnet_common::physics::{Instruction,MouseInstruction,ModeInstruction,Mi #[derive(Debug)] pub enum InternalInstruction{ CollisionStart(Collision,model_physics::GigaTime), + // transfer to a flush minkowski face + CollisionTransfer(ContactCollision,model_physics::MinkowskiFace), CollisionEnd(Collision,model_physics::GigaTime), StrafeTick, ReachWalkTargetVelocity, @@ -785,19 +787,40 @@ impl TouchingState{ crate::push_solve::push_solve(&contacts,acceleration) } fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<InternalInstruction,Time>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,start_time:Time){ + use model_physics::DirectedEdge; // let relative_body=body.relative_to(&Body::ZERO); let relative_body=body; for contact in &self.contacts{ //detect face slide off let model_mesh=models.contact_mesh(contact); let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh()); - collector.collect(minkowski.predict_collision_face_out(&relative_body,start_time..collector.time(),contact.face_id).map(|(_face,time)|{ - TimedInstruction{ - time:relative_body.time+time.into(), - instruction:InternalInstruction::CollisionEnd( - Collision::Contact(*contact), - time - ), + collector.collect(minkowski.predict_collision_face_out(&relative_body,start_time..collector.time(),contact.face_id).map(|(out_edge,time)|{ + // TODO: determine if this code should go inside predict_collision_face_out + // check if the face across the out_edge is flush to contact.face_id + let (src_face_n,_src_face_d)=minkowski.face_nd(contact.face_id); + // the face across may be left or right depending on the directed edge parity + let dst_face=minkowski.edge_faces(out_edge.as_undirected()).as_ref()[!out_edge.parity() as usize]; + let (dst_face_n,_dst_face_d)=minkowski.face_nd(dst_face); + // are they exactly flush + if src_face_n.cross(dst_face_n)==vec3::ZERO_6 + // implicitly don't need to check d values because faces share two vertices + // && n0*d1==n1*d0 + { + TimedInstruction{ + time:relative_body.time+time.into(), + instruction:InternalInstruction::CollisionTransfer( + *contact, + dst_face, + ), + } + }else{ + TimedInstruction{ + time:relative_body.time+time.into(), + instruction:InternalInstruction::CollisionEnd( + Collision::Contact(*contact), + time + ), + } } })); } @@ -1656,6 +1679,7 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim |InternalInstruction::CollisionEnd(_,dt)=>(true,Some(dt)), InternalInstruction::StrafeTick |InternalInstruction::ReachWalkTargetVelocity=>(true,None), + InternalInstruction::CollisionTransfer(..)=>(false,None), }; if should_advance_body{ match goober_time{ @@ -1700,6 +1724,15 @@ fn atomic_internal_instruction(state:&mut PhysicsState,data:&PhysicsData,ins:Tim state.time ), }, + InternalInstruction::CollisionTransfer(collision,dst_face)=>{ + // transfer to a flush surface of the same object + state.touching.contacts.remove(&collision); + state.touching.contacts.insert(ContactCollision{ + face_id:dst_face, + model_id:collision.model_id, + submesh_id:collision.submesh_id, + }); + }, InternalInstruction::StrafeTick=>{ //TODO make this less huge if let Some(strafe_settings)=&state.style.strafe{