replace TIME with Time

This commit is contained in:
Quaternions 2023-10-11 19:17:56 -07:00
parent 4616fd7b3b
commit f16bc043c4
2 changed files with 74 additions and 47 deletions

View File

@ -1,6 +1,8 @@
//integer units
#[derive(Clone,Copy,Hash,Debug)]
pub struct Time(i64);
impl Time{
pub const ZERO:Self=Self(0);
pub const ONE_SECOND:Self=Self(1_000_000_000);
pub const ONE_MILLISECOND:Self=Self(1_000_000);
pub const ONE_MICROSECOND:Self=Self(1_000);
@ -18,6 +20,35 @@ impl Time{
Self(Self::ONE_NANOSECOND.0*num)
}
//should I have checked subtraction? force all time variables to be positive?
pub fn nanos(&self)->i64{
self.0
}
}
impl std::fmt::Display for Time{
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)
}
}
impl std::ops::Neg for Time{
type Output=Time;
#[inline]
fn neg(self)->Self::Output {
Time(-self.0)
}
}
impl std::ops::Add<Time> for Time{
type Output=Time;
#[inline]
fn add(self,rhs:Self)->Self::Output {
Time(self.0+rhs.0)
}
}
impl std::ops::Sub<Time> for Time{
type Output=Time;
#[inline]
fn sub(self,rhs:Self)->Self::Output {
Time(self.0-rhs.0)
}
}
#[derive(Clone,Copy,Hash)]

View File

@ -1,6 +1,6 @@
use crate::{instruction::{InstructionEmitter, InstructionConsumer, TimedInstruction}, zeroes::zeroes2};
use crate::integer::{Planar64,Planar64Vec3,Planar64Mat3,Angle32,Angle32Vec2,Ratio64Vec2};
use crate::integer::{Time,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64,Ratio64Vec2};
#[derive(Debug)]
pub enum PhysicsInstruction {
@ -54,7 +54,7 @@ pub struct Body {
position: Planar64Vec3,//I64 where 2^32 = 1 u
velocity: Planar64Vec3,//I64 where 2^32 = 1 u/s
acceleration: Planar64Vec3,//I64 where 2^32 = 1 u/s/s
time: TIME,//nanoseconds x xxxxD!
time:Time,//nanoseconds x xxxxD!
}
pub enum MoveRestriction {
@ -75,7 +75,7 @@ impl InputState {
}
}
impl crate::instruction::InstructionEmitter<InputInstruction> for InputState{
fn next_instruction(&self, time_limit:crate::body::TIME) -> Option<TimedInstruction<InputInstruction>> {
fn next_instruction(&self, time_limit:crate::body::Time) -> Option<TimedInstruction<InputInstruction>> {
//this is polled by PhysicsState for actions like Jump
//no, it has to be the other way around. physics is run up until the jump instruction, and then the jump instruction is pushed.
self.queue.get(0)
@ -93,24 +93,24 @@ impl crate::instruction::InstructionConsumer<InputInstruction> for InputState{
#[derive(Clone,Debug)]
pub struct MouseState {
pub pos: glam::IVec2,
pub time: TIME,
pub time:Time,
}
impl Default for MouseState{
fn default() -> Self {
Self {
time:0,
time:Time::ZERO,
pos:glam::IVec2::ZERO,
}
}
}
impl MouseState {
pub fn lerp(&self,target:&MouseState,time:TIME)->glam::IVec2 {
pub fn lerp(&self,target:&MouseState,time:Time)->glam::IVec2 {
let m0=self.pos.as_i64vec2();
let m1=target.pos.as_i64vec2();
//these are deltas
let t1t=(target.time-time) as i64;
let tt0=(time-self.time) as i64;
let dt=(target.time-self.time) as i64;
let t1t=(target.time-time).nanos();
let tt0=(time-self.time).nanos();
let dt=(target.time-self.time).nanos();
((m0*t1t+m1*tt0)/dt).as_ivec2()
}
}
@ -121,14 +121,14 @@ pub enum WalkEnum{
}
pub struct WalkState {
pub target_velocity: Planar64Vec3,
pub target_time: TIME,
pub target_time: Time,
pub state: WalkEnum,
}
impl WalkState {
pub fn new() -> Self {
Self{
target_velocity:Planar64Vec3::ZERO,
target_time:0,
target_time:Time::ZERO,
state:WalkEnum::Reached,
}
}
@ -160,7 +160,7 @@ impl PhysicsCamera {
Self{
offset,
sensitivity:Ratio64Vec2::ONE.mul_ratio(200_000),
mouse:MouseState{pos:glam::IVec2::ZERO,time:-1},//escape initialization hell divide by zero
mouse:MouseState{pos:glam::IVec2::ZERO,time:-Time::ONE_NANOSECOND},//escape initialization hell divide by zero
clamped_mouse_pos:glam::IVec2::ZERO,
angle_pitch_lower_limit:-Angle32::FRAC_PI_2,
angle_pitch_upper_limit:Angle32::FRAC_PI_2,
@ -210,8 +210,7 @@ pub struct StyleModifiers{
pub friction:Planar64,
pub walk_accel:Planar64,
pub gravity:Planar64Vec3,
pub strafe_tick_num:TIME,
pub strafe_tick_den:TIME,
pub strafe_tick_rate:Ratio64,
pub hitbox_halfsize:Planar64Vec3,
}
impl std::default::Default for StyleModifiers{
@ -219,8 +218,7 @@ impl std::default::Default for StyleModifiers{
Self{
controls_mask: !0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
controls_held: 0,
strafe_tick_num: 100,//100t
strafe_tick_den: 1_000_000_000,
strafe_tick_rate:Ratio64::ONE.div_ratio(100),
gravity: Planar64Vec3::new(0,100,0),
friction: Planar64::new(12)/10,
walk_accel: Planar64::new(90),
@ -280,7 +278,7 @@ impl StyleModifiers{
}
pub struct PhysicsState{
pub time:TIME,
pub time:Time,
pub body:Body,
pub world:WorldState,//currently there is only one state the world can be in
pub game:GameMechanicsState,
@ -391,26 +389,24 @@ impl RelativeCollision {
}
}
pub type TIME = i64;
impl Body {
pub fn with_pva(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3) -> Self {
Self{
position,
velocity,
acceleration,
time: 0,
time:Time::ZERO,
}
}
pub fn extrapolated_position(&self,time: TIME)->Planar64Vec3{
let dt=(time-self.time) as f64/1_000_000_000f64;
self.position+self.velocity*(dt as f32)+self.acceleration*((0.5*dt*dt) as f32)
pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{
let dt=time-self.time;
self.position+self.velocity*dt+self.acceleration*(dt*dt*0.5)
}
pub fn extrapolated_velocity(&self,time: TIME)->Planar64Vec3{
let dt=(time-self.time) as f64/1_000_000_000f64;
self.velocity+self.acceleration*(dt as f32)
pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{
let dt=time-self.time;
self.velocity+self.acceleration*dt
}
pub fn advance_time(&mut self, time: TIME){
pub fn advance_time(&mut self,time:Time){
self.position=self.extrapolated_position(time);
self.velocity=self.extrapolated_velocity(time);
self.time=time;
@ -420,9 +416,9 @@ impl Body {
impl Default for PhysicsState{
fn default() -> Self {
Self{
time: 0,
spawn_point:Planar64Vec3::new(0,50,0),
body: Body::with_pva(Planar64Vec3::new(0,50,0),Planar64Vec3::new(0,0,0),Planar64Vec3::new(0,-100,0)),
time: Time::ZERO,
style:StyleModifiers::default(),
grounded: false,
contacts: std::collections::HashMap::new(),
@ -628,7 +624,7 @@ impl PhysicsState {
}
}
//tickless gaming
pub fn run(&mut self, time_limit:TIME){
pub fn run(&mut self, time_limit:Time){
//prepare is ommitted - everything is done via instructions.
while let Some(instruction) = self.next_instruction(time_limit) {//collect
//process
@ -637,7 +633,7 @@ impl PhysicsState {
}
}
pub fn advance_time(&mut self, time: TIME){
pub fn advance_time(&mut self, time: Time){
self.body.advance_time(time);
self.time=time;
}
@ -672,7 +668,7 @@ impl PhysicsState {
}
fn next_strafe_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
return Some(TimedInstruction{
time:(self.time*self.style.strafe_tick_num/self.style.strafe_tick_den+1)*self.style.strafe_tick_den/self.style.strafe_tick_num,
time:self.style.strafe_tick_rate.div_int(self.style.strafe_tick_rate.mul_int(self.time)+1),
//only poll the physics if there is a before and after mouse event
instruction:PhysicsInstruction::StrafeTick
});
@ -727,7 +723,7 @@ impl PhysicsState {
let mut a=target_diff/time_delta;
self.contact_constrain_acceleration(&mut a);
self.body.acceleration=a;
self.walk.target_time=self.body.time+((time_delta as f64)*1_000_000_000f64) as TIME;
self.walk.target_time=self.body.time+Time::from(time_delta);
self.walk.state=WalkEnum::Transient;
}
}else{
@ -755,7 +751,7 @@ impl PhysicsState {
}
aabb
}
fn predict_collision_end(&self,time:TIME,time_limit:TIME,collision_data:&RelativeCollision) -> Option<TimedInstruction<PhysicsInstruction>> {
fn predict_collision_end(&self,time:Time,time_limit:Time,collision_data:&RelativeCollision) -> Option<TimedInstruction<PhysicsInstruction>> {
//must treat cancollide false objects differently: you may not exit through the same face you entered.
//RelativeCollsion must reference the full model instead of a particular face
//this is Ctrl+C Ctrl+V of predict_collision_start but with v=-v before the calc and t=-t after the calc
@ -773,7 +769,7 @@ impl PhysicsState {
//must be moving towards surface to collide
//must beat the current soonest collision time
//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+((-t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&0f32<v.x+a.x*-t{
//collect valid t
best_time=t_time;
@ -786,7 +782,7 @@ impl PhysicsState {
//must be moving towards surface to collide
//must beat the current soonest collision time
//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+((-t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&v.x+a.x*-t<0f32{
//collect valid t
best_time=t_time;
@ -818,7 +814,7 @@ impl PhysicsState {
//must be moving towards surface to collide
//must beat the current soonest collision time
//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+((-t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&0f32<v.y+a.y*-t{
//collect valid t
best_time=t_time;
@ -831,7 +827,7 @@ impl PhysicsState {
//must be moving towards surface to collide
//must beat the current soonest collision time
//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+((-t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&v.y+a.y*-t<0f32{
//collect valid t
best_time=t_time;
@ -863,7 +859,7 @@ impl PhysicsState {
//must be moving towards surface to collide
//must beat the current soonest collision time
//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+((-t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&0f32<v.z+a.z*-t{
//collect valid t
best_time=t_time;
@ -876,7 +872,7 @@ impl PhysicsState {
//must be moving towards surface to collide
//must beat the current soonest collision time
//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+((-t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&v.z+a.z*-t<0f32{
//collect valid t
best_time=t_time;
@ -909,7 +905,7 @@ impl PhysicsState {
}
None
}
fn predict_collision_start(&self,time:TIME,time_limit:TIME,model_id:u32) -> Option<TimedInstruction<PhysicsInstruction>> {
fn predict_collision_start(&self,time:Time,time_limit:Time,model_id:u32) -> Option<TimedInstruction<PhysicsInstruction>> {
let mesh0=self.mesh();
let mesh1=self.models.get(model_id as usize).unwrap().mesh();
let (p,v,a,body_time)=(self.body.position,self.body.velocity,self.body.acceleration,self.body.time);
@ -921,7 +917,7 @@ impl PhysicsState {
//must collide now or in the future
//must beat the current soonest collision time
//must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&0f32<v.x+a.x*t{
let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping
@ -937,7 +933,7 @@ impl PhysicsState {
//must collide now or in the future
//must beat the current soonest collision time
//must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&v.x+a.x*t<0f32{
let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping
@ -954,7 +950,7 @@ impl PhysicsState {
//must collide now or in the future
//must beat the current soonest collision time
//must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&0f32<v.y+a.y*t{
let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping
@ -970,7 +966,7 @@ impl PhysicsState {
//must collide now or in the future
//must beat the current soonest collision time
//must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&v.y+a.y*t<0f32{
let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping
@ -987,7 +983,7 @@ impl PhysicsState {
//must collide now or in the future
//must beat the current soonest collision time
//must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&0f32<v.z+a.z*t{
let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping
@ -1003,7 +999,7 @@ impl PhysicsState {
//must collide now or in the future
//must beat the current soonest collision time
//must be moving towards surface
let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
if time<=t_time&&t_time<best_time&&v.z+a.z*t<0f32{
let dp=self.body.extrapolated_position(t_time)-p;
//faces must be overlapping
@ -1031,7 +1027,7 @@ impl PhysicsState {
impl crate::instruction::InstructionEmitter<PhysicsInstruction> 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<TimedInstruction<PhysicsInstruction>> {
fn next_instruction(&self,time_limit:Time) -> Option<TimedInstruction<PhysicsInstruction>> {
//JUST POLLING!!! NO MUTATION
let mut collector = crate::instruction::InstructionCollector::new(time_limit);
//check for collision stop instructions with curent contacts