diff --git a/src/pipeline/events.rs b/src/pipeline/events.rs index 85b50926..363ed1a1 100644 --- a/src/pipeline/events.rs +++ b/src/pipeline/events.rs @@ -9,10 +9,13 @@ use rapier::pipeline::EventHandler; use std::collections::HashMap; use std::sync::RwLock; +#[cfg(doc)] +use crate::prelude::ActiveEvents; + /// Events occurring when two colliders start or stop colliding /// /// This will only get triggered if the entity has the -/// [`ActiveEvent::COLLISION_EVENTS`] flag enabled. +/// [`ActiveEvents::COLLISION_EVENTS`] flag enabled. #[derive(Event, Copy, Clone, Debug, PartialEq, Eq)] pub enum CollisionEvent { /// Event occurring when two colliders start colliding @@ -25,7 +28,7 @@ pub enum CollisionEvent { /// between two colliders exceed a threshold ([`ContactForceEventThreshold`]). /// /// This will only get triggered if the entity has the -/// [`ActiveEvent::CONTACT_FORCE_EVENTS`] flag enabled. +/// [`ActiveEvents::CONTACT_FORCE_EVENTS`] flag enabled. #[derive(Event, Copy, Clone, Debug, PartialEq)] pub struct ContactForceEvent { /// The first collider involved in the contact. @@ -119,3 +122,113 @@ impl<'a> EventHandler for EventQueue<'a> { } } } + +#[cfg(test)] +mod test { + use bevy::time::{TimePlugin, TimeUpdateStrategy}; + use systems::tests::HeadlessRenderPlugin; + + use crate::{plugin::*, prelude::*}; + + #[cfg(feature = "dim3")] + fn cuboid(hx: Real, hy: Real, hz: Real) -> Collider { + Collider::cuboid(hx, hy, hz) + } + #[cfg(feature = "dim2")] + fn cuboid(hx: Real, hy: Real, _hz: Real) -> Collider { + Collider::cuboid(hx, hy) + } + + #[test] + pub fn events_received() { + return main(); + + use bevy::prelude::*; + + #[derive(Resource, Reflect)] + pub struct EventsSaver { + pub events: Vec, + } + + impl Default for EventsSaver { + fn default() -> Self { + Self { + events: Default::default(), + } + } + } + + pub fn save_events( + mut events: EventReader, + mut saver: ResMut>, + ) { + for event in events.read() { + saver.events.push(event.clone()); + } + } + + fn run_test(app: &mut App) { + app.add_systems(PostUpdate, save_events::) + .add_systems(PostUpdate, save_events::) + .init_resource::>() + .init_resource::>(); + + // Simulates 60 updates per seconds + app.insert_resource(TimeUpdateStrategy::ManualDuration( + std::time::Duration::from_secs_f32(1f32 / 60f32), + )); + // 2 seconds should be plenty of time for the cube to fall on the + // lowest collider. + for _ in 0..120 { + app.update(); + } + let saved_collisions = app + .world() + .get_resource::>() + .unwrap(); + assert_eq!(saved_collisions.events.len(), 3); + let saved_contact_forces = app + .world() + .get_resource::>() + .unwrap(); + assert_eq!(saved_contact_forces.events.len(), 1); + } + + /// Adapted from events example + fn main() { + let mut app = App::new(); + app.add_plugins(( + HeadlessRenderPlugin, + TransformPlugin, + TimePlugin, + RapierPhysicsPlugin::::default(), + )) + .add_systems(Startup, setup_physics); + run_test(&mut app); + } + + pub fn setup_physics(mut commands: Commands) { + /* + * Ground + */ + commands.spawn(( + TransformBundle::from(Transform::from_xyz(0.0, -1.2, 0.0)), + cuboid(4.0, 1.0, 1.0), + )); + + commands.spawn(( + TransformBundle::from(Transform::from_xyz(0.0, 5.0, 0.0)), + cuboid(4.0, 1.5, 1.0), + Sensor, + )); + + commands.spawn(( + TransformBundle::from(Transform::from_xyz(0.0, 13.0, 0.0)), + RigidBody::Dynamic, + cuboid(0.5, 0.5, 0.5), + ActiveEvents::COLLISION_EVENTS | ActiveEvents::CONTACT_FORCE_EVENTS, + ContactForceEventThreshold(30.0), + )); + } + } +} diff --git a/src/plugin/systems/mod.rs b/src/plugin/systems/mod.rs index c513856c..c24571bb 100644 --- a/src/plugin/systems/mod.rs +++ b/src/plugin/systems/mod.rs @@ -61,7 +61,7 @@ pub fn step_simulation( } #[cfg(test)] -mod tests { +pub mod tests { use bevy::{ asset::AssetPlugin, ecs::event::Events,