diff --git a/src/integer.rs b/src/integer.rs index 1f39b6a..9a00886 100644 --- a/src/integer.rs +++ b/src/integer.rs @@ -1,5 +1,5 @@ //integer units -#[derive(Clone,Copy,Hash,PartialEq,PartialOrd,Debug)] +#[derive(Clone,Copy,Hash,Eq,PartialEq,PartialOrd,Debug)] pub struct Time(i64); impl Time{ pub const ZERO:Self=Self(0); @@ -800,7 +800,7 @@ impl std::ops::Div for Planar64Vec3{ } ///[-1.0,1.0] = [-2^32,2^32] -#[derive(Clone,Copy)] +#[derive(Clone,Copy,Hash,Eq,PartialEq)] pub struct Planar64Mat3{ x_axis:Planar64Vec3, y_axis:Planar64Vec3, @@ -916,7 +916,7 @@ impl std::ops::Div for Planar64Mat3{ } ///[-1.0,1.0] = [-2^32,2^32] -#[derive(Clone,Copy,Default)] +#[derive(Clone,Copy,Default,Hash,Eq,PartialEq)] pub struct Planar64Affine3{ pub matrix3:Planar64Mat3,//includes scale above 1 pub translation:Planar64Vec3, diff --git a/src/model.rs b/src/model.rs index 553f08c..4a1c40c 100644 --- a/src/model.rs +++ b/src/model.rs @@ -83,11 +83,11 @@ pub enum TempIndexedAttributes{ } //you have this effect while in contact -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub struct ContactingLadder{ pub sticky:bool } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub enum ContactingBehaviour{ Surf, Cling,//usable as a zipline, or other weird and wonderful things @@ -95,24 +95,24 @@ pub enum ContactingBehaviour{ Elastic(u32),//[1/2^32,1] 0=None (elasticity+1)/2^32 } //you have this effect while intersecting -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub struct IntersectingWater{ pub viscosity:Planar64, pub density:Planar64, pub current:Planar64Vec3, } //All models can be given these attributes -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub struct GameMechanicAccelerator{ pub acceleration:Planar64Vec3 } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub enum GameMechanicBooster{ Affine(Planar64Affine3),//capable of SetVelocity,DotVelocity,normal booster,bouncy part,redirect velocity, and much more Velocity(Planar64Vec3),//straight up boost velocity adds to your current velocity Energy{direction:Planar64Vec3,energy:Planar64},//increase energy in direction } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub enum GameMechanicCheckpoint{ Ordered{ mode_id:u32, @@ -122,12 +122,12 @@ pub enum GameMechanicCheckpoint{ mode_id:u32, }, } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub enum TrajectoryChoice{ HighArcLongDuration,//underhand lob at target: less horizontal speed and more air time LowArcShortDuration,//overhand throw at target: more horizontal speed and less air time } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub enum GameMechanicSetTrajectory{ AirTime(Time),//air time (relative to gravity direction) is invariant across mass and gravity changes Height(Planar64),//boost height (relative to gravity direction) is invariant across mass and gravity changes @@ -143,14 +143,14 @@ pub enum GameMechanicSetTrajectory{ Velocity(Planar64Vec3),//SetVelocity DotVelocity{direction:Planar64Vec3,dot:Planar64},//set your velocity in a specific direction without touching other directions } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub enum ZoneBehaviour{ //Start is indexed //Checkpoints are indexed Finish, Anitcheat, } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub struct GameMechanicZone{ pub mode_id:u32, pub behaviour:ZoneBehaviour, @@ -161,7 +161,7 @@ pub struct GameMechanicZone{ // InRange(Planar64,Planar64), // OutsideRange(Planar64,Planar64), // } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub enum StageElementBehaviour{ //Spawn,//The behaviour of stepping on a spawn setting the spawnid SpawnAt, @@ -178,14 +178,14 @@ pub enum StageElementBehaviour{ JumpLimit(u32), //Speedtrap(TrapCondition),//Acts as a trigger with a speed condition } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub struct GameMechanicStageElement{ pub mode_id:u32, pub stage_id:u32,//which spawn to send to pub force:bool,//allow setting to lower spawn id i.e. 7->3 pub behaviour:StageElementBehaviour } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub struct GameMechanicWormhole{ //destination does not need to be another wormhole //this defines a one way portal to a destination model transform @@ -193,13 +193,13 @@ pub struct GameMechanicWormhole{ pub destination_model_id:u32, //(position,angles)*=origin.transform.inverse()*destination.transform } -#[derive(Clone)] +#[derive(Clone,Hash,Eq,PartialEq)] pub enum TeleportBehaviour{ StageElement(GameMechanicStageElement), Wormhole(GameMechanicWormhole), } //attributes listed in order of handling -#[derive(Default,Clone)] +#[derive(Default,Clone,Hash,Eq,PartialEq)] pub struct GameMechanicAttributes{ pub zone:Option, pub booster:Option, @@ -218,7 +218,7 @@ impl GameMechanicAttributes{ ||self.accelerator.is_some() } } -#[derive(Default,Clone)] +#[derive(Default,Clone,Hash,Eq,PartialEq)] pub struct ContactingAttributes{ //friction? pub contact_behaviour:Option, @@ -228,7 +228,7 @@ impl ContactingAttributes{ self.contact_behaviour.is_some() } } -#[derive(Default,Clone)] +#[derive(Default,Clone,Hash,Eq,PartialEq)] pub struct IntersectingAttributes{ pub water:Option, } diff --git a/src/model_physics.rs b/src/model_physics.rs index 7690a6e..6c0046a 100644 --- a/src/model_physics.rs +++ b/src/model_physics.rs @@ -20,6 +20,11 @@ struct Face{ normal:Planar64Vec3, dot:Planar64, } +impl Face{ + fn nd(&self)->(Planar64Vec3,Planar64){ + (self.normal,self.dot) + } +} struct Vert(Planar64Vec3); struct FaceRefs{ edges:Vec<(EdgeId,FaceId)>, @@ -171,22 +176,23 @@ impl PhysicsMesh{ pub fn verts<'a>(&'a self)->impl Iterator+'a{ self.verts.iter().map(|Vert(pos)|*pos) } - pub fn brute_t(&self,body:&crate::physics::Body,time_limit:crate::integer::Time)->Option<(FaceId,crate::integer::Time)>{ + pub fn brute(&self,body:&crate::physics::Body,time_limit:crate::integer::Time)->Option<(FaceId,crate::integer::Time)>{ //check each face let mut best_time=time_limit; let mut best_face=None; - for (i,f) in self.face_topology.iter().enumerate(){ - let (n,d)=self.face_nd(FaceId(i)); + for (i,face) in self.faces.iter().enumerate(){ + let face_id=FaceId(i); + let (n,d)=face.nd(); for t in crate::zeroes::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ let t=body.time+crate::integer::Time::from(t); if body.time{ normal_transform:&'a crate::integer::Planar64Mat3, normal_determinant:Planar64, } +impl TransformedMesh<'_>{ + pub fn brute_in(&self,body:&crate::physics::Body,time_limit:crate::integer::Time)->Option<(FaceId,crate::integer::Time)>{ + //check each face + let mut best_time=time_limit; + let mut best_face=None; + for i in 0..self.mesh.faces.len(){ + let face_id=FaceId(i); + let (n,d)=self.face_nd(face_id); + for t in crate::zeroes::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ + let t=body.time+crate::integer::Time::from(t); + if body.timeOption<(FaceId,crate::integer::Time)>{ + //check each face + let mut best_time=time_limit; + let mut best_face=None; + for i in 0..self.mesh.faces.len(){ + let face_id=FaceId(i); + let (n,d)=self.face_nd(face_id); + for t in crate::zeroes::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ + let t=body.time+crate::integer::Time::from(t); + if body.timePlanar64::ZERO{ + let p=body.extrapolated_position(t); + if self.face_edges(face_id).iter().all(|&(_,face_id)|{ + let (n,d)=self.face_nd(face_id); + n.dot(p)<=d + }){ + best_time=t; + best_face=Some(face_id); + } + } + } + } + best_face.map(|f|(f,best_time)) + } + pub fn brute_out_face(&self,body:&crate::physics::Body,time_limit:crate::integer::Time,face_id:FaceId)->Option<(FaceId,crate::integer::Time)>{ + //check each face + let mut best_time=time_limit; + let mut best_face=None; + for &(edge_id,face_id) in self.mesh.face_edges(face_id).iter(){ + let (n,d)=self.face_nd(face_id); + for t in crate::zeroes::zeroes2((n.dot(body.position)-d)*2,n.dot(body.velocity)*2,n.dot(body.acceleration)){ + let t=body.time+crate::integer::Time::from(t); + if body.timePlanar64::ZERO{ + best_time=t; + best_face=Some(face_id); + } + } + } + best_face.map(|f|(f,best_time)) + } +} impl MeshQuery for TransformedMesh<'_>{ fn closest_fev(&self,point:Planar64Vec3)->FEV{ //TODO: put some genius code right here @@ -405,6 +475,7 @@ impl MeshQuery for MinkowskiMesh<'_>{ }).collect()) }, MinkowskiFace::EdgeEdge(e0,e1)=>{ + /* let e0v=self.mesh0.edge_verts(e0); let e1v=self.mesh1.edge_verts(e1); let [r0,r1]=e0v.map(|vert_id0|{ @@ -427,6 +498,8 @@ impl MeshQuery for MinkowskiMesh<'_>{ (MinkowskiEdge::EdgeVert(e0,vert_id1),MinkowskiFace::VertFace(v0,face_id1)) }); Cow::Owned(vec![r0,r1,r2,r3]) + */ + todo!() }, MinkowskiFace::VertFace(v0,f1)=>{ Cow::Owned(self.mesh1.face_edges(f1).iter().map(|&(edge_id1,face_id1)|{ diff --git a/src/physics.rs b/src/physics.rs index d13f6a1..0ff44c9 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -85,15 +85,12 @@ struct WalkState{ impl WalkEnum{ //args going crazy //(walk_enum,body.acceleration)=with_target_velocity(); - fn with_target_velocity(touching:&TouchingState,body:&Body,style:&StyleModifiers,models:&PhysicsModels,mut velocity:Planar64Vec3,normal:&Planar64Vec3)->(WalkEnum,Planar64Vec3){ - touching.constrain_velocity(models,&mut velocity); + fn with_target_velocity(body:&Body,style:&StyleModifiers,models:&PhysicsModels,velocity:Planar64Vec3,normal:&Planar64Vec3)->(WalkEnum,Planar64Vec3){ let mut target_diff=velocity-body.velocity; //remove normal component target_diff-=normal.clone()*(normal.dot(target_diff)/normal.dot(normal.clone())); if target_diff==Planar64Vec3::ZERO{ - let mut a=Planar64Vec3::ZERO; - touching.constrain_acceleration(models,&mut a); - (WalkEnum::Reached,a) + (WalkEnum::Reached,Planar64Vec3::ZERO) }else{ //normal friction acceleration is clippedAcceleration.dot(normal)*friction let diff_len=target_diff.length(); @@ -105,21 +102,20 @@ impl WalkEnum{ let accel=style.walk_accel.min(style.gravity.dot(Planar64Vec3::NEG_Y)*friction); let time_delta=diff_len/accel; let mut a=target_diff.with_length(accel); - touching.constrain_acceleration(models,&mut a); (WalkEnum::Transient(WalkTarget{velocity,time:body.time+Time::from(time_delta)}),a) } } } impl WalkState{ fn ground(touching:&TouchingState,body:&Body,style:&StyleModifiers,models:&PhysicsModels,velocity:Planar64Vec3)->(Self,Planar64Vec3){ - let (walk_enum,a)=WalkEnum::with_target_velocity(touching,body,style,models,velocity,&Planar64Vec3::Y); + let (walk_enum,a)=WalkEnum::with_target_velocity(body,style,models,velocity,&Planar64Vec3::Y); (Self{ state:walk_enum, normal:Planar64Vec3::Y, },a) } fn ladder(touching:&TouchingState,body:&Body,style:&StyleModifiers,models:&PhysicsModels,velocity:Planar64Vec3,normal:&Planar64Vec3)->(Self,Planar64Vec3){ - let (walk_enum,a)=WalkEnum::with_target_velocity(touching,body,style,models,velocity,normal); + let (walk_enum,a)=WalkEnum::with_target_velocity(body,style,models,velocity,normal); (Self{ state:walk_enum, normal:normal.clone(), @@ -208,8 +204,10 @@ impl PhysicsModels{ self.models.push(model); model_id } - fn push_attr(&mut self,attr:PhysicsCollisionAttributes){ + fn push_attr(&mut self,attr:PhysicsCollisionAttributes)->usize{ + let attr_id=self.attributes.len(); self.attributes.push(attr); + attr_id } } @@ -339,6 +337,7 @@ struct StyleModifiers{ swim_speed:Planar64, mass:Planar64, mv:Planar64, + surf_slope:Option, rocket_force:Option, gravity:Planar64Vec3, hitbox_halfsize:Planar64Vec3, @@ -386,6 +385,7 @@ impl StyleModifiers{ ladder_accel:Planar64::int(160), ladder_dot:(Planar64::int(1)/2).sqrt(), swim_speed:Planar64::int(12), + surf_slope:Some(Planar64::raw(7)/8), hitbox_halfsize:Planar64Vec3::int(2,5,2)/2, camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2 } @@ -414,6 +414,7 @@ impl StyleModifiers{ ladder_accel:Planar64::int(180), ladder_dot:(Planar64::int(1)/2).sqrt(), swim_speed:Planar64::int(12), + surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75 hitbox_halfsize:Planar64Vec3::int(2,5,2)/2, camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2 } @@ -441,6 +442,7 @@ impl StyleModifiers{ ladder_accel:Planar64::int(180), ladder_dot:(Planar64::int(1)/2).sqrt(), swim_speed:Planar64::int(12), + surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75 hitbox_halfsize:Planar64Vec3::int(2,5,2)/2, camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2 } @@ -469,6 +471,7 @@ impl StyleModifiers{ ladder_accel:Planar64::int(180),//? ladder_dot:(Planar64::int(1)/2).sqrt(),//? swim_speed:Planar64::int(12),//? + surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75 hitbox_halfsize:Planar64Vec3::raw(33<<28,73<<28,33<<28)/2, camera_offset:Planar64Vec3::raw(0,(64<<28)-(73<<27),0), } @@ -496,6 +499,7 @@ impl StyleModifiers{ ladder_accel:Planar64::int(180),//? ladder_dot:(Planar64::int(1)/2).sqrt(),//? swim_speed:Planar64::int(12),//? + surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75 hitbox_halfsize:Planar64Vec3::raw(33<<28,73<<28,33<<28)/2, camera_offset:Planar64Vec3::raw(0,(64<<28)-(73<<27),0), } @@ -519,6 +523,7 @@ impl StyleModifiers{ ladder_accel:Planar64::int(180), ladder_dot:(Planar64::int(1)/2).sqrt(), swim_speed:Planar64::int(12), + surf_slope:Some(Planar64::raw(3787805118)),// normal.y=0.75 hitbox_halfsize:Planar64Vec3::int(2,5,2)/2, camera_offset:Planar64Vec3::int(0,2,0),//4.5-2.5=2 } @@ -642,6 +647,7 @@ impl PhysicsOutputState{ } } +#[derive(Clone,Hash,Eq,PartialEq)] enum PhysicsCollisionAttributes{ Contact{//track whether you are contacting the object contacting:crate::model::ContactingAttributes, @@ -652,6 +658,17 @@ enum PhysicsCollisionAttributes{ general:crate::model::GameMechanicAttributes, }, } +struct NonPhysicsError; +impl TryFrom<&crate::model::CollisionAttributes> for PhysicsCollisionAttributes{ + type Error=NonPhysicsError; + fn try_from(value:&crate::model::CollisionAttributes)->Result{ + match value{ + crate::model::CollisionAttributes::Decoration=>Err(NonPhysicsError), + crate::model::CollisionAttributes::Contact{contacting,general}=>Ok(Self::Contact{contacting:contacting.clone(),general:general.clone()}), + crate::model::CollisionAttributes::Intersect{intersecting,general}=>Ok(Self::Intersect{intersecting:intersecting.clone(),general:general.clone()}), + } + } +} pub struct PhysicsModel{ //A model is a thing that has a hitbox. can be represented by a list of TreyMesh-es @@ -664,7 +681,7 @@ pub struct PhysicsModel{ } impl PhysicsModel{ - fn new(mesh_id:usize,attr_id:usize,transform:crate::integer::Planar64Affine3)->Self{ + pub fn new(mesh_id:usize,attr_id:usize,transform:crate::integer::Planar64Affine3)->Self{ let normal_transform=transform.matrix3.inverse().transpose(); Self{ mesh_id, @@ -674,18 +691,12 @@ impl PhysicsModel{ normal_determinant:normal_transform.determinant(), } } - pub fn from_model(mesh_id:usize,instance:&crate::model::ModelInstance)->Option{ - match &instance.attributes{ - crate::model::CollisionAttributes::Contact{contacting,general}=>Some(PhysicsModel::new(mesh_id,instance.transform.clone(),PhysicsCollisionAttributes::Contact{contacting:contacting.clone(),general:general.clone()})), - crate::model::CollisionAttributes::Intersect{intersecting,general}=>Some(PhysicsModel::new(mesh_id,instance.transform.clone(),PhysicsCollisionAttributes::Intersect{intersecting:intersecting.clone(),general:general.clone()})), - crate::model::CollisionAttributes::Decoration=>None, - } - } } #[derive(Debug,Clone,Eq,Hash,PartialEq)] struct ContactCollision{ - face_id:crate::model_physics::MinkowskiFace, + //face_id:crate::model_physics::MinkowskiFace, + face_id:crate::model_physics::FaceId, model_id:usize,//using id to avoid lifetimes } #[derive(Debug,Clone,Eq,Hash,PartialEq)] @@ -697,6 +708,14 @@ enum Collision{ Contact(ContactCollision), Intersect(IntersectCollision), } +impl Collision{ + fn model_id(&self)->usize{ + match self{ + &Collision::Contact(ContactCollision{model_id,face_id:_}) + |&Collision::Intersect(IntersectCollision{model_id})=>model_id, + } + } +} #[derive(Default)] struct TouchingState{ contacts:std::collections::HashSet::, @@ -719,23 +738,56 @@ impl TouchingState{ Collision::Intersect(collision)=>self.intersects.remove(collision), } } - fn get_acceleration(&self,gravity:Planar64Vec3)->Planar64Vec3{ - //accelerators - //water - //contact constrain? - todo!() - } fn constrain_velocity(&self,models:&PhysicsModels,velocity:&mut Planar64Vec3){ + //TODO: trey push solve for contact in &self.contacts{ - //trey push solve + let n=contact.normal(models); + velocity-=n.dot(velocity)/n.length(); } - todo!() } fn constrain_acceleration(&self,models:&PhysicsModels,acceleration:&mut Planar64Vec3){ + //TODO: trey push solve for contact in &self.contacts{ - //trey push solve + let n=contact.normal(models); + acceleration-=n.dot(acceleration)/n.length(); + } + } + fn get_move_state(&self,mut a:Planar64Vec3)->(MoveState,Planar64Vec3){ + //check current move conditions and use heuristics to determine + //which ladder to climb on, which ground to walk on, etc + //collect move state affecting objects from contacts (accelerator,water,ladder,ground) + for contact in &self.contacts{ + // + } + for intersect in &self.intersects{ + // + } + (move_state,a) + } + fn predict_collision_end(&self,collector:&mut crate::instruction::InstructionCollector,models:&PhysicsModels,body:&Body,time:Time){ + for contact in &self.contacts{ + //detect face slide off + collector.collect(models.mesh(contact.model_id).brute_out_face(body,collector.time(),contact.face_id).map(|(face,time)|{ + TimedInstruction{ + time, + instruction:PhysicsInstruction::CollisionStart( + Collision::Contact(ContactCollision{model_id:contact.model_id,face_id:face}) + ), + } + })); + } + let relative_body=VirtualBody::relative(&Body::default(),body).body(time); + for intersect in &self.intersects{ + //detect model collision in reverse + collector.collect(models.mesh(intersect.model_id).brute_out(&relative_body,collector.time()).map(|(face,time)|{ + TimedInstruction{ + time, + instruction:PhysicsInstruction::CollisionStart( + Collision::Intersect(IntersectCollision{model_id:intersect.model_id}) + ), + } + })); } - todo!() } } @@ -845,13 +897,21 @@ impl PhysicsState { pub fn generate_models(&mut self,indexed_models:&crate::model::IndexedModelInstances){ let mut starts=Vec::new(); let mut spawns=Vec::new(); + let mut attr_hash=std::collections::HashMap::new(); for model in &indexed_models.models{ let mesh_id=self.meshes.len(); let mut make_mesh=false; for model_instance in &model.instances{ - if let Some(model_physics)=PhysicsModel::from_model(mesh_id,model_instance){ + if let Ok(physics_attributes)=PhysicsCollisionAttributes::try_from(&model_instance.attributes){ + let attr_id=if let Some(&attr_id)=attr_hash.get(&physics_attributes){ + attr_id + }else{ + let attr_id=self.models.push_attr(physics_attributes.clone()); + attr_hash.insert(physics_attributes,attr_id); + attr_id + }; + let model_physics=PhysicsModel::new(mesh_id,attr_id,model_instance.transform); make_mesh=true; - //TODO: index attributes let model_id=self.models.push_model(model_physics); for attr in &model_instance.temp_indexing{ match attr{ @@ -918,6 +978,13 @@ impl PhysicsState { fn set_control(&mut self,control:u32,state:bool){ self.controls=if state{self.controls|control}else{self.controls&!control}; } + fn gravity(&self)->Planar64Vec3{ + let mut a=self.style.gravity; + if let Some(rocket_force)=self.style.rocket_force{ + a+=self.style.get_propulsion_control_dir(&self.camera,self.controls,&self.next_mouse,self.time)*rocket_force; + } + a + } fn jump(&mut self){ match &self.move_state{ MoveState::Walk(walk_state)|MoveState::Ladder(walk_state)=>{ @@ -976,13 +1043,13 @@ impl PhysicsState { MoveState::Walk(WalkState{normal,state})=>{ let n=normal; let a; - (*state,a)=WalkEnum::with_target_velocity(&self.touching,&self.body,&self.style,&self.models,self.style.get_walk_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time),&n); + (*state,a)=WalkEnum::with_target_velocity(&self.body,&self.style,&self.models,self.style.get_walk_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time),&n); Some(a) }, MoveState::Ladder(WalkState{normal,state})=>{ let n=normal; let a; - (*state,a)=WalkEnum::with_target_velocity(&self.touching,&self.body,&self.style,&self.models,self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time),&n); + (*state,a)=WalkEnum::with_target_velocity(&self.body,&self.style,&self.models,self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time),&n); Some(a) }, } @@ -1003,28 +1070,32 @@ impl PhysicsState { } } -impl crate::instruction::InstructionEmitter for PhysicsState { +impl crate::instruction::InstructionEmitter for PhysicsState{ //this little next instruction function can cache its return value and invalidate the cached value by watching the State. - fn next_instruction(&self,time_limit:Time) -> Option> { + fn next_instruction(&self,time_limit:Time)->Option>{ //JUST POLLING!!! NO MUTATION let mut collector = crate::instruction::InstructionCollector::new(time_limit); collector.collect(self.next_move_instruction()); //check for collision ends - self.touching.next_instruction(&mut collector,self.style.mesh,self.body,self.time,collector.time()); + self.touching.predict_collision_end(&mut collector,&self.models,&self.body,self.time); //check for collision starts let mut aabb=crate::aabb::Aabb::default(); aabb.grow(self.body.extrapolated_position(self.time)); aabb.grow(self.body.extrapolated_position(collector.time())); aabb.inflate(self.style.hitbox_halfsize); + //common body + let relative_body=VirtualBody::relative(&Body::default(),&self.body).body(self.time); self.bvh.the_tester(&aabb,&mut |id|{ //no checks are needed because of the time limits. - let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(self.style.mesh,&self.models.mesh(id)); - let relative_body=VirtualBody::relative(&self.body,&Body::default()).body(self.time); - collector.collect(crate::face_crawler::predict_collision(&minkowski,&relative_body,collector.time()).map(|(face,time)|{ - //TODO: match model attribute and generate Collision::{Contact,Intersect} - TimedInstruction{time,instruction:PhysicsInstruction::CollisionStart(Collision::Contact(ContactCollision{model_id:id,face_id:face}))} + //let minkowski=crate::model_physics::MinkowskiMesh::minkowski_sum(self.style.mesh,&self.models.mesh(id)); + //collector.collect(crate::face_crawler::predict_collision(&minkowski,&relative_body,collector.time()).map(|(face,time)|{ + collector.collect(self.models.mesh(id).brute_in(&relative_body,collector.time()).map(|(face,time)|{ + TimedInstruction{time,instruction:PhysicsInstruction::CollisionStart(match self.models.attr(id){ + PhysicsCollisionAttributes::Contact{contacting:_,general:_}=>Collision::Contact(ContactCollision{model_id:id,face_id:face}), + PhysicsCollisionAttributes::Intersect{intersecting:_,general:_}=>Collision::Intersect(IntersectCollision{model_id:id}), + })} })); }); collector.instruction() @@ -1066,7 +1137,7 @@ fn run_teleport_behaviour(teleport_behaviour:&Option{ - if (ordered_checkpoint_id.is_none()||ordered_checkpoint_id.is_some_and(|id|id for PhysicsStat } match ins.instruction{ PhysicsInstruction::CollisionStart(c)=>{ - match self.models.attr(c.model_id()){ + let model_id=c.model_id(); + match self.models.attr(model_id){ PhysicsCollisionAttributes::Contact{contacting,general}=>{ let mut v=self.body.velocity; match &contacting.contact_behaviour{ Some(crate::model::ContactingBehaviour::Surf)=>println!("I'm surfing!"), Some(crate::model::ContactingBehaviour::Cling)=>println!("Unimplemented!"), &Some(crate::model::ContactingBehaviour::Elastic(elasticity))=>{ - let n=c.normal(&self.models); - let d=n.dot(v)*Planar64::raw(-1-elasticity as i64); - v-=n*(d/n.dot(n)); + // let n=c.normal(&self.models); + // let d=n.dot(v)*Planar64::raw(-1-elasticity as i64); + // v-=n*(d/n.dot(n)); + todo!() }, Some(crate::model::ContactingBehaviour::Ladder(contacting_ladder))=>{ if contacting_ladder.sticky{ @@ -1124,18 +1197,21 @@ impl crate::instruction::InstructionConsumer for PhysicsStat v=Planar64Vec3::ZERO;//model.velocity } //ladder walkstate - let (walk_state,a)=WalkState::ladder(&self.touching,&self.body,&self.style,&self.models,self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time),&c.normal(&self.models)); + let mut target_velocity=self.style.get_ladder_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time); + self.touching.constrain_velocity(&self.models,&mut target_velocity); + let (walk_state,mut a)=WalkState::ladder(&self.touching,&self.body,&self.style,&self.models,target_velocity,&c.normal(&self.models)); self.move_state=MoveState::Ladder(walk_state); + self.touching.constrain_acceleration(&self.models,&mut a); self.body.acceleration=a; } - None=>match &c.face { - TreyMeshFace::Top => { - //ground - let (walk_state,a)=WalkState::ground(&self.touching,&self.body,&self.style,&self.models,self.style.get_walk_target_velocity(&self.camera,self.controls,&self.next_mouse,self.time)); - self.move_state=MoveState::Walk(walk_state); - self.body.acceleration=a; - }, - _ => (), + None=>if self.style.surf_slope.map_or(true,|s|s for PhysicsStat if self.style.get_control(StyleModifiers::CONTROL_JUMP,self.controls){ self.jump(); } - if let Some(a)=self.refresh_walk_target(){ + if let Some(mut a)=self.refresh_walk_target(){ + self.touching.constrain_acceleration(&self.models,&mut a); self.body.acceleration=a; } }, @@ -1186,18 +1263,12 @@ impl crate::instruction::InstructionConsumer for PhysicsStat }, PhysicsInstruction::CollisionEnd(c) => { match self.models.attr(c.model_id()){ - PhysicsCollisionAttributes::Contact{contacting: _,general: _}=>{ + PhysicsCollisionAttributes::Contact{contacting:_,general:_}=>{ self.touching.remove(&c);//remove contact before calling contact_constrain_acceleration - let mut a=self.style.gravity; - if let Some(rocket_force)=self.style.rocket_force{ - a+=self.style.get_propulsion_control_dir(&self.camera,self.controls,&self.next_mouse,self.time)*rocket_force; - } - self.touching.constrain_acceleration(&self.models,&mut a); - self.body.acceleration=a; //check ground - self.move_state=self.touching.get_move_state(); + (self.move_state,self.body.acceleration)=self.touching.get_move_state(self.gravity()); }, - PhysicsCollisionAttributes::Intersect{intersecting: _,general: _}=>{ + PhysicsCollisionAttributes::Intersect{intersecting:_,general:_}=>{ self.touching.remove(&c); }, } @@ -1271,7 +1342,8 @@ impl crate::instruction::InstructionConsumer for PhysicsStat PhysicsInputInstruction::Idle => {refresh_walk_target=false;},//literally idle! } if refresh_walk_target{ - if let Some(a)=self.refresh_walk_target(){ + if let Some(mut a)=self.refresh_walk_target(){ + self.touching.constrain_acceleration(&self.models,&mut a); self.body.acceleration=a; }else if let Some(rocket_force)=self.style.rocket_force{ let mut a=self.style.gravity;