runtime attributes + implement model intersection (but not collision end)

This commit is contained in:
Quaternions 2023-10-04 14:15:04 -07:00
parent fb2e2afeb9
commit b8f13539db
2 changed files with 102 additions and 36 deletions

View File

@ -221,13 +221,13 @@ impl Camera {
} }
pub struct GameMechanicsState{ pub struct GameMechanicsState{
pub spawn_id:u32, pub stage_id:u32,
//jump_counts:HashMap<u32,u32>, //jump_counts:HashMap<u32,u32>,
} }
impl std::default::Default for GameMechanicsState{ impl std::default::Default for GameMechanicsState{
fn default() -> Self { fn default() -> Self {
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 world:WorldState,//currently there is only one state the world can be in
pub game:GameMechanicsState, pub game:GameMechanicsState,
pub style:StyleModifiers, pub style:StyleModifiers,
pub contacts:std::collections::HashSet::<RelativeCollision>, pub contacts:std::collections::HashMap::<u32,RelativeCollision>,
pub intersects:std::collections::HashMap::<u32,RelativeCollision>,
//pub intersections: Vec<ModelId>, //pub intersections: Vec<ModelId>,
//camera must exist in state because wormholes modify the camera, also camera punch //camera must exist in state because wormholes modify the camera, also camera punch
pub camera:Camera, 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 //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. //in this iteration, all it needs is extents.
mesh: TreyMesh, mesh: TreyMesh,
transform:glam::Affine3A,
attributes:PhysicsCollisionAttributes, attributes:PhysicsCollisionAttributes,
} }
@ -471,6 +473,7 @@ impl ModelPhysics {
Self{ Self{
mesh:aabb, mesh:aabb,
attributes, attributes,
transform:transform.clone(),
} }
} }
pub fn from_model(model:&crate::model::IndexedModel,instance:&crate::model::ModelInstance) -> Option<Self> { pub fn from_model(model:&crate::model::IndexedModel,instance:&crate::model::ModelInstance) -> Option<Self> {
@ -557,6 +560,8 @@ impl PhysicsState {
pub fn clear(&mut self){ pub fn clear(&mut self){
self.models.clear(); self.models.clear();
self.modes.clear(); self.modes.clear();
self.contacts.clear();
self.intersects.clear();
} }
pub fn get_mode(&self,mode_id:u32)->Option<&crate::model::ModeDescription>{ pub fn get_mode(&self,mode_id:u32)->Option<&crate::model::ModeDescription>{
if let Some(&mode)=self.mode_from_mode_id.get(&mode_id){ 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){ 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 n=contact.normal(&self.models);
let d=velocity.dot(n); let d=velocity.dot(n);
if d<0f32{ if d<0f32{
@ -600,7 +605,7 @@ impl PhysicsState {
} }
} }
fn contact_constrain_acceleration(&self,acceleration:&mut glam::Vec3){ 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 n=contact.normal(&self.models);
let d=acceleration.dot(n); let d=acceleration.dot(n);
if d<0f32{ if d<0f32{
@ -973,12 +978,19 @@ impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState
//JUST POLLING!!! NO MUTATION //JUST POLLING!!! NO MUTATION
let mut collector = crate::instruction::InstructionCollector::new(time_limit); let mut collector = crate::instruction::InstructionCollector::new(time_limit);
//check for collision stop instructions with curent contacts //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)); 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!!) //check for collision start instructions (against every part in the game with no optimization!!)
for i in 0..self.models.len() { 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 { if self.grounded {
//walk maintenance //walk maintenance
@ -1013,37 +1025,90 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
self.spawn_point=position; self.spawn_point=position;
} }
PhysicsInstruction::CollisionStart(c) => { PhysicsInstruction::CollisionStart(c) => {
//check ground let model=c.model(&self.models).unwrap();
match &c.face { match &model.attributes{
AabbFace::Top => { PhysicsCollisionAttributes::Contact{contacting,general}=>{
//ground match &contacting.surf{
self.grounded=true; Some(surf)=>println!("I'm surfing!"),
}, None=>match &c.face {
_ => (), AabbFace::Top => {
} //ground
self.contacts.insert(c); self.grounded=true;
//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){ match &general.booster{
self.jump(); Some(booster)=>self.body.velocity+=booster.velocity,
None=>(),
}
match &general.stage_element{
Some(stage_element)=>{
if stage_element.force||self.game.stage_id<stage_element.stage_id{
self.game.stage_id=stage_element.stage_id;
}
match stage_element.behaviour{
crate::model::StageElementBehaviour::SpawnAt=>(),
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) => { PhysicsInstruction::CollisionEnd(c) => {
self.contacts.remove(&c);//remove contact before calling contact_constrain_acceleration let model=c.model(&self.models).unwrap();
let mut a=self.style.gravity; match &model.attributes{
self.contact_constrain_acceleration(&mut a); PhysicsCollisionAttributes::Contact{contacting,general}=>{
self.body.acceleration=a; self.contacts.remove(&c.model);//remove contact before calling contact_constrain_acceleration
//check ground let mut a=self.style.gravity;
match &c.face { self.contact_constrain_acceleration(&mut a);
AabbFace::Top => { self.body.acceleration=a;
self.grounded=false; //check ground
}, match &c.face {
_ => (), AabbFace::Top => {
} self.grounded=false;
self.refresh_walk_target(); },
_ => (),
}
self.refresh_walk_target();
},
PhysicsCollisionAttributes::Intersect{intersecting,general}=>{
self.intersects.remove(&c.model);
},
}
}, },
PhysicsInstruction::StrafeTick => { PhysicsInstruction::StrafeTick => {
let camera_mat=self.camera.simulate_move_rotation_y(self.mouse_interpolation.interpolated_position(self.time).x-self.mouse_interpolation.mouse0.x); let camera_mat=self.camera.simulate_move_rotation_y(self.mouse_interpolation.interpolated_position(self.time).x-self.mouse_interpolation.mouse0.x);

View File

@ -589,7 +589,8 @@ impl framework::Example for GlobalState {
time: 0, time: 0,
style:body::StyleModifiers::default(), style:body::StyleModifiers::default(),
grounded: false, grounded: false,
contacts: std::collections::HashSet::new(), contacts: std::collections::HashMap::new(),
intersects: std::collections::HashMap::new(),
models: Vec::new(), models: Vec::new(),
walk: body::WalkState::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)), camera: body::Camera::from_offset(glam::vec3(0.0,4.5-2.5,0.0),(config.width as f32)/(config.height as f32)),