This commit is contained in:
Quaternions 2023-10-12 15:51:31 -07:00
parent 01b5769dc0
commit 10a293e789
2 changed files with 148 additions and 72 deletions

View File

@ -24,6 +24,11 @@ impl Time{
self.0 self.0
} }
} }
impl From<Planar64> for Time{
fn from(value:Planar64)->Self{
Time((((value.0 as i128)*1_000_000_000)>>32) as i64)
}
}
impl std::fmt::Display for Time{ impl std::fmt::Display for Time{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{ fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
write!(f,"{}s+{}ns",self.0/Self::ONE_SECOND.0,self.0%Self::ONE_SECOND.0) write!(f,"{}s+{}ns",self.0/Self::ONE_SECOND.0,self.0%Self::ONE_SECOND.0)
@ -50,6 +55,20 @@ impl std::ops::Sub<Time> for Time{
Time(self.0-rhs.0) Time(self.0-rhs.0)
} }
} }
impl std::ops::Mul<Time> for Time{
type Output=Time;
#[inline]
fn mul(self,rhs:Time)->Self::Output{
Self((((self.0 as i128)*(rhs.0 as i128))/1_000_000_000) as i64)
}
}
impl std::ops::Div<i64> for Time{
type Output=Time;
#[inline]
fn div(self,rhs:i64)->Self::Output {
Time(self.0/rhs)
}
}
#[derive(Clone,Copy,Hash)] #[derive(Clone,Copy,Hash)]
pub struct Ratio64{ pub struct Ratio64{
@ -323,24 +342,31 @@ pub struct Planar64(i64);
impl Planar64{ impl Planar64{
pub const ZERO:Self=Self(0); pub const ZERO:Self=Self(0);
pub const ONE:Self=Self(1<<32); pub const ONE:Self=Self(1<<32);
#[inline]
pub fn int(num:i32)->Self{ pub fn int(num:i32)->Self{
Self(Self::ONE.0*num as i64) Self(Self::ONE.0*num as i64)
} }
#[inline]
pub fn raw(num:i64)->Self{ pub fn raw(num:i64)->Self{
Self(num) Self(num)
} }
#[inline]
pub fn get(&self)->i64{ pub fn get(&self)->i64{
self.0 self.0
} }
pub fn from_ratio(num:i64,den:std::num::NonZeroU64)->Self{
Self(Self::ONE.0*num/den.get() as i64)
}
} }
impl Into<f32> for Planar64{ impl Into<f32> for Planar64{
#[inline]
fn into(self)->f32{ fn into(self)->f32{
self.0 as f32/(1<<32) as f32 self.0 as f32/(1<<32) as f32
} }
} }
impl From<Ratio64> for Planar64{
#[inline]
fn from(ratio:Ratio64)->Self{
Self(Self::ONE.0*ratio.num/ratio.den.get() as i64)
}
}
impl std::ops::Neg for Planar64{ impl std::ops::Neg for Planar64{
type Output=Planar64; type Output=Planar64;
#[inline] #[inline]
@ -390,6 +416,11 @@ impl std::ops::Div<Planar64> for Planar64{
Planar64((((self.0 as i128)<<64)/rhs.0 as i128) as i64) Planar64((((self.0 as i128)<<64)/rhs.0 as i128) as i64)
} }
} }
// impl PartialOrd<i64> for Planar64{
// fn partial_cmp(&self, other: &i64) -> Option<std::cmp::Ordering> {
// self.0.partial_cmp(other)
// }
// }
///[-1.0,1.0] = [-2^32,2^32] ///[-1.0,1.0] = [-2^32,2^32]
@ -422,7 +453,7 @@ impl Planar64Vec3{
Planar64(self.0.z) Planar64(self.0.z)
} }
#[inline] #[inline]
pub fn min(self,rhs:Self)->Self{ pub fn min(&self,rhs:Self)->Self{
Self(glam::i64vec3( Self(glam::i64vec3(
self.0.x.min(rhs.0.x), self.0.x.min(rhs.0.x),
self.0.y.min(rhs.0.y), self.0.y.min(rhs.0.y),
@ -430,7 +461,7 @@ impl Planar64Vec3{
)) ))
} }
#[inline] #[inline]
pub fn max(self,rhs:Self)->Self{ pub fn max(&self,rhs:Self)->Self{
Self(glam::i64vec3( Self(glam::i64vec3(
self.0.x.max(rhs.0.x), self.0.x.max(rhs.0.x),
self.0.y.max(rhs.0.y), self.0.y.max(rhs.0.y),
@ -438,14 +469,39 @@ impl Planar64Vec3{
)) ))
} }
#[inline] #[inline]
pub fn midpoint(self,rhs:Self)->Self{ pub fn midpoint(&self,rhs:Self)->Self{
Self((self.0+rhs.0)/2) Self((self.0+rhs.0)/2)
} }
#[inline] #[inline]
pub fn cmplt(self,rhs:Self)->glam::BVec3{ pub fn cmplt(&self,rhs:Self)->glam::BVec3{
self.0.cmplt(rhs.0) self.0.cmplt(rhs.0)
} }
#[inline]
pub fn dot(&self,rhs:Self)->Planar64{
Planar64(((
(self.0.x as i128)*(rhs.0.x as i128)+
(self.0.y as i128)*(rhs.0.y as i128)+
(self.0.z as i128)*(rhs.0.z as i128)
)>>64) as i64)
}
#[inline]
pub fn length(&self)->Planar64{
let radicand=(self.0.x as i128)*(self.0.x as i128)+(self.0.y as i128)*(self.0.y as i128)+(self.0.z as i128)*(self.0.z as i128);
Planar64(unsafe{(radicand as f64).sqrt().to_int_unchecked()})
}
#[inline]
pub fn with_length(&self,length:Planar64)->Self{
let radicand=(self.0.x as i128)*(self.0.x as i128)+(self.0.y as i128)*(self.0.y as i128)+(self.0.z as i128)*(self.0.z as i128);
let self_length:i128=unsafe{(radicand as f64).sqrt().to_int_unchecked()};
//self.0*length/self_length
Planar64Vec3(
glam::i64vec3(
((self.0.x as i128)*(length.0 as i128)/self_length) as i64,
((self.0.y as i128)*(length.0 as i128)/self_length) as i64,
((self.0.z as i128)*(length.0 as i128)/self_length) as i64,
)
)
}
} }
impl Into<glam::Vec3> for Planar64Vec3{ impl Into<glam::Vec3> for Planar64Vec3{
fn into(self)->glam::Vec3{ fn into(self)->glam::Vec3{
@ -456,6 +512,13 @@ impl Into<glam::Vec3> for Planar64Vec3{
) )
} }
} }
impl std::ops::Neg for Planar64Vec3{
type Output=Planar64Vec3;
#[inline]
fn neg(self)->Self::Output{
Planar64Vec3(-self.0)
}
}
impl std::ops::Add<Planar64Vec3> for Planar64Vec3{ impl std::ops::Add<Planar64Vec3> for Planar64Vec3{
type Output=Planar64Vec3; type Output=Planar64Vec3;
#[inline] #[inline]
@ -493,6 +556,17 @@ impl std::ops::Mul<Planar64> for Planar64Vec3{
)) ))
} }
} }
impl std::ops::Mul<Time> for Planar64Vec3{
type Output=Planar64Vec3;
#[inline]
fn mul(self,rhs:Time)->Self::Output{
Planar64Vec3(glam::i64vec3(
(((self.0.x as i128)*(rhs.0 as i128))/1_000_000_000) as i64,
(((self.0.y as i128)*(rhs.0 as i128))/1_000_000_000) as i64,
(((self.0.z as i128)*(rhs.0 as i128))/1_000_000_000) as i64
))
}
}
impl std::ops::Div<i64> for Planar64Vec3{ impl std::ops::Div<i64> for Planar64Vec3{
type Output=Planar64Vec3; type Output=Planar64Vec3;
#[inline] #[inline]

View File

@ -149,7 +149,7 @@ pub struct PhysicsCamera {
//angle limits could be an enum + struct that defines whether it's limited and selects clamp or wrap depending //angle limits could be an enum + struct that defines whether it's limited and selects clamp or wrap depending
// enum AngleLimit{ // enum AngleLimit{
// Unlimited, // Unlimited,
// Limited(Angle32,Angle32), // Limited{lower:Angle32,upper:Angle32},
// } // }
//pitch_limit:AngleLimit, //pitch_limit:AngleLimit,
//yaw_limit:AngleLimit, //yaw_limit:AngleLimit,
@ -218,7 +218,7 @@ impl std::default::Default for StyleModifiers{
Self{ Self{
controls_mask: !0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN), controls_mask: !0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
controls_held: 0, controls_held: 0,
strafe_tick_rate:Ratio64::ONE/100, strafe_tick_rate:Ratio64::new(100,Time::ONE_SECOND.nanos() as u64).unwrap(),
gravity: Planar64Vec3::int(0,100,0), gravity: Planar64Vec3::int(0,100,0),
friction: Planar64::int(12)/10, friction: Planar64::int(12)/10,
walk_accel: Planar64::int(90), walk_accel: Planar64::int(90),
@ -400,7 +400,7 @@ impl Body {
} }
pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{ pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{
let dt=time-self.time; let dt=time-self.time;
self.position+self.velocity*dt+self.acceleration*(dt*dt*0.5) self.position+self.velocity*dt+self.acceleration*(dt*dt/2)
} }
pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{ pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{
let dt=time-self.time; let dt=time-self.time;
@ -643,7 +643,7 @@ impl PhysicsState {
} }
fn jump(&mut self){ fn jump(&mut self){
self.grounded=false;//do I need this? self.grounded=false;//do I need this?
let mut v=self.body.velocity+Planar64Vec3::int(0,715588,0)/20000;//0.715588/2.0*100.0 let mut v=self.body.velocity+Planar64Vec3::int(0,715588,0)/(2*1000000/100);//0.715588/2.0*100.0
self.contact_constrain_velocity(&mut v); self.contact_constrain_velocity(&mut v);
self.body.velocity=v; self.body.velocity=v;
} }
@ -652,8 +652,8 @@ impl PhysicsState {
for (_,contact) in &self.contacts { 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<Planar64::ZERO{
(*velocity)-=d/n.length_squared()*n; (*velocity)-=n*(d/n.dot(n));
} }
} }
} }
@ -661,14 +661,14 @@ impl PhysicsState {
for (_,contact) in &self.contacts { 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<Planar64::ZERO{
(*acceleration)-=d/n.length_squared()*n; (*acceleration)-=n*(d/n.dot(n));
} }
} }
} }
fn next_strafe_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> { fn next_strafe_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
return Some(TimedInstruction{ return Some(TimedInstruction{
time:self.style.strafe_tick_rate.rhs_div_int(self.style.strafe_tick_rate.mul_int(self.time)+1), time:Time::from_nanos(self.style.strafe_tick_rate.rhs_div_int(self.style.strafe_tick_rate.mul_int(self.time.nanos())+1)),
//only poll the physics if there is a before and after mouse event //only poll the physics if there is a before and after mouse event
instruction:PhysicsInstruction::StrafeTick instruction:PhysicsInstruction::StrafeTick
}); });
@ -711,16 +711,18 @@ impl PhysicsState {
let mut v=self.walk.target_velocity; let mut v=self.walk.target_velocity;
self.contact_constrain_velocity(&mut v); self.contact_constrain_velocity(&mut v);
let mut target_diff=v-self.body.velocity; let mut target_diff=v-self.body.velocity;
target_diff.y=0f32; //remove normal component
target_diff-=Planar64Vec3::Y*target_diff.y();
if target_diff==Planar64Vec3::ZERO{ if target_diff==Planar64Vec3::ZERO{
let mut a=Planar64Vec3::ZERO; let mut a=Planar64Vec3::ZERO;
self.contact_constrain_acceleration(&mut a); self.contact_constrain_acceleration(&mut a);
self.body.acceleration=a; self.body.acceleration=a;
self.walk.state=WalkEnum::Reached; self.walk.state=WalkEnum::Reached;
}else{ }else{
let accel=self.style.walk_accel.min(self.style.gravity.length()*self.style.friction); //normal friction acceleration is clippedAcceleration.dot(normal)*friction
let accel=self.style.walk_accel.min(self.style.gravity.dot(Planar64Vec3::NEG_Y)*self.style.friction);
let time_delta=target_diff.length()/accel; let time_delta=target_diff.length()/accel;
let mut a=target_diff/time_delta; let mut a=target_diff.with_length(accel);
self.contact_constrain_acceleration(&mut a); self.contact_constrain_acceleration(&mut a);
self.body.acceleration=a; self.body.acceleration=a;
self.walk.target_time=self.body.time+Time::from(time_delta); self.walk.target_time=self.body.time+Time::from(time_delta);
@ -764,26 +766,26 @@ impl PhysicsState {
//collect x //collect x
match collision_data.face { match collision_data.face {
TreyMeshFace::Top|TreyMeshFace::Back|TreyMeshFace::Bottom|TreyMeshFace::Front=>{ TreyMeshFace::Top|TreyMeshFace::Back|TreyMeshFace::Bottom|TreyMeshFace::Front=>{
for t in zeroes2(mesh0.max.x-mesh1.min.x,v.x,0.5*a.x) { for t in zeroes2(mesh0.max.x()-mesh1.min.x(),v.x(),a.x()/2) {
//negative t = back in time //negative t = back in time
//must be moving towards surface to collide //must be moving towards surface to collide
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time; let t_time=self.body.time-Time::from(t);
if time<=t_time&&t_time<best_time&&0f32<v.x+a.x*-t{ if time<=t_time&&t_time<best_time&&Planar64::ZERO<v.x()+a.x()*-t{
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
exit_face=Some(TreyMeshFace::Left); exit_face=Some(TreyMeshFace::Left);
break; break;
} }
} }
for t in zeroes2(mesh0.min.x-mesh1.max.x,v.x,0.5*a.x) { for t in zeroes2(mesh0.min.x()-mesh1.max.x(),v.x(),a.x()/2) {
//negative t = back in time //negative t = back in time
//must be moving towards surface to collide //must be moving towards surface to collide
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time; let t_time=self.body.time-Time::from(t);
if time<=t_time&&t_time<best_time&&v.x+a.x*-t<0f32{ if time<=t_time&&t_time<best_time&&v.x()+a.x()*-t<Planar64::ZERO{
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
exit_face=Some(TreyMeshFace::Right); exit_face=Some(TreyMeshFace::Right);
@ -793,14 +795,14 @@ impl PhysicsState {
}, },
TreyMeshFace::Left=>{ TreyMeshFace::Left=>{
//generate event if v.x<0||a.x<0 //generate event if v.x<0||a.x<0
if -v.x<0f32{ if -v.x()<Planar64::ZERO{
best_time=time; best_time=time;
exit_face=Some(TreyMeshFace::Left); exit_face=Some(TreyMeshFace::Left);
} }
}, },
TreyMeshFace::Right=>{ TreyMeshFace::Right=>{
//generate event if 0<v.x||0<a.x //generate event if 0<v.x||0<a.x
if 0f32<(-v.x){ if Planar64::ZERO<(-v.x()){
best_time=time; best_time=time;
exit_face=Some(TreyMeshFace::Right); exit_face=Some(TreyMeshFace::Right);
} }
@ -809,26 +811,26 @@ impl PhysicsState {
//collect y //collect y
match collision_data.face { match collision_data.face {
TreyMeshFace::Left|TreyMeshFace::Back|TreyMeshFace::Right|TreyMeshFace::Front=>{ TreyMeshFace::Left|TreyMeshFace::Back|TreyMeshFace::Right|TreyMeshFace::Front=>{
for t in zeroes2(mesh0.max.y-mesh1.min.y,v.y,0.5*a.y) { for t in zeroes2(mesh0.max.y()-mesh1.min.y(),v.y(),a.y()/2) {
//negative t = back in time //negative t = back in time
//must be moving towards surface to collide //must be moving towards surface to collide
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time; let t_time=self.body.time-Time::from(t);
if time<=t_time&&t_time<best_time&&0f32<v.y+a.y*-t{ if time<=t_time&&t_time<best_time&&Planar64::ZERO<v.y()+a.y()*-t{
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
exit_face=Some(TreyMeshFace::Bottom); exit_face=Some(TreyMeshFace::Bottom);
break; break;
} }
} }
for t in zeroes2(mesh0.min.y-mesh1.max.y,v.y,0.5*a.y) { for t in zeroes2(mesh0.min.y()-mesh1.max.y(),v.y(),a.y()/2) {
//negative t = back in time //negative t = back in time
//must be moving towards surface to collide //must be moving towards surface to collide
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time; let t_time=self.body.time-Time::from(t);
if time<=t_time&&t_time<best_time&&v.y+a.y*-t<0f32{ if time<=t_time&&t_time<best_time&&v.y()+a.y()*-t<Planar64::ZERO{
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
exit_face=Some(TreyMeshFace::Top); exit_face=Some(TreyMeshFace::Top);
@ -838,14 +840,14 @@ impl PhysicsState {
}, },
TreyMeshFace::Bottom=>{ TreyMeshFace::Bottom=>{
//generate event if v.y<0||a.y<0 //generate event if v.y<0||a.y<0
if -v.y<0f32{ if -v.y()<Planar64::ZERO{
best_time=time; best_time=time;
exit_face=Some(TreyMeshFace::Bottom); exit_face=Some(TreyMeshFace::Bottom);
} }
}, },
TreyMeshFace::Top=>{ TreyMeshFace::Top=>{
//generate event if 0<v.y||0<a.y //generate event if 0<v.y||0<a.y
if 0f32<(-v.y){ if Planar64::ZERO<(-v.y()){
best_time=time; best_time=time;
exit_face=Some(TreyMeshFace::Top); exit_face=Some(TreyMeshFace::Top);
} }
@ -854,26 +856,26 @@ impl PhysicsState {
//collect z //collect z
match collision_data.face { match collision_data.face {
TreyMeshFace::Left|TreyMeshFace::Bottom|TreyMeshFace::Right|TreyMeshFace::Top=>{ TreyMeshFace::Left|TreyMeshFace::Bottom|TreyMeshFace::Right|TreyMeshFace::Top=>{
for t in zeroes2(mesh0.max.z-mesh1.min.z,v.z,0.5*a.z) { for t in zeroes2(mesh0.max.z()-mesh1.min.z(),v.z(),a.z()/2) {
//negative t = back in time //negative t = back in time
//must be moving towards surface to collide //must be moving towards surface to collide
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time; let t_time=self.body.time-Time::from(t);
if time<=t_time&&t_time<best_time&&0f32<v.z+a.z*-t{ if time<=t_time&&t_time<best_time&&Planar64::ZERO<v.z()+a.z()*-t{
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
exit_face=Some(TreyMeshFace::Front); exit_face=Some(TreyMeshFace::Front);
break; break;
} }
} }
for t in zeroes2(mesh0.min.z-mesh1.max.z,v.z,0.5*a.z) { for t in zeroes2(mesh0.min.z()-mesh1.max.z(),v.z(),a.z()/2) {
//negative t = back in time //negative t = back in time
//must be moving towards surface to collide //must be moving towards surface to collide
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time; let t_time=self.body.time-Time::from(t);
if time<=t_time&&t_time<best_time&&v.z+a.z*-t<0f32{ if time<=t_time&&t_time<best_time&&v.z()+a.z()*-t<Planar64::ZERO{
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
exit_face=Some(TreyMeshFace::Back); exit_face=Some(TreyMeshFace::Back);
@ -883,14 +885,14 @@ impl PhysicsState {
}, },
TreyMeshFace::Front=>{ TreyMeshFace::Front=>{
//generate event if v.z<0||a.z<0 //generate event if v.z<0||a.z<0
if -v.z<0f32{ if -v.z()<Planar64::ZERO{
best_time=time; best_time=time;
exit_face=Some(TreyMeshFace::Front); exit_face=Some(TreyMeshFace::Front);
} }
}, },
TreyMeshFace::Back=>{ TreyMeshFace::Back=>{
//generate event if 0<v.z||0<a.z //generate event if 0<v.z||0<a.z
if 0f32<(-v.z){ if Planar64::ZERO<(-v.z()){
best_time=time; best_time=time;
exit_face=Some(TreyMeshFace::Back); exit_face=Some(TreyMeshFace::Back);
} }
@ -913,15 +915,15 @@ impl PhysicsState {
let mut best_time=time_limit; let mut best_time=time_limit;
let mut best_face:Option<TreyMeshFace>=None; let mut best_face:Option<TreyMeshFace>=None;
//collect x //collect x
for t in zeroes2(mesh0.max.x-mesh1.min.x,v.x,0.5*a.x) { for t in zeroes2(mesh0.max.x()-mesh1.min.x(),v.x(),a.x()/2) {
//must collide now or in the future //must collide now or in the future
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time; let t_time=body_time+Time::from(t);
if time<=t_time&&t_time<best_time&&0f32<v.x+a.x*t{ if time<=t_time&&t_time<best_time&&Planar64::ZERO<v.x()+a.x()*t{
let dp=self.body.extrapolated_position(t_time)-p; let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping //faces must be overlapping
if mesh1.min.y<mesh0.max.y+dp.y&&mesh0.min.y+dp.y<mesh1.max.y&&mesh1.min.z<mesh0.max.z+dp.z&&mesh0.min.z+dp.z<mesh1.max.z { if mesh1.min.y()<mesh0.max.y()+dp.y()&&mesh0.min.y()+dp.y()<mesh1.max.y()&&mesh1.min.z()<mesh0.max.z()+dp.z()&&mesh0.min.z()+dp.z()<mesh1.max.z() {
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
best_face=Some(TreyMeshFace::Left); best_face=Some(TreyMeshFace::Left);
@ -929,15 +931,15 @@ impl PhysicsState {
} }
} }
} }
for t in zeroes2(mesh0.min.x-mesh1.max.x,v.x,0.5*a.x) { for t in zeroes2(mesh0.min.x()-mesh1.max.x(),v.x(),a.x()/2) {
//must collide now or in the future //must collide now or in the future
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time; let t_time=body_time+Time::from(t);
if time<=t_time&&t_time<best_time&&v.x+a.x*t<0f32{ if time<=t_time&&t_time<best_time&&v.x()+a.x()*t<Planar64::ZERO{
let dp=self.body.extrapolated_position(t_time)-p; let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping //faces must be overlapping
if mesh1.min.y<mesh0.max.y+dp.y&&mesh0.min.y+dp.y<mesh1.max.y&&mesh1.min.z<mesh0.max.z+dp.z&&mesh0.min.z+dp.z<mesh1.max.z { if mesh1.min.y()<mesh0.max.y()+dp.y()&&mesh0.min.y()+dp.y()<mesh1.max.y()&&mesh1.min.z()<mesh0.max.z()+dp.z()&&mesh0.min.z()+dp.z()<mesh1.max.z() {
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
best_face=Some(TreyMeshFace::Right); best_face=Some(TreyMeshFace::Right);
@ -946,15 +948,15 @@ impl PhysicsState {
} }
} }
//collect y //collect y
for t in zeroes2(mesh0.max.y-mesh1.min.y,v.y,0.5*a.y) { for t in zeroes2(mesh0.max.y()-mesh1.min.y(),v.y(),a.y()/2) {
//must collide now or in the future //must collide now or in the future
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time; let t_time=body_time+Time::from(t);
if time<=t_time&&t_time<best_time&&0f32<v.y+a.y*t{ if time<=t_time&&t_time<best_time&&Planar64::ZERO<v.y()+a.y()*t{
let dp=self.body.extrapolated_position(t_time)-p; let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping //faces must be overlapping
if mesh1.min.x<mesh0.max.x+dp.x&&mesh0.min.x+dp.x<mesh1.max.x&&mesh1.min.z<mesh0.max.z+dp.z&&mesh0.min.z+dp.z<mesh1.max.z { if mesh1.min.x()<mesh0.max.x()+dp.x()&&mesh0.min.x()+dp.x()<mesh1.max.x()&&mesh1.min.z()<mesh0.max.z()+dp.z()&&mesh0.min.z()+dp.z()<mesh1.max.z() {
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
best_face=Some(TreyMeshFace::Bottom); best_face=Some(TreyMeshFace::Bottom);
@ -962,15 +964,15 @@ impl PhysicsState {
} }
} }
} }
for t in zeroes2(mesh0.min.y-mesh1.max.y,v.y,0.5*a.y) { for t in zeroes2(mesh0.min.y()-mesh1.max.y(),v.y(),a.y()/2) {
//must collide now or in the future //must collide now or in the future
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time; let t_time=body_time+Time::from(t);
if time<=t_time&&t_time<best_time&&v.y+a.y*t<0f32{ if time<=t_time&&t_time<best_time&&v.y()+a.y()*t<Planar64::ZERO{
let dp=self.body.extrapolated_position(t_time)-p; let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping //faces must be overlapping
if mesh1.min.x<mesh0.max.x+dp.x&&mesh0.min.x+dp.x<mesh1.max.x&&mesh1.min.z<mesh0.max.z+dp.z&&mesh0.min.z+dp.z<mesh1.max.z { if mesh1.min.x()<mesh0.max.x()+dp.x()&&mesh0.min.x()+dp.x()<mesh1.max.x()&&mesh1.min.z()<mesh0.max.z()+dp.z()&&mesh0.min.z()+dp.z()<mesh1.max.z() {
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
best_face=Some(TreyMeshFace::Top); best_face=Some(TreyMeshFace::Top);
@ -979,15 +981,15 @@ impl PhysicsState {
} }
} }
//collect z //collect z
for t in zeroes2(mesh0.max.z-mesh1.min.z,v.z,0.5*a.z) { for t in zeroes2(mesh0.max.z()-mesh1.min.z(),v.z(),a.z()/2) {
//must collide now or in the future //must collide now or in the future
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time; let t_time=body_time+Time::from(t);
if time<=t_time&&t_time<best_time&&0f32<v.z+a.z*t{ if time<=t_time&&t_time<best_time&&Planar64::ZERO<v.z()+a.z()*t{
let dp=self.body.extrapolated_position(t_time)-p; let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping //faces must be overlapping
if mesh1.min.y<mesh0.max.y+dp.y&&mesh0.min.y+dp.y<mesh1.max.y&&mesh1.min.x<mesh0.max.x+dp.x&&mesh0.min.x+dp.x<mesh1.max.x { if mesh1.min.y()<mesh0.max.y()+dp.y()&&mesh0.min.y()+dp.y()<mesh1.max.y()&&mesh1.min.x()<mesh0.max.x()+dp.x()&&mesh0.min.x()+dp.x()<mesh1.max.x() {
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
best_face=Some(TreyMeshFace::Front); best_face=Some(TreyMeshFace::Front);
@ -995,15 +997,15 @@ impl PhysicsState {
} }
} }
} }
for t in zeroes2(mesh0.min.z-mesh1.max.z,v.z,0.5*a.z) { for t in zeroes2(mesh0.min.z()-mesh1.max.z(),v.z(),a.z()/2) {
//must collide now or in the future //must collide now or in the future
//must beat the current soonest collision time //must beat the current soonest collision time
//must be moving towards surface //must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time; let t_time=body_time+Time::from(t);
if time<=t_time&&t_time<best_time&&v.z+a.z*t<0f32{ if time<=t_time&&t_time<best_time&&v.z()+a.z()*t<Planar64::ZERO{
let dp=self.body.extrapolated_position(t_time)-p; let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping //faces must be overlapping
if mesh1.min.y<mesh0.max.y+dp.y&&mesh0.min.y+dp.y<mesh1.max.y&&mesh1.min.x<mesh0.max.x+dp.x&&mesh0.min.x+dp.x<mesh1.max.x { if mesh1.min.y()<mesh0.max.y()+dp.y()&&mesh0.min.y()+dp.y()<mesh1.max.y()&&mesh1.min.x()<mesh0.max.x()+dp.x()&&mesh0.min.x()+dp.x()<mesh1.max.x() {
//collect valid t //collect valid t
best_time=t_time; best_time=t_time;
best_face=Some(TreyMeshFace::Back); best_face=Some(TreyMeshFace::Back);
@ -1106,7 +1108,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
if let Some(mode)=self.get_mode(stage_element.mode_id){ 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(&spawn)=mode.get_spawn_model_id(self.game.stage_id){
if let Some(model)=self.models.get(spawn as usize){ if let Some(model)=self.models.get(spawn as usize){
self.body.position=model.transform.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(self.style.hitbox_halfsize.y+0.1); self.body.position=model.transform.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(self.style.hitbox_halfsize.y()+Planar64::ONE/16);
//manual clear //for c in self.contacts{process_instruction(CollisionEnd(c))} //manual clear //for c in self.contacts{process_instruction(CollisionEnd(c))}
self.contacts.clear(); self.contacts.clear();
self.intersects.clear(); self.intersects.clear();
@ -1154,7 +1156,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
if let Some(mode)=self.get_mode(stage_element.mode_id){ 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(&spawn)=mode.get_spawn_model_id(self.game.stage_id){
if let Some(model)=self.models.get(spawn as usize){ if let Some(model)=self.models.get(spawn as usize){
self.body.position=model.transform.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(self.style.hitbox_halfsize.y+0.1); self.body.position=model.transform.transform_point3(Planar64Vec3::Y)+Planar64Vec3::Y*(self.style.hitbox_halfsize.y()+Planar64::ONE/16);
//manual clear //for c in self.contacts{process_instruction(CollisionEnd(c))} //manual clear //for c in self.contacts{process_instruction(CollisionEnd(c))}
self.contacts.clear(); self.contacts.clear();
self.intersects.clear(); self.intersects.clear();