diff --git a/src/body.rs b/src/body.rs index c05480e9..71f089fc 100644 --- a/src/body.rs +++ b/src/body.rs @@ -221,13 +221,13 @@ impl Camera { } pub struct GameMechanicsState{ - pub spawn_id:u32, + pub stage_id:u32, //jump_counts:HashMap, } impl std::default::Default for GameMechanicsState{ fn default() -> Self { Self{ - spawn_id:0, + stage_id:0, } } } @@ -317,7 +317,8 @@ pub struct PhysicsState{ pub world:WorldState,//currently there is only one state the world can be in pub game:GameMechanicsState, pub style:StyleModifiers, - pub contacts:std::collections::HashSet::, + pub contacts:std::collections::HashMap::, + pub intersects:std::collections::HashMap::, //pub intersections: Vec, //camera must exist in state because wormholes modify the camera, also camera punch pub camera:Camera, @@ -459,6 +460,7 @@ pub struct ModelPhysics { //A model is a thing that has a hitbox. can be represented by a list of TreyMesh-es //in this iteration, all it needs is extents. mesh: TreyMesh, + transform:glam::Affine3A, attributes:PhysicsCollisionAttributes, } @@ -471,6 +473,7 @@ impl ModelPhysics { Self{ mesh:aabb, attributes, + transform:transform.clone(), } } pub fn from_model(model:&crate::model::IndexedModel,instance:&crate::model::ModelInstance) -> Option { @@ -557,6 +560,8 @@ impl PhysicsState { pub fn clear(&mut self){ self.models.clear(); self.modes.clear(); + self.contacts.clear(); + self.intersects.clear(); } pub fn get_mode(&self,mode_id:u32)->Option<&crate::model::ModeDescription>{ if let Some(&mode)=self.mode_from_mode_id.get(&mode_id){ @@ -591,7 +596,7 @@ impl PhysicsState { } fn contact_constrain_velocity(&self,velocity:&mut glam::Vec3){ - for contact in self.contacts.iter() { + for (_,contact) in &self.contacts { let n=contact.normal(&self.models); let d=velocity.dot(n); if d<0f32{ @@ -600,7 +605,7 @@ impl PhysicsState { } } fn contact_constrain_acceleration(&self,acceleration:&mut glam::Vec3){ - for contact in self.contacts.iter() { + for (_,contact) in &self.contacts { let n=contact.normal(&self.models); let d=acceleration.dot(n); if d<0f32{ @@ -973,12 +978,19 @@ impl crate::instruction::InstructionEmitter for PhysicsState //JUST POLLING!!! NO MUTATION let mut collector = crate::instruction::InstructionCollector::new(time_limit); //check for collision stop instructions with curent contacts - for collision_data in self.contacts.iter() { + for (_,collision_data) in &self.contacts { collector.collect(self.predict_collision_end(self.time,time_limit,collision_data)); } + // for collision_data in &self.intersects{ + // collector.collect(self.predict_collision_end2(self.time,time_limit,collision_data)); + // } //check for collision start instructions (against every part in the game with no optimization!!) for i in 0..self.models.len() { - collector.collect(self.predict_collision_start(self.time,time_limit,i as u32)); + let i=i as u32; + if self.contacts.contains_key(&i)||self.intersects.contains_key(&i){ + continue; + } + collector.collect(self.predict_collision_start(self.time,time_limit,i)); } if self.grounded { //walk maintenance @@ -1013,37 +1025,90 @@ impl crate::instruction::InstructionConsumer for PhysicsStat self.spawn_point=position; } PhysicsInstruction::CollisionStart(c) => { - //check ground - match &c.face { - AabbFace::Top => { - //ground - self.grounded=true; - }, - _ => (), - } - self.contacts.insert(c); - //flatten v - let mut v=self.body.velocity; - self.contact_constrain_velocity(&mut v); - self.body.velocity=v; - if self.grounded&&self.style.get_control(StyleModifiers::CONTROL_JUMP,self.controls){ - self.jump(); + let model=c.model(&self.models).unwrap(); + match &model.attributes{ + PhysicsCollisionAttributes::Contact{contacting,general}=>{ + match &contacting.surf{ + Some(surf)=>println!("I'm surfing!"), + None=>match &c.face { + AabbFace::Top => { + //ground + self.grounded=true; + }, + _ => (), + }, + } + match &general.booster{ + Some(booster)=>self.body.velocity+=booster.velocity, + None=>(), + } + match &general.stage_element{ + Some(stage_element)=>{ + if stage_element.force||self.game.stage_id(), + crate::model::StageElementBehaviour::Trigger + |crate::model::StageElementBehaviour::Teleport=>{ + //TODO make good + if let Some(mode)=self.get_mode(stage_element.mode_id){ + if let Some(&spawn)=mode.get_spawn_model_id(self.game.stage_id){ + if let Some(model)=self.models.get(spawn as usize){ + self.body.position=model.transform.transform_point3(glam::Vec3::Y)+glam::Vec3::Y*(self.style.hitbox_halfsize.y+0.1); + //manual clear //for c in self.contacts{process_instruction(CollisionEnd(c))} + self.contacts.clear(); + self.intersects.clear(); + self.body.acceleration=self.style.gravity; + self.walk.state=WalkEnum::Reached; + self.grounded=false; + }else{println!("bad1");} + }else{println!("bad2");} + }else{println!("bad3");} + }, + crate::model::StageElementBehaviour::Platform=>(), + } + }, + None=>(), + } + //check ground + self.contacts.insert(c.model,c); + //flatten v + let mut v=self.body.velocity; + self.contact_constrain_velocity(&mut v); + self.body.velocity=v; + if self.grounded&&self.style.get_control(StyleModifiers::CONTROL_JUMP,self.controls){ + self.jump(); + } + self.refresh_walk_target(); + }, + PhysicsCollisionAttributes::Intersect{intersecting,general}=>{ + //I think that setting the velocity to 0 was preventing surface contacts from entering an infinite loop + self.intersects.insert(c.model,c); + }, } - self.refresh_walk_target(); }, PhysicsInstruction::CollisionEnd(c) => { - self.contacts.remove(&c);//remove contact before calling contact_constrain_acceleration - let mut a=self.style.gravity; - self.contact_constrain_acceleration(&mut a); - self.body.acceleration=a; - //check ground - match &c.face { - AabbFace::Top => { - self.grounded=false; - }, - _ => (), - } - self.refresh_walk_target(); + let model=c.model(&self.models).unwrap(); + match &model.attributes{ + PhysicsCollisionAttributes::Contact{contacting,general}=>{ + self.contacts.remove(&c.model);//remove contact before calling contact_constrain_acceleration + let mut a=self.style.gravity; + self.contact_constrain_acceleration(&mut a); + self.body.acceleration=a; + //check ground + match &c.face { + AabbFace::Top => { + self.grounded=false; + }, + _ => (), + } + self.refresh_walk_target(); + }, + PhysicsCollisionAttributes::Intersect{intersecting,general}=>{ + self.intersects.remove(&c.model); + }, + } }, PhysicsInstruction::StrafeTick => { let camera_mat=self.camera.simulate_move_rotation_y(self.mouse_interpolation.interpolated_position(self.time).x-self.mouse_interpolation.mouse0.x); diff --git a/src/main.rs b/src/main.rs index a2317369..2cb478ab 100644 --- a/src/main.rs +++ b/src/main.rs @@ -589,7 +589,8 @@ impl framework::Example for GlobalState { time: 0, style:body::StyleModifiers::default(), grounded: false, - contacts: std::collections::HashSet::new(), + contacts: std::collections::HashMap::new(), + intersects: std::collections::HashMap::new(), models: Vec::new(), walk: body::WalkState::new(), camera: body::Camera::from_offset(glam::vec3(0.0,4.5-2.5,0.0),(config.width as f32)/(config.height as f32)),