Create an example project to test transform interpolation
This commit is contained in:
parent
53837d469b
commit
db501015d0
|
@ -947,6 +947,18 @@ 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"]
|
"lyra-game", "lyra-math", "lyra-scene", "examples/many-lights", "examples/fixed-timestep-rotating-model"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
scripting = ["dep:lyra-scripting"]
|
scripting = ["dep:lyra-scripting"]
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
[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
|
|
@ -0,0 +1,241 @@
|
||||||
|
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,6 +7,7 @@ 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)]
|
||||||
|
@ -16,6 +17,7 @@ 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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +54,21 @@ 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,4 +1,4 @@
|
||||||
use std::{any::{Any, TypeId}, collections::HashMap, ptr::NonNull};
|
use std::{any::TypeId, collections::HashMap, ptr::NonNull};
|
||||||
|
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefMut};
|
||||||
|
|
||||||
|
|
|
@ -4,9 +4,15 @@ use lyra_reflect::Reflect;
|
||||||
|
|
||||||
use crate::{plugin::Plugin, game::GameStages};
|
use crate::{plugin::Plugin, game::GameStages};
|
||||||
|
|
||||||
#[derive(Clone, Component, Default, Reflect)]
|
#[derive(Clone, Copy, 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