check touching before testing collision

This commit is contained in:
2025-11-19 08:57:53 -08:00
parent fbb047f8d4
commit 2a05d50abb

View File

@@ -614,7 +614,7 @@ impl MoveState{
// TODO: unduplicate this code
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){
Some(walk_state)=>if !touching.contacts.contains_key(&walk_state.contact.convex_mesh_id){
self.set_move_state(MoveState::Air,body,touching,models,hitbox_mesh,style,camera,input_state);
}else{
// stopped touching something else while walking
@@ -753,8 +753,8 @@ impl Collision{
}
#[derive(Clone,Debug,Default)]
struct TouchingState{
contacts:HashSet<ContactCollision>,
intersects:HashSet<IntersectCollision>,
contacts:HashMap<ConvexMeshId<ContactModelId>,model_physics::MinkowskiFace>,
intersects:HashSet<ConvexMeshId<IntersectModelId>>,
}
impl TouchingState{
fn clear(&mut self){
@@ -763,20 +763,20 @@ impl TouchingState{
}
fn insert(&mut self,collision:Collision)->bool{
match collision{
Collision::Contact(collision)=>self.contacts.insert(collision),
Collision::Intersect(collision)=>self.intersects.insert(collision),
Collision::Contact(collision)=>self.contacts.insert(collision.convex_mesh_id,collision.face_id).is_none(),
Collision::Intersect(collision)=>self.intersects.insert(collision.convex_mesh_id),
}
}
fn contains(&self,collision:&Collision)->bool{
match collision{
Collision::Contact(collision)=>self.contacts.contains(collision),
Collision::Intersect(collision)=>self.intersects.contains(collision),
fn contains(&self,convex_mesh_id:&ConvexMeshId<PhysicsModelId>)->bool{
match convex_mesh_id.model_id{
PhysicsModelId::Contact(contact_model_id)=>self.contacts.contains_key(&convex_mesh_id.map(contact_model_id)),
PhysicsModelId::Intersect(intersect_model_id)=>self.intersects.contains(&convex_mesh_id.map(intersect_model_id)),
}
}
fn remove(&mut self,collision:&Collision)->bool{
match collision{
Collision::Contact(collision)=>self.contacts.remove(collision),
Collision::Intersect(collision)=>self.intersects.remove(collision),
fn remove(&mut self,convex_mesh_id:&ConvexMeshId<PhysicsModelId>)->bool{
match convex_mesh_id.model_id{
PhysicsModelId::Contact(contact_model_id)=>self.contacts.remove(&convex_mesh_id.map(contact_model_id)).is_some(),
PhysicsModelId::Intersect(intersect_model_id)=>self.intersects.remove(&convex_mesh_id.map(intersect_model_id)),
}
}
fn base_acceleration(&self,models:&PhysicsModels,style:&StyleModifiers,camera:&PhysicsCamera,input_state:&InputState)->Planar64Vec3{
@@ -785,13 +785,13 @@ impl TouchingState{
a+=rocket_settings.acceleration(style.get_propulsion_control_dir(camera,input_state.controls));
}
//add accelerators
for contact in &self.contacts{
if let Some(accelerator)=&models.contact_attr(contact.convex_mesh_id.model_id).general.accelerator{
for contact in self.contacts.keys(){
if let Some(accelerator)=&models.contact_attr(contact.model_id).general.accelerator{
a+=accelerator.acceleration;
}
}
for intersect in &self.intersects{
if let Some(accelerator)=&models.intersect_attr(intersect.convex_mesh_id.model_id).general.accelerator{
if let Some(accelerator)=&models.intersect_attr(intersect.model_id).general.accelerator{
a+=accelerator.acceleration;
}
}
@@ -799,8 +799,9 @@ impl TouchingState{
a
}
fn constrain_velocity(&self,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,velocity:Planar64Vec3)->Planar64Vec3{
let contacts:Vec<_>=self.contacts.iter().map(|contact|{
let n=contact_normal(models,hitbox_mesh,contact);
let contacts:Vec<_>=self.contacts.iter().map(|(&convex_mesh_id,&face_id)|{
let contact=ContactCollision{face_id,convex_mesh_id};
let n=contact_normal(models,hitbox_mesh,&contact);
crate::push_solve::Contact{
position:vec3::ZERO,
velocity:n,
@@ -810,8 +811,9 @@ impl TouchingState{
crate::push_solve::push_solve(&contacts,velocity)
}
fn constrain_acceleration(&self,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,acceleration:Planar64Vec3)->Planar64Vec3{
let contacts:Vec<_>=self.contacts.iter().map(|contact|{
let n=contact_normal(models,hitbox_mesh,contact);
let contacts:Vec<_>=self.contacts.iter().map(|(&convex_mesh_id,&face_id)|{
let contact=ContactCollision{face_id,convex_mesh_id};
let n=contact_normal(models,hitbox_mesh,&contact);
crate::push_solve::Contact{
position:vec3::ZERO,
velocity:n,
@@ -823,29 +825,29 @@ impl TouchingState{
fn predict_collision_end(&self,collector:&mut instruction::InstructionCollector<InternalInstruction,Time>,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,body:&Body,start_time:Time){
// let relative_body=body.relative_to(&Body::ZERO);
let relative_body=body;
for contact in &self.contacts{
for (convex_mesh_id,face_id) in &self.contacts{
//detect face slide off
let model_mesh=models.contact_mesh(&contact.convex_mesh_id);
let model_mesh=models.contact_mesh(convex_mesh_id);
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)|{
collector.collect(minkowski.predict_collision_face_out(&relative_body,start_time..collector.time(),*face_id).map(|(_face,time)|{
TimedInstruction{
time:relative_body.time+time.into(),
instruction:InternalInstruction::CollisionEnd(
Collision::Contact(*contact),
Collision::Contact(ContactCollision{face_id:*face_id,convex_mesh_id:*convex_mesh_id}),
time
),
}
}));
}
for intersect in &self.intersects{
for convex_mesh_id in &self.intersects{
//detect model collision in reverse
let model_mesh=models.intersect_mesh(&intersect.convex_mesh_id);
let model_mesh=models.intersect_mesh(convex_mesh_id);
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,hitbox_mesh.transformed_mesh());
collector.collect(minkowski.predict_collision_out(&relative_body,start_time..collector.time()).map(|(_face,time)|{
TimedInstruction{
time:relative_body.time+time.into(),
instruction:InternalInstruction::CollisionEnd(
Collision::Intersect(*intersect),
Collision::Intersect(IntersectCollision{convex_mesh_id:*convex_mesh_id}),
time
),
}
@@ -1199,24 +1201,23 @@ impl<'a> PhysicsContext<'a>{
//relative to moving platforms
//let relative_body=state.body.relative_to(&Body::ZERO);
let relative_body=&state.body;
data.bvh.sample_aabb(&aabb,&mut |&convex_mesh_id|{
data.bvh.sample_aabb(&aabb,&mut |convex_mesh_id|{
if state.touching.contains(convex_mesh_id){
return;
}
//no checks are needed because of the time limits.
let model_mesh=data.models.mesh(convex_mesh_id);
let model_mesh=data.models.mesh(*convex_mesh_id);
let minkowski=model_physics::MinkowskiMesh::minkowski_sum(model_mesh,data.hitbox_mesh.transformed_mesh());
collector.collect(minkowski.predict_collision_in(relative_body,state.time..collector.time())
.and_then(|(face,dt)|{
let collision=Collision::new(convex_mesh_id,face);
// filter objects already in contacts
(!state.touching.contains(&collision)).then(||
TimedInstruction{
time:relative_body.time+dt.into(),
instruction:InternalInstruction::CollisionStart(
collision,
dt
)
}
)
})
.map(|(face,dt)|
TimedInstruction{
time:relative_body.time+dt.into(),
instruction:InternalInstruction::CollisionStart(
Collision::new(*convex_mesh_id,face),
dt
)
}
)
);
});
collector.take()
@@ -1249,10 +1250,12 @@ fn recalculate_touching(
//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(){
while let Some((&convex_mesh_id,&face_id))=touching.contacts.iter().next(){
let contact=ContactCollision{face_id,convex_mesh_id};
collision_end_contact(move_state,body,touching,models,hitbox_mesh,style,camera,input_state,models.contact_attr(contact.convex_mesh_id.model_id),contact)
}
while let Some(&intersect)=touching.intersects.iter().next(){
while let Some(&convex_mesh_id)=touching.intersects.iter().next(){
let intersect=IntersectCollision{convex_mesh_id};
collision_end_intersect(move_state,body,touching,models,hitbox_mesh,style,camera,input_state,mode,run,models.intersect_attr(intersect.convex_mesh_id.model_id),intersect,time);
}
//find all models in the teleport region
@@ -1309,8 +1312,9 @@ fn set_position(
fn set_velocity_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,v:Planar64Vec3)->bool{
//This is not correct but is better than what I have
let mut culled=false;
touching.contacts.retain(|contact|{
let n=contact_normal(models,hitbox_mesh,contact);
touching.contacts.retain(|&convex_mesh_id,&mut face_id|{
let contact=ContactCollision{face_id,convex_mesh_id};
let n=contact_normal(models,hitbox_mesh,&contact);
let r=n.dot(v).is_positive();
if r{
culled=true;
@@ -1327,8 +1331,9 @@ fn set_velocity(body:&mut Body,touching:&TouchingState,models:&PhysicsModels,hit
fn set_acceleration_cull(body:&mut Body,touching:&mut TouchingState,models:&PhysicsModels,hitbox_mesh:&HitboxMesh,a:Planar64Vec3)->bool{
//This is not correct but is better than what I have
let mut culled=false;
touching.contacts.retain(|contact|{
let n=contact_normal(models,hitbox_mesh,contact);
touching.contacts.retain(|&convex_mesh_id,&mut face_id|{
let contact=ContactCollision{face_id,convex_mesh_id};
let n=contact_normal(models,hitbox_mesh,&contact);
let r=n.dot(a).is_positive();
if r{
culled=true;
@@ -1681,7 +1686,7 @@ fn collision_end_contact(
_attr:&gameplay_attributes::ContactAttributes,
contact:ContactCollision,
){
touching.remove(&Collision::Contact(contact));//remove contact before calling contact_constrain_acceleration
touching.contacts.remove(&contact.convex_mesh_id);//remove contact before calling contact_constrain_acceleration
//check ground
//TODO do better
//this is inner code from move_state.cull_velocity
@@ -1712,7 +1717,7 @@ fn collision_end_intersect(
intersect:IntersectCollision,
time:Time,
){
touching.remove(&Collision::Intersect(intersect));
touching.intersects.remove(&intersect.convex_mesh_id);
move_state.apply_enum_and_body(body,touching,models,hitbox_mesh,style,camera,input_state);
if let Some(mode)=mode{
let zone=mode.get_zone(intersect.convex_mesh_id.model_id.into());