commit 3de1eca78baa0d9f3434c482aa75b5055af5a5b9
parent c1fcfed98c47602cf4266188fcf36b0635ca97be
Author: Joël Lupien <jojolepromain@gmail.com>
Date: Mon, 11 Feb 2019 04:34:58 -0500
Timestep debug info (#19)
* Better error message for physics stepper timestep change.
* More debug messages for physics stepper.
* Added a way to change the timestep at runtime. Added reset and timestep change keybinds for the amethyst example.
Diffstat:
3 files changed, 54 insertions(+), 30 deletions(-)
diff --git a/examples/amethyst.rs b/examples/amethyst.rs
@@ -1,13 +1,15 @@
use amethyst::assets::{Handle, Loader};
use amethyst::core::nalgebra::{Matrix3, Vector3};
use amethyst::core::specs::world::Builder;
+use amethyst::core::specs::Join;
use amethyst::core::{GlobalTransform, Transform, TransformBundle};
use amethyst::renderer::{
AmbientColor, Camera, DisplayConfig, DrawShaded, Light, Material, MaterialDefaults, MeshData,
MeshHandle, Pipeline, PointLight, PosNormTex, RenderBundle, Rgba, ScreenDimensions, Shape,
- Stage, Texture,
+ Stage, Texture, VirtualKeyCode,
};
-use amethyst::{Application, GameData, GameDataBuilder, SimpleState, StateData};
+use amethyst::input::{is_close_requested, is_key_down};
+use amethyst::{Application, GameData, GameDataBuilder, SimpleState, StateData, StateEvent, SimpleTrans, Trans};
use nphysics_ecs_dumb::ncollide::shape::{Ball, ShapeHandle};
use nphysics_ecs_dumb::nphysics::math::Velocity;
use nphysics_ecs_dumb::nphysics::object::Material as PhysicsMaterial;
@@ -45,7 +47,7 @@ impl SimpleState for GameState {
(resolution.width(), resolution.height())
};
- let camera_transform = Transform::from(Vector3::new(0.0, 0.0, 0.0));
+ let camera_transform = Transform::from(Vector3::new(0.0, 5.0, 5.0));
// Add Camera
data.world
@@ -81,7 +83,7 @@ impl SimpleState for GameState {
.create_entity()
.with(sphere_handle.clone())
.with(material.clone())
- .with(Transform::from(Vector3::new(0.0, 3.0, -10.0)))
+ .with(Transform::from(Vector3::new(0.0, 15.0, -10.0)))
.with(GlobalTransform::default())
.with(DynamicBody::new_rigidbody_with_velocity(
Velocity::linear(0.0, 1.0, 0.0),
@@ -148,6 +150,45 @@ impl SimpleState for GameState {
material.clone(),
);*/
}
+
+ fn handle_event(
+ &mut self,
+ data: StateData<'_, GameData<'_, '_>>,
+ event: StateEvent,
+ ) -> SimpleTrans {
+ if let StateEvent::Window(event) = &event {
+ // Exit if user hits Escape or closes the window
+ if is_close_requested(&event) || is_key_down(&event, VirtualKeyCode::Escape) {
+ return Trans::Quit;
+ }
+
+ //
+ if is_key_down(&event, VirtualKeyCode::T) {
+ *data.world.write_resource::<TimeStep>() = TimeStep::Fixed(1./120.);
+ println!("Setting timestep to 1./120.");
+ }
+
+ if is_key_down(&event, VirtualKeyCode::Y) {
+ *data.world.write_resource::<TimeStep>() = TimeStep::Fixed(1./60.);
+ println!("Setting timestep to 1./60.");
+ }
+
+ if is_key_down(&event, VirtualKeyCode::S) {
+ *data.world.write_resource::<TimeStep>() = TimeStep::SemiFixed(TimeStepConstraint::new(
+ vec![1. / 240., 1. / 120., 1. / 60.],
+ 0.4,
+ Duration::from_millis(50),
+ Duration::from_millis(500),
+ ))
+ }
+
+ // Reset the example
+ if is_key_down(&event, VirtualKeyCode::Space) {
+ *(&mut data.world.write_storage::<Transform>(), &data.world.read_storage::<DynamicBody>()).join().next().unwrap().0.translation_mut() = Vector3::new(0.0, 15.0, -10.0);
+ }
+ }
+ Trans::None
+ }
}
fn main() -> amethyst::Result<()> {
@@ -181,12 +222,6 @@ fn main() -> amethyst::Result<()> {
.with_bundle(
PhysicsBundle::new()
.with_dep(&["transform_system"])
- .with_timestep(TimeStep::SemiFixed(TimeStepConstraint::new(
- vec![1. / 240., 1. / 120., 1. / 60.],
- 0.4,
- Duration::from_millis(50),
- Duration::from_millis(500),
- )))
.with_timestep_iter_limit(20),
)?
.with_bundle(RenderBundle::new(pipe, Some(display_config)))?;
diff --git a/src/systems/mod.rs b/src/systems/mod.rs
@@ -9,8 +9,6 @@ use amethyst::core::specs::DispatcherBuilder;
use amethyst::error::Error;
use core::result::Result;
-use crate::time_step::TimeStep;
-
pub use self::physics_stepper::PhysicsStepperSystem;
pub use self::sync_bodies_from_physics::*;
pub use self::sync_bodies_to_physics::SyncBodiesToPhysicsSystem;
@@ -25,7 +23,6 @@ pub const SYNC_BODIES_FROM_PHYSICS_SYSTEM: &str = "sync_bodies_from_physics_syst
pub struct PhysicsBundle<'a> {
dep: &'a [&'a str],
- timestep: TimeStep,
timestep_iter_limit: i32,
}
@@ -33,7 +30,6 @@ impl Default for PhysicsBundle<'_> {
fn default() -> Self {
Self {
dep: Default::default(),
- timestep: Default::default(),
timestep_iter_limit: 10,
}
}
@@ -49,12 +45,6 @@ impl<'a> PhysicsBundle<'a> {
self
}
- /// Set the timestep to use for the `PhysicsStepperSystem`
- pub fn with_timestep(mut self, timestep: TimeStep) -> Self {
- self.timestep = timestep;
- self
- }
-
/// Set the maximum number of physics timesteps to simulate in a single run of the `PhysicsStepperSystem`
pub fn with_timestep_iter_limit(mut self, timestep_iter_limit: i32) -> Self {
self.timestep_iter_limit = timestep_iter_limit;
@@ -82,7 +72,7 @@ impl<'a, 'b, 'c> SystemBundle<'a, 'b> for PhysicsBundle<'c> {
);
builder.add(
- PhysicsStepperSystem::new(self.timestep, self.timestep_iter_limit),
+ PhysicsStepperSystem::new(self.timestep_iter_limit),
PHYSICS_STEPPER_SYSTEM,
&[
SYNC_BODIES_TO_PHYSICS_SYSTEM,
diff --git a/src/systems/physics_stepper.rs b/src/systems/physics_stepper.rs
@@ -1,7 +1,7 @@
use crate::time_step::TimeStep;
use crate::PhysicsWorld;
use amethyst::core::Time;
-use amethyst::ecs::{Read, System, WriteExpect};
+use amethyst::ecs::{Read, System, WriteExpect, Write};
use std::f32::EPSILON;
use std::time::Instant;
@@ -13,7 +13,6 @@ const TIME_STEP_DECREASE_HYSTERESIS: f32 = 1.5;
/// Simulates a step of the physics world.
pub struct PhysicsStepperSystem {
- intended_timestep: TimeStep,
timestep_iter_limit: i32,
time_accumulator: f32,
avg_step_time: Option<f32>,
@@ -22,7 +21,6 @@ pub struct PhysicsStepperSystem {
impl Default for PhysicsStepperSystem {
fn default() -> Self {
PhysicsStepperSystem {
- intended_timestep: TimeStep::Fixed(1. / 120.),
timestep_iter_limit: 10,
time_accumulator: 0.,
avg_step_time: None,
@@ -31,9 +29,8 @@ impl Default for PhysicsStepperSystem {
}
impl PhysicsStepperSystem {
- pub fn new(intended_timestep: TimeStep, timestep_iter_limit: i32) -> Self {
+ pub fn new(timestep_iter_limit: i32) -> Self {
PhysicsStepperSystem {
- intended_timestep,
timestep_iter_limit,
time_accumulator: 0.,
avg_step_time: None,
@@ -42,11 +39,11 @@ impl PhysicsStepperSystem {
}
impl<'a> System<'a> for PhysicsStepperSystem {
- type SystemData = (WriteExpect<'a, PhysicsWorld>, Read<'a, Time>);
+ type SystemData = (WriteExpect<'a, PhysicsWorld>, Read<'a, Time>, Write<'a, TimeStep>);
// Simulate world using the current time frame
- fn run(&mut self, (mut physical_world, time): Self::SystemData) {
- let (timestep, mut change_timestep) = match &mut self.intended_timestep {
+ fn run(&mut self, (mut physical_world, time, mut intended_timestep): Self::SystemData) {
+ let (timestep, mut change_timestep) = match &mut *intended_timestep {
TimeStep::Fixed(timestep) => (*timestep, false),
TimeStep::SemiFixed(constraint) => {
let mut timestep = (constraint.current_timestep(), false);
@@ -94,11 +91,12 @@ impl<'a> System<'a> for PhysicsStepperSystem {
};
if (physical_world.timestep() - timestep).abs() > EPSILON && !change_timestep {
- warn!("Physics world timestep out of sync with intended timestep! Leave me alone!!!");
+ warn!("Physics world timestep out of sync with intended timestep! Physics timestep: {}, Requested timestep: {}", physical_world.timestep(), timestep);
change_timestep = true;
}
if change_timestep {
+ trace!("Changing physics timestep to {}", timestep);
// reset average when changing timestep
self.avg_step_time = None;
physical_world.set_timestep(timestep);
@@ -110,6 +108,7 @@ impl<'a> System<'a> for PhysicsStepperSystem {
while steps <= self.timestep_iter_limit && self.time_accumulator >= timestep {
let physics_time = Instant::now();
+ trace!("Stepping physics system. Step: {}, Timestep: {}, Time accumulator: {}", steps, timestep, self.time_accumulator);
physical_world.step();
let physics_time = physics_time.elapsed();