changed logic of how to run the loop to allow for external event loops
This commit is contained in:
parent
8a1b482b3e
commit
464ebaaf25
@ -11,3 +11,6 @@ include = ["/src", "LICENSE", "/examples"]
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dev-dependencies]
|
||||
winit = "0.25.0"
|
13
README.md
13
README.md
@ -18,21 +18,26 @@ fn main() {
|
||||
let mut x: f32 = 0.0;
|
||||
|
||||
// create a closure containing your update logic
|
||||
let update_logic = |state: &mut State| {
|
||||
let mut update_logic = move |state: &mut State| {
|
||||
// access loop metadata via the State object
|
||||
x += state.get_timescale();
|
||||
print!("x: {} | ", x);
|
||||
|
||||
// print information about the current tick's timings
|
||||
state.debug_tick();
|
||||
state.debug_time();
|
||||
};
|
||||
|
||||
// create a closure containing your display logic
|
||||
let display_logic = |state: &State| {
|
||||
let display_logic = move |state: &State| {
|
||||
//
|
||||
};
|
||||
|
||||
// run the simulation with your user-defined update and display logic
|
||||
sim.run(update_logic, display_logic);
|
||||
// initialize the sim (cleans internal clocks, etc.)
|
||||
sim.init();
|
||||
loop {
|
||||
// "step" the sim forward
|
||||
sim.step(&mut update_logic, &display_logic);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -8,20 +8,25 @@ fn main() {
|
||||
let mut x: f32 = 0.0;
|
||||
|
||||
// create a closure containing your update logic
|
||||
let update_logic = |state: &mut State| {
|
||||
let mut update_logic = move |state: &mut State| {
|
||||
// access loop metadata via the State object
|
||||
x += state.get_timescale();
|
||||
print!("x: {} | ", x);
|
||||
|
||||
// print information about the current tick's timings
|
||||
state.debug_tick();
|
||||
state.debug_time();
|
||||
};
|
||||
|
||||
// create a closure containing your display logic
|
||||
let display_logic = |state: &State| {
|
||||
let display_logic = move |state: &State| {
|
||||
//
|
||||
};
|
||||
|
||||
// run the simulation with your user-defined update and display logic
|
||||
sim.run(update_logic, display_logic);
|
||||
// initialize the sim (cleans internal clocks, etc.)
|
||||
sim.init();
|
||||
loop {
|
||||
// "step" the sim forward
|
||||
sim.step(&mut update_logic, &display_logic);
|
||||
}
|
||||
}
|
46
examples/windowing.rs
Normal file
46
examples/windowing.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use hypoloop::core::{State, Loop};
|
||||
use winit::{
|
||||
event::{ElementState, Event, KeyboardInput, WindowEvent},
|
||||
event_loop::{ControlFlow, EventLoop},
|
||||
window::{CursorIcon, WindowBuilder},
|
||||
};
|
||||
|
||||
fn main() {
|
||||
// create sim with default configuration
|
||||
let mut sim = Loop::new();
|
||||
|
||||
// test variable
|
||||
let mut x: f32 = 0.0;
|
||||
|
||||
// create a winit event loop
|
||||
let event_loop = EventLoop::new();
|
||||
|
||||
// create a winit window
|
||||
let window = WindowBuilder::new().build(&event_loop).unwrap();
|
||||
window.set_title("Windowing test with hypoloop");
|
||||
|
||||
// create a closure containing your update logic
|
||||
let mut update_logic = move |state: &mut State| {
|
||||
// access loop metadata via the State object
|
||||
x += state.get_timescale();
|
||||
print!("x: {} | ", x);
|
||||
|
||||
// print information about the current tick's timings
|
||||
state.debug_time();
|
||||
};
|
||||
|
||||
// create a closure containing your display logic
|
||||
let display_logic = move |state: &State| {
|
||||
// redraw the winit window
|
||||
window.request_redraw();
|
||||
};
|
||||
|
||||
// initialize the sim (cleans internal clocks, etc.)
|
||||
sim.init();
|
||||
|
||||
// run the winit event loop with embedded hypoloop sim
|
||||
event_loop.run(move |event, _, control_flow| {
|
||||
// "step" the sim forward
|
||||
sim.step(&mut update_logic, &display_logic);
|
||||
});
|
||||
}
|
69
src/lib.rs
69
src/lib.rs
@ -7,10 +7,11 @@ pub mod core {
|
||||
update_interval: u32,
|
||||
timescale: f32,
|
||||
simulate: bool,
|
||||
clock_start: Instant,
|
||||
last_tick: Instant,
|
||||
delta_time: u32,
|
||||
irl_time: Duration,
|
||||
sim_time: Duration,
|
||||
last_tick: Instant
|
||||
sim_time: Duration
|
||||
}
|
||||
|
||||
impl State {
|
||||
@ -21,10 +22,11 @@ pub mod core {
|
||||
update_interval: 40,
|
||||
timescale: 1.0,
|
||||
simulate: true,
|
||||
clock_start: Instant::now(),
|
||||
last_tick: Instant::now(),
|
||||
delta_time: 0,
|
||||
irl_time: Duration::new(0,0),
|
||||
sim_time: Duration::new(0,0),
|
||||
last_tick: Instant::now()
|
||||
sim_time: Duration::new(0,0)
|
||||
};
|
||||
|
||||
// Make sure that delta_time always starts the same as update_interval
|
||||
@ -59,12 +61,12 @@ pub mod core {
|
||||
self.last_tick
|
||||
}
|
||||
|
||||
/// Pauses the simulation
|
||||
/// Pauses the simulation from within update logic
|
||||
pub fn pause(&mut self) {
|
||||
self.simulate = false;
|
||||
}
|
||||
|
||||
/// Resumes the simulation
|
||||
/// Resumes the simulation from within update logic
|
||||
pub fn resume(&mut self) {
|
||||
self.simulate = true;
|
||||
}
|
||||
@ -74,12 +76,15 @@ pub mod core {
|
||||
self.timescale = timescale;
|
||||
}
|
||||
|
||||
/// Prints a string of information about the current tick
|
||||
pub fn debug_tick(self) {
|
||||
/// Prints a string of information about the current time (IRL time, Sim time, Delta time (tick), Delta time (step))
|
||||
/// IRL time: Real time (in ms) elapsed since the start of the loop
|
||||
/// Sim time: Virtual time (in ms) elapsed since the start of the loop
|
||||
/// Delta time (tick): Real time (in ms) elapsed between the last tick and the previous tick
|
||||
/// Delta time (step): Real time (in ms with nanosecond accuracy) elapsed since the last update tick
|
||||
pub fn debug_time(self) {
|
||||
let elapsed_time = Instant::now().duration_since(self.last_tick);
|
||||
let loop_delay_ms = elapsed_time.as_nanos() as f32 / 1_000_000.0;
|
||||
let loop_rate_hz = 1000.0 / loop_delay_ms;
|
||||
println!("IRL time: {}ms | Sim time: {}ms | Tick delay/rate: {}ms/{}hz", self.irl_time.as_millis(), self.sim_time.as_millis(), loop_delay_ms, loop_rate_hz);
|
||||
println!("IRL time: {}ms | Sim time: {}ms | Delta time (tick): {}ms | Delta time (step): {}ms", self.irl_time.as_millis(), self.sim_time.as_millis(), self.delta_time, loop_delay_ms);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,15 +104,21 @@ pub mod core {
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes and runs the simulation using a user-supplied callback as the update logic
|
||||
pub fn run(&mut self, mut update_callback: impl FnMut(&mut State), mut display_callback: impl FnMut(&State)) {
|
||||
/// Initializes or re-initializes the simulation
|
||||
pub fn init(&mut self) {
|
||||
// Make sure the simulation will run
|
||||
self.state.simulate = true;
|
||||
|
||||
// start the clock to keep track of real time
|
||||
let clock_start = Instant::now();
|
||||
// reset the internal clocks
|
||||
self.state.clock_start = Instant::now();
|
||||
self.state.irl_time = Duration::new(0,0);
|
||||
self.state.sim_time = Duration::new(0,0);
|
||||
}
|
||||
|
||||
while self.state.simulate {
|
||||
/// Executes the per-loop logic (can be triggered manually so that hypoloop can be tied into external event loops)
|
||||
pub fn step(&mut self, mut update_callback: impl FnMut(&mut State), display_callback: impl Fn(&State)) {
|
||||
// don't run if the simulation is paused
|
||||
if self.state.simulate {
|
||||
// TODO - support frameskips
|
||||
if !self.realtime || delta_time(self.state.last_tick) >= self.state.update_interval {
|
||||
// mutable delta time and timescale for flexibility
|
||||
@ -121,7 +132,7 @@ pub mod core {
|
||||
} else {
|
||||
self.state.delta_time = self.state.update_interval;
|
||||
self.state.sim_time += Duration::from_millis(self.state.update_interval as u64);
|
||||
self.state.irl_time = Instant::now().duration_since(clock_start);
|
||||
self.state.irl_time = Instant::now().duration_since(self.state.clock_start);
|
||||
}
|
||||
|
||||
// update
|
||||
@ -144,34 +155,8 @@ pub mod core {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// update function
|
||||
// this is where all your per-tick logic should go
|
||||
fn update(user_function: fn(), delta_time: u32, timescale: f32) {
|
||||
// use timestep to scale per-tick calculations appropriately
|
||||
let timestep: f32 = delta_time as f32 / 1000.0 * timescale;
|
||||
|
||||
// call user update function
|
||||
user_function();
|
||||
}
|
||||
|
||||
// display function
|
||||
// this is where you should call a render function
|
||||
fn display(delta_time: u32, timescale: f32, update_interval: u32) {
|
||||
// use interpolation to smooth display values between ticks
|
||||
let interpolation: f32 = delta_time as f32 / update_interval as f32 * timescale;
|
||||
}
|
||||
|
||||
// gets the time in milliseconds that's elapsed since the earlier Instant
|
||||
fn delta_time(earlier: Instant) -> u32 {
|
||||
Instant::now().duration_since(earlier).as_millis() as u32
|
||||
}
|
||||
|
||||
// default update function (does nothing)
|
||||
fn default_update() {
|
||||
}
|
||||
|
||||
// default display function (does nothing)
|
||||
fn default_display() {
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user