Compare commits
No commits in common. "db501015d0a0a7c9c966d471f036782be2ca5d61" and "e2c6b557bb578fe9bc6963b009b027b9e94e4be5" have entirely different histories.
db501015d0
...
e2c6b557bb
|
@ -947,18 +947,6 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fixed-timestep-rotating-model"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"async-std",
|
|
||||||
"fps_counter",
|
|
||||||
"lyra-engine",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
version = "1.0.28"
|
version = "1.0.28"
|
||||||
|
|
|
@ -10,7 +10,7 @@ members = [
|
||||||
"lyra-ecs",
|
"lyra-ecs",
|
||||||
"lyra-reflect",
|
"lyra-reflect",
|
||||||
"lyra-scripting",
|
"lyra-scripting",
|
||||||
"lyra-game", "lyra-math", "lyra-scene", "examples/many-lights", "examples/fixed-timestep-rotating-model"]
|
"lyra-game", "lyra-math", "lyra-scene", "examples/many-lights"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
scripting = ["dep:lyra-scripting"]
|
scripting = ["dep:lyra-scripting"]
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
[package]
|
|
||||||
name = "fixed-timestep-rotating-model"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
lyra-engine = { path = "../../", features = ["tracy"] }
|
|
||||||
anyhow = "1.0.75"
|
|
||||||
async-std = "1.12.0"
|
|
||||||
tracing = "0.1.37"
|
|
||||||
rand = "0.8.5"
|
|
||||||
fps_counter = "3.0.0"
|
|
||||||
|
|
||||||
[target.x86_64-unknown-linux-gnu]
|
|
||||||
linker = "/usr/bin/clang"
|
|
||||||
rustflags = ["-Clink-arg=-fuse-ld=lld", "-Clink-arg=-Wl,--no-rosegment"]
|
|
||||||
|
|
||||||
[profile.dev]
|
|
||||||
opt-level = 1
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
debug = true
|
|
|
@ -1,241 +0,0 @@
|
||||||
use std::ptr::NonNull;
|
|
||||||
|
|
||||||
use lyra_engine::{
|
|
||||||
assets::{gltf::Gltf, ResourceManager},
|
|
||||||
ecs::{
|
|
||||||
query::{Res, ResMut, View},
|
|
||||||
system::{BatchedSystem, Criteria, CriteriaSchedule, IntoSystem},
|
|
||||||
World,
|
|
||||||
},
|
|
||||||
game::Game,
|
|
||||||
input::{
|
|
||||||
Action, ActionHandler, ActionKind, ActionMapping, ActionMappingId, ActionSource,
|
|
||||||
InputActionPlugin, KeyCode, LayoutId, MouseAxis, MouseInput,
|
|
||||||
},
|
|
||||||
math::{self, Transform, Vec3},
|
|
||||||
render::light::directional::DirectionalLight,
|
|
||||||
scene::{
|
|
||||||
CameraComponent, FreeFlyCamera, FreeFlyCameraPlugin, WorldTransform,
|
|
||||||
ACTLBL_LOOK_LEFT_RIGHT, ACTLBL_LOOK_ROLL, ACTLBL_LOOK_UP_DOWN,
|
|
||||||
ACTLBL_MOVE_FORWARD_BACKWARD, ACTLBL_MOVE_LEFT_RIGHT, ACTLBL_MOVE_UP_DOWN,
|
|
||||||
},
|
|
||||||
DeltaTime,
|
|
||||||
};
|
|
||||||
use tracing::info;
|
|
||||||
|
|
||||||
#[async_std::main]
|
|
||||||
async fn main() {
|
|
||||||
let action_handler_plugin = |game: &mut Game| {
|
|
||||||
let action_handler = ActionHandler::builder()
|
|
||||||
.add_layout(LayoutId::from(0))
|
|
||||||
.add_action(ACTLBL_MOVE_FORWARD_BACKWARD, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_MOVE_LEFT_RIGHT, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_MOVE_UP_DOWN, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_LOOK_LEFT_RIGHT, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_LOOK_UP_DOWN, Action::new(ActionKind::Axis))
|
|
||||||
.add_action(ACTLBL_LOOK_ROLL, Action::new(ActionKind::Axis))
|
|
||||||
.add_action("Debug", Action::new(ActionKind::Button))
|
|
||||||
.add_mapping(
|
|
||||||
ActionMapping::builder(LayoutId::from(0), ActionMappingId::from(0))
|
|
||||||
.bind(
|
|
||||||
ACTLBL_MOVE_FORWARD_BACKWARD,
|
|
||||||
&[
|
|
||||||
ActionSource::Keyboard(KeyCode::W).into_binding_modifier(1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::S).into_binding_modifier(-1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_MOVE_LEFT_RIGHT,
|
|
||||||
&[
|
|
||||||
ActionSource::Keyboard(KeyCode::A).into_binding_modifier(-1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::D).into_binding_modifier(1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_MOVE_UP_DOWN,
|
|
||||||
&[
|
|
||||||
ActionSource::Keyboard(KeyCode::C).into_binding_modifier(1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::Z).into_binding_modifier(-1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_LOOK_LEFT_RIGHT,
|
|
||||||
&[
|
|
||||||
ActionSource::Mouse(MouseInput::Axis(MouseAxis::X)).into_binding(),
|
|
||||||
ActionSource::Keyboard(KeyCode::Left).into_binding_modifier(-1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::Right).into_binding_modifier(1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_LOOK_UP_DOWN,
|
|
||||||
&[
|
|
||||||
ActionSource::Mouse(MouseInput::Axis(MouseAxis::Y)).into_binding(),
|
|
||||||
ActionSource::Keyboard(KeyCode::Up).into_binding_modifier(-1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::Down).into_binding_modifier(1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
ACTLBL_LOOK_ROLL,
|
|
||||||
&[
|
|
||||||
ActionSource::Keyboard(KeyCode::E).into_binding_modifier(-1.0),
|
|
||||||
ActionSource::Keyboard(KeyCode::Q).into_binding_modifier(1.0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.bind(
|
|
||||||
"Debug",
|
|
||||||
&[ActionSource::Keyboard(KeyCode::B).into_binding()],
|
|
||||||
)
|
|
||||||
.finish(),
|
|
||||||
)
|
|
||||||
.finish();
|
|
||||||
|
|
||||||
let world = game.world_mut();
|
|
||||||
world.add_resource(action_handler);
|
|
||||||
game.with_plugin(InputActionPlugin);
|
|
||||||
};
|
|
||||||
|
|
||||||
Game::initialize()
|
|
||||||
.await
|
|
||||||
.with_plugin(lyra_engine::DefaultPlugins)
|
|
||||||
.with_plugin(setup_scene_plugin)
|
|
||||||
.with_plugin(action_handler_plugin)
|
|
||||||
//.with_plugin(camera_debug_plugin)
|
|
||||||
.with_plugin(FreeFlyCameraPlugin)
|
|
||||||
.run()
|
|
||||||
.await;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn setup_scene_plugin(game: &mut Game) {
|
|
||||||
let world = game.world_mut();
|
|
||||||
let resman = world.get_resource_mut::<ResourceManager>();
|
|
||||||
let camera_gltf = resman
|
|
||||||
.request::<Gltf>("../assets/AntiqueCamera.glb")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
camera_gltf.wait_recurse_dependencies_load();
|
|
||||||
let camera_mesh = &camera_gltf.data_ref().unwrap().scenes[0];
|
|
||||||
drop(resman);
|
|
||||||
|
|
||||||
world.spawn((
|
|
||||||
camera_mesh.clone(),
|
|
||||||
WorldTransform::default(),
|
|
||||||
Transform::from_xyz(0.0, -5.0, 0.0),
|
|
||||||
));
|
|
||||||
|
|
||||||
{
|
|
||||||
let mut light_tran = Transform::from_xyz(1.5, 2.5, 0.0);
|
|
||||||
light_tran.scale = Vec3::new(0.5, 0.5, 0.5);
|
|
||||||
light_tran.rotate_x(math::Angle::Degrees(-45.0));
|
|
||||||
light_tran.rotate_y(math::Angle::Degrees(25.0));
|
|
||||||
world.spawn((
|
|
||||||
DirectionalLight {
|
|
||||||
enabled: true,
|
|
||||||
color: Vec3::ONE,
|
|
||||||
intensity: 0.15, //..Default::default()
|
|
||||||
},
|
|
||||||
light_tran,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut camera = CameraComponent::new_3d();
|
|
||||||
camera.transform.translation += math::Vec3::new(0.0, 0.0, 1.5);
|
|
||||||
world.spawn((camera, FreeFlyCamera::default()));
|
|
||||||
|
|
||||||
let fps_counter = |mut counter: ResMut<fps_counter::FPSCounter>,
|
|
||||||
delta: Res<DeltaTime>| -> anyhow::Result<()> {
|
|
||||||
let tick = counter.tick();
|
|
||||||
|
|
||||||
info!("FPS: {}, frame time: {}", tick, **delta);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
world.add_resource(fps_counter::FPSCounter::new());
|
|
||||||
|
|
||||||
let rotate_system = |dt: Res<DeltaTime>, view: View<&mut Transform>| -> anyhow::Result<()> {
|
|
||||||
const SPEED: f32 = 4.0;
|
|
||||||
let dt = **dt;
|
|
||||||
|
|
||||||
for mut transform in view.iter() {
|
|
||||||
info!("rotation: {:?}", transform.rotation);
|
|
||||||
transform.rotate_y(math::Angle::Degrees(SPEED * dt));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut sys = BatchedSystem::new();
|
|
||||||
sys.with_criteria(FixedTimestep::new(60));
|
|
||||||
sys.with_system(rotate_system.into_system());
|
|
||||||
sys.with_system(fps_counter.into_system());
|
|
||||||
|
|
||||||
game.with_system("fixed_timestep", sys, &[]);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FixedTimestep {
|
|
||||||
max_tps: u32,
|
|
||||||
fixed_time: f32,
|
|
||||||
accumulator: f32,
|
|
||||||
old_dt: Option<DeltaTime>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl FixedTimestep {
|
|
||||||
pub fn new(max_tps: u32) -> Self {
|
|
||||||
Self {
|
|
||||||
max_tps,
|
|
||||||
fixed_time: Self::calc_fixed_time(max_tps),
|
|
||||||
accumulator: 0.0,
|
|
||||||
old_dt: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn calc_fixed_time(max_tps: u32) -> f32 {
|
|
||||||
1.0 / max_tps as f32
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_tps(&mut self, tps: u32) {
|
|
||||||
self.max_tps = tps;
|
|
||||||
self.fixed_time = Self::calc_fixed_time(tps);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn tps(&self) -> u32 {
|
|
||||||
self.max_tps
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fixed_time(&self) -> f32 {
|
|
||||||
self.fixed_time
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Criteria for FixedTimestep {
|
|
||||||
fn can_run(&mut self, mut world: NonNull<World>, check_count: u32) -> CriteriaSchedule {
|
|
||||||
let world = unsafe { world.as_mut() };
|
|
||||||
if check_count == 0 {
|
|
||||||
let delta_time = world.get_resource::<DeltaTime>();
|
|
||||||
self.accumulator += **delta_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.accumulator >= self.fixed_time {
|
|
||||||
self.accumulator -= self.fixed_time;
|
|
||||||
return CriteriaSchedule::YesAndLoop;
|
|
||||||
}
|
|
||||||
|
|
||||||
CriteriaSchedule::No
|
|
||||||
}
|
|
||||||
|
|
||||||
fn modify_world(&mut self, mut world: NonNull<World>) {
|
|
||||||
let world = unsafe { world.as_mut() };
|
|
||||||
self.old_dt = world.try_get_resource().map(|r| *r);
|
|
||||||
|
|
||||||
world.add_resource(DeltaTime::from(self.fixed_time));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn undo_world_modifications(&mut self, mut world: NonNull<World>) {
|
|
||||||
let world = unsafe { world.as_mut() };
|
|
||||||
world.add_resource(
|
|
||||||
self.old_dt
|
|
||||||
.expect("DeltaTime resource was somehow never got from the world"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -7,7 +7,6 @@ struct FixedTimestep {
|
||||||
max_tps: u32,
|
max_tps: u32,
|
||||||
fixed_time: f32,
|
fixed_time: f32,
|
||||||
accumulator: f32,
|
accumulator: f32,
|
||||||
old_dt: Option<DeltaTime>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -17,7 +16,6 @@ impl FixedTimestep {
|
||||||
max_tps,
|
max_tps,
|
||||||
fixed_time: Self::calc_fixed_time(max_tps),
|
fixed_time: Self::calc_fixed_time(max_tps),
|
||||||
accumulator: 0.0,
|
accumulator: 0.0,
|
||||||
old_dt: None,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,21 +52,6 @@ impl Criteria for FixedTimestep {
|
||||||
|
|
||||||
CriteriaSchedule::No
|
CriteriaSchedule::No
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modify_world(&mut self, mut world: NonNull<World>) {
|
|
||||||
let world = unsafe { world.as_mut() };
|
|
||||||
self.old_dt = world.try_get_resource().map(|r| *r);
|
|
||||||
|
|
||||||
world.add_resource(DeltaTime::from(self.fixed_time));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn undo_world_modifications(&mut self, mut world: NonNull<World>) {
|
|
||||||
let world = unsafe { world.as_mut() };
|
|
||||||
world.add_resource(
|
|
||||||
self.old_dt
|
|
||||||
.expect("DeltaTime resource was somehow never got from the world"),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
use lyra_ecs::World;
|
use lyra_ecs::World;
|
||||||
use tracing::{debug_span, instrument};
|
use tracing::debug_span;
|
||||||
|
|
||||||
use crate::Access;
|
use crate::Access;
|
||||||
|
|
||||||
use super::{Criteria, GraphExecutorError, IntoSystem, System};
|
use super::{System, Criteria, IntoSystem};
|
||||||
|
|
||||||
/// A system that executes a batch of systems in order that they were given.
|
/// A system that executes a batch of systems in order that they were given.
|
||||||
/// You can optionally add criteria that must pass before the systems are
|
/// You can optionally add criteria that must pass before the systems are
|
||||||
|
@ -13,7 +13,6 @@ pub struct BatchedSystem {
|
||||||
systems: Vec<Box<dyn System>>,
|
systems: Vec<Box<dyn System>>,
|
||||||
criteria: Vec<Box<dyn Criteria>>,
|
criteria: Vec<Box<dyn Criteria>>,
|
||||||
criteria_checks: u32,
|
criteria_checks: u32,
|
||||||
did_run: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchedSystem {
|
impl BatchedSystem {
|
||||||
|
@ -48,7 +47,6 @@ impl System for BatchedSystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, world))]
|
|
||||||
fn execute(&mut self, world: std::ptr::NonNull<World>) -> anyhow::Result<()> {
|
fn execute(&mut self, world: std::ptr::NonNull<World>) -> anyhow::Result<()> {
|
||||||
let mut can_run = true;
|
let mut can_run = true;
|
||||||
let mut check_again = false;
|
let mut check_again = false;
|
||||||
|
@ -71,26 +69,13 @@ impl System for BatchedSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
if can_run {
|
if can_run {
|
||||||
for criteria in self.criteria.iter_mut() {
|
|
||||||
criteria.modify_world(world);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (idx, system) in self.systems.iter_mut().enumerate() {
|
for (idx, system) in self.systems.iter_mut().enumerate() {
|
||||||
let span = debug_span!("batch", system=idx);
|
let sys_span = debug_span!("batch", system=tracing::field::Empty);
|
||||||
let _e = span.enter();
|
sys_span.record("system", idx);
|
||||||
|
let _e = sys_span.enter();
|
||||||
|
|
||||||
system.execute(world)?;
|
system.execute(world)?;
|
||||||
|
|
||||||
/* let deferred_span = debug_span!("deferred_exec");
|
|
||||||
let _e = deferred_span.enter();
|
|
||||||
|
|
||||||
if let Err(e) = system.execute_deferred(world)
|
|
||||||
.map_err(|e| GraphExecutorError::Command(e)) {
|
|
||||||
return Err(e.into());
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.did_run = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if check_again {
|
if check_again {
|
||||||
|
@ -102,26 +87,9 @@ impl System for BatchedSystem {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self, world))]
|
fn execute_deferred(&mut self, _: std::ptr::NonNull<World>) -> anyhow::Result<()> {
|
||||||
fn execute_deferred(&mut self, world: std::ptr::NonNull<World>) -> anyhow::Result<()> {
|
todo!()
|
||||||
if self.did_run {
|
|
||||||
for (idx, system) in self.systems.iter_mut().enumerate() {
|
|
||||||
let span = debug_span!("batch", system=idx);
|
|
||||||
let _e = span.enter();
|
|
||||||
|
|
||||||
system.execute_deferred(world)
|
|
||||||
.map_err(|e| GraphExecutorError::Command(e))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
for criteria in self.criteria.iter_mut() {
|
|
||||||
criteria.undo_world_modifications(world);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.did_run = false;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,17 +26,13 @@ pub trait Criteria {
|
||||||
/// * `world` - The ecs world.
|
/// * `world` - The ecs world.
|
||||||
/// * `check_count` - The amount of times the Criteria has been checked this tick.
|
/// * `check_count` - The amount of times the Criteria has been checked this tick.
|
||||||
fn can_run(&mut self, world: NonNull<World>, check_count: u32) -> CriteriaSchedule;
|
fn can_run(&mut self, world: NonNull<World>, check_count: u32) -> CriteriaSchedule;
|
||||||
|
}
|
||||||
|
|
||||||
/// Modify the world after the [`Criteria`] in the system batch allows the systems to run.
|
impl<F> Criteria for F
|
||||||
///
|
where F: FnMut(&mut World, u32) -> CriteriaSchedule
|
||||||
/// This can be great if this Criteria limits the execution of systems based off of resources.
|
{
|
||||||
/// A `FixedTimestep` criteria would use this to replace the [`DeltaTime`] resource in the
|
fn can_run(&mut self, mut world: NonNull<World>, check_count: u32) -> CriteriaSchedule {
|
||||||
/// world to match the timestep time.
|
let world_mut = unsafe { world.as_mut() };
|
||||||
fn modify_world(&mut self, world: NonNull<World>);
|
self(world_mut, check_count)
|
||||||
|
}
|
||||||
/// Undo modifications to the world after the systems in the batch have been executed.
|
|
||||||
///
|
|
||||||
/// The `FixedTimestep` criteria (see docs for [`Criteria::modify_world`]) uses this
|
|
||||||
/// to replace the [`DeltaTime`] resource with its original value before it was replaced.
|
|
||||||
fn undo_world_modifications(&mut self, world: NonNull<World>);
|
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{any::TypeId, collections::HashMap, ptr::NonNull};
|
use std::{any::{Any, TypeId}, collections::HashMap, ptr::NonNull};
|
||||||
|
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,9 @@ use lyra_reflect::Reflect;
|
||||||
|
|
||||||
use crate::{plugin::Plugin, game::GameStages};
|
use crate::{plugin::Plugin, game::GameStages};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Component, Default, Reflect)]
|
#[derive(Clone, Component, Default, Reflect)]
|
||||||
pub struct DeltaTime(f32, #[reflect(skip)] Option<Instant>);
|
pub struct DeltaTime(f32, #[reflect(skip)] Option<Instant>);
|
||||||
|
|
||||||
impl From<f32> for DeltaTime {
|
|
||||||
fn from(value: f32) -> Self {
|
|
||||||
DeltaTime(value, None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::ops::Deref for DeltaTime {
|
impl std::ops::Deref for DeltaTime {
|
||||||
type Target = f32;
|
type Target = f32;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue