this is very cool but it won't work because mouse timestamps will be identical while paused
This commit is contained in:
parent
ad862ae8c9
commit
64e1e762a1
@ -42,6 +42,7 @@ pub enum InputInstruction {
|
|||||||
Jump(bool),
|
Jump(bool),
|
||||||
Zoom(bool),
|
Zoom(bool),
|
||||||
Reset,
|
Reset,
|
||||||
|
SetPaused(bool),
|
||||||
Idle,
|
Idle,
|
||||||
//Idle: there were no input events, but the simulation is safe to advance to this timestep
|
//Idle: there were no input events, but the simulation is safe to advance to this timestep
|
||||||
//for interpolation / networking / playback reasons, most playback heads will always want
|
//for interpolation / networking / playback reasons, most playback heads will always want
|
||||||
@ -453,6 +454,7 @@ impl PhysicsState {
|
|||||||
pub fn into_worker(mut self)->crate::worker::CompatWorker<TimedInstruction<InputInstruction>,PhysicsOutputState,Box<dyn FnMut(TimedInstruction<InputInstruction>)->PhysicsOutputState>>{
|
pub fn into_worker(mut self)->crate::worker::CompatWorker<TimedInstruction<InputInstruction>,PhysicsOutputState,Box<dyn FnMut(TimedInstruction<InputInstruction>)->PhysicsOutputState>>{
|
||||||
let mut mouse_blocking=true;
|
let mut mouse_blocking=true;
|
||||||
let mut last_mouse_time=self.next_mouse.time;
|
let mut last_mouse_time=self.next_mouse.time;
|
||||||
|
let mut simulation_timer=crate::timers::UnscaledTimer::unpaused();
|
||||||
let mut timeline=std::collections::VecDeque::new();
|
let mut timeline=std::collections::VecDeque::new();
|
||||||
crate::worker::CompatWorker::new(self.output(),Box::new(move |ins:TimedInstruction<InputInstruction>|{
|
crate::worker::CompatWorker::new(self.output(),Box::new(move |ins:TimedInstruction<InputInstruction>|{
|
||||||
if if let Some(phys_input)=match ins.instruction{
|
if if let Some(phys_input)=match ins.instruction{
|
||||||
@ -460,17 +462,17 @@ impl PhysicsState {
|
|||||||
if mouse_blocking{
|
if mouse_blocking{
|
||||||
//tell the game state which is living in the past about its future
|
//tell the game state which is living in the past about its future
|
||||||
timeline.push_front(TimedInstruction{
|
timeline.push_front(TimedInstruction{
|
||||||
time:last_mouse_time,
|
time:simulation_timer.time(last_mouse_time),
|
||||||
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:m}),
|
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:m}),
|
||||||
});
|
});
|
||||||
}else{
|
}else{
|
||||||
//mouse has just started moving again after being still for longer than 10ms.
|
//mouse has just started moving again after being still for longer than 10ms.
|
||||||
//replace the entire mouse interpolation state to avoid an intermediate state with identical m0.t m1.t timestamps which will divide by zero
|
//replace the entire mouse interpolation state to avoid an intermediate state with identical m0.t m1.t timestamps which will divide by zero
|
||||||
timeline.push_front(TimedInstruction{
|
timeline.push_front(TimedInstruction{
|
||||||
time:last_mouse_time,
|
time:simulation_timer.time(last_mouse_time),
|
||||||
instruction:PhysicsInputInstruction::ReplaceMouse(
|
instruction:PhysicsInputInstruction::ReplaceMouse(
|
||||||
MouseState{time:last_mouse_time,pos:self.next_mouse.pos},
|
MouseState{time:simulation_timer.time(last_mouse_time),pos:self.next_mouse.pos},
|
||||||
MouseState{time:ins.time,pos:m}
|
MouseState{time:simulation_timer.time(ins.time),pos:m}
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
//delay physics execution until we have an interpolation target
|
//delay physics execution until we have an interpolation target
|
||||||
@ -479,6 +481,14 @@ impl PhysicsState {
|
|||||||
last_mouse_time=ins.time;
|
last_mouse_time=ins.time;
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
|
InputInstruction::SetPaused(s)=>{
|
||||||
|
if s{
|
||||||
|
simulation_timer.pause(ins.time);
|
||||||
|
}else{
|
||||||
|
simulation_timer.unpause(ins.time);
|
||||||
|
}
|
||||||
|
Some(PhysicsInputInstruction::Idle)
|
||||||
|
}
|
||||||
InputInstruction::MoveForward(s)=>Some(PhysicsInputInstruction::SetMoveForward(s)),
|
InputInstruction::MoveForward(s)=>Some(PhysicsInputInstruction::SetMoveForward(s)),
|
||||||
InputInstruction::MoveLeft(s)=>Some(PhysicsInputInstruction::SetMoveLeft(s)),
|
InputInstruction::MoveLeft(s)=>Some(PhysicsInputInstruction::SetMoveLeft(s)),
|
||||||
InputInstruction::MoveBack(s)=>Some(PhysicsInputInstruction::SetMoveBack(s)),
|
InputInstruction::MoveBack(s)=>Some(PhysicsInputInstruction::SetMoveBack(s)),
|
||||||
@ -492,7 +502,7 @@ impl PhysicsState {
|
|||||||
}{
|
}{
|
||||||
//non-mouse event
|
//non-mouse event
|
||||||
timeline.push_back(TimedInstruction{
|
timeline.push_back(TimedInstruction{
|
||||||
time:ins.time,
|
time:simulation_timer.time(ins.time),
|
||||||
instruction:phys_input,
|
instruction:phys_input,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -504,7 +514,7 @@ impl PhysicsState {
|
|||||||
if 10_000_000<ins.time-self.next_mouse.time{
|
if 10_000_000<ins.time-self.next_mouse.time{
|
||||||
//push an event to extrapolate no movement from
|
//push an event to extrapolate no movement from
|
||||||
timeline.push_front(TimedInstruction{
|
timeline.push_front(TimedInstruction{
|
||||||
time:last_mouse_time,
|
time:simulation_timer.time(last_mouse_time),
|
||||||
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:self.next_mouse.pos}),
|
instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:self.next_mouse.pos}),
|
||||||
});
|
});
|
||||||
last_mouse_time=ins.time;
|
last_mouse_time=ins.time;
|
||||||
@ -526,9 +536,10 @@ impl PhysicsState {
|
|||||||
}{
|
}{
|
||||||
//empty queue
|
//empty queue
|
||||||
while let Some(instruction)=timeline.pop_front(){
|
while let Some(instruction)=timeline.pop_front(){
|
||||||
self.run(instruction.time);
|
let simulation_time=simulation_timer.time(instruction.time);
|
||||||
|
self.run(simulation_time);
|
||||||
self.process_instruction(TimedInstruction{
|
self.process_instruction(TimedInstruction{
|
||||||
time:instruction.time,
|
time:simulation_time,
|
||||||
instruction:PhysicsInstruction::Input(instruction.instruction),
|
instruction:PhysicsInstruction::Input(instruction.instruction),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,18 @@
|
|||||||
type TIME=crate::physics::TIME;
|
type TIME=crate::physics::TIME;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Timescale{
|
pub struct Timescale{
|
||||||
num:i64,
|
num:i64,
|
||||||
den:std::num::NonZeroU64,
|
den:std::num::NonZeroU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Paused{}
|
pub struct Paused{}
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Unpaused{}
|
pub struct Unpaused{}
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct PausedScaled{scale:Timescale}
|
pub struct PausedScaled{scale:Timescale}
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct UnpausedScaled{scale:Timescale}
|
pub struct UnpausedScaled{scale:Timescale}
|
||||||
|
|
||||||
pub trait TimerState{}
|
pub trait TimerState{}
|
||||||
@ -32,10 +37,81 @@ pub trait IsUnscaled{}
|
|||||||
impl IsUnscaled for Paused{}
|
impl IsUnscaled for Paused{}
|
||||||
impl IsUnscaled for Unpaused{}
|
impl IsUnscaled for Unpaused{}
|
||||||
|
|
||||||
|
//scaled timer wrapper
|
||||||
|
enum Scaled{
|
||||||
|
Paused(Timer<PausedScaled>),
|
||||||
|
Unpaused(Timer<UnpausedScaled>),
|
||||||
|
}
|
||||||
|
pub struct ScaledTimer{
|
||||||
|
timer:Scaled,
|
||||||
|
}
|
||||||
|
impl ScaledTimer{
|
||||||
|
pub fn unpaused()->Self{
|
||||||
|
Self{
|
||||||
|
timer:Scaled::Unpaused(unpaused_scaled(Timescale{num:1,den:std::num::NonZeroU64::new(1).unwrap()}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn time(&self,time:TIME)->TIME{
|
||||||
|
match &self.timer{
|
||||||
|
Scaled::Paused(timer)=>timer.time(),
|
||||||
|
Scaled::Unpaused(timer)=>timer.time(time),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn pause(&mut self,time:TIME){
|
||||||
|
match &self.timer{
|
||||||
|
Scaled::Paused(_)=>(),
|
||||||
|
Scaled::Unpaused(timer)=>self.timer=Scaled::Paused(timer.clone().pause(time)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn unpause(&mut self,time:TIME){
|
||||||
|
match &self.timer{
|
||||||
|
Scaled::Paused(timer)=>self.timer=Scaled::Unpaused(timer.clone().unpause(time)),
|
||||||
|
Scaled::Unpaused(_)=>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//unscaled timer wrapper
|
||||||
|
enum Unscaled{
|
||||||
|
Paused(Timer<Paused>),
|
||||||
|
Unpaused(Timer<Unpaused>),
|
||||||
|
}
|
||||||
|
pub struct UnscaledTimer{
|
||||||
|
timer:Unscaled,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnscaledTimer{
|
||||||
|
pub fn unpaused()->Self{
|
||||||
|
Self{
|
||||||
|
timer:Unscaled::Unpaused(unpaused())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn time(&self,time:TIME)->TIME{
|
||||||
|
match &self.timer{
|
||||||
|
Unscaled::Paused(timer)=>timer.time(),
|
||||||
|
Unscaled::Unpaused(timer)=>timer.time(time),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn pause(&mut self,time:TIME){
|
||||||
|
match &self.timer{
|
||||||
|
Unscaled::Paused(_)=>(),
|
||||||
|
Unscaled::Unpaused(timer)=>self.timer=Unscaled::Paused(timer.clone().pause(time)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pub fn unpause(&mut self,time:TIME){
|
||||||
|
match &self.timer{
|
||||||
|
Unscaled::Paused(timer)=>self.timer=Unscaled::Unpaused(timer.clone().unpause(time)),
|
||||||
|
Unscaled::Unpaused(_)=>(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Timer<State:TimerState>{
|
pub struct Timer<State:TimerState>{
|
||||||
offset:crate::physics::TIME,
|
offset:crate::physics::TIME,
|
||||||
state:State,
|
state:State,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_offset(time:TIME,write_time:TIME)->TIME{
|
fn get_offset(time:TIME,write_time:TIME)->TIME{
|
||||||
write_time-time
|
write_time-time
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user