Skip to content

Commit

Permalink
Use hooks and observers for component initialization
Browse files Browse the repository at this point in the history
  • Loading branch information
Jondolf committed Aug 9, 2024
1 parent b620e2b commit 80cf108
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 234 deletions.
50 changes: 25 additions & 25 deletions src/collision/collider/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ impl<C: ScalableCollider> Plugin for ColliderBackendPlugin<C> {
app.insert_resource(ColliderRemovalSystem(collider_removed_id));
}

// Initialize missing components for colliders.
app.observe(on_add_collider::<C>);

// Register a component hook that updates mass properties of rigid bodies
// when the colliders attached to them are removed.
// Also removes `ColliderMarker` components.
Expand Down Expand Up @@ -197,7 +200,6 @@ impl<C: ScalableCollider> Plugin for ColliderBackendPlugin<C> {
app.add_systems(
self.schedule,
(
init_colliders::<C>.in_set(PrepareSet::InitColliders),
init_transforms::<C>
.in_set(PrepareSet::InitTransforms)
.after(init_transforms::<RigidBody>),
Expand All @@ -214,9 +216,7 @@ impl<C: ScalableCollider> Plugin for ColliderBackendPlugin<C> {
// Update collider parents for colliders that are on the same entity as the rigid body.
app.add_systems(
self.schedule,
update_root_collider_parents::<C>
.after(PrepareSet::InitColliders)
.before(PrepareSet::Finalize),
update_root_collider_parents::<C>.before(PrepareSet::Finalize),
);

let physics_schedule = app
Expand Down Expand Up @@ -251,12 +251,11 @@ impl<C: ScalableCollider> Plugin for ColliderBackendPlugin<C> {
pub struct ColliderMarker;

/// Initializes missing components for [colliders](Collider).
#[allow(clippy::type_complexity)]
pub(crate) fn init_colliders<C: AnyCollider>(
pub(crate) fn on_add_collider<C: AnyCollider>(
trigger: Trigger<OnAdd, C>,
mut commands: Commands,
mut colliders: Query<
colliders: Query<
(
Entity,
&C,
Option<&ColliderAabb>,
Option<&ColliderDensity>,
Expand All @@ -265,28 +264,29 @@ pub(crate) fn init_colliders<C: AnyCollider>(
Added<C>,
>,
) {
for (entity, collider, aabb, density, is_sensor) in &mut colliders {
let density = *density.unwrap_or(&ColliderDensity::default());
let mass_properties = if is_sensor {
ColliderMassProperties::ZERO
} else {
collider.mass_properties(density.0)
};

commands.entity(entity).try_insert((
*aabb.unwrap_or(&collider.aabb(Vector::ZERO, Rotation::default())),
density,
mass_properties,
CollidingEntities::default(),
ColliderMarker,
));
}
let Ok((collider, aabb, density, is_sensor)) = colliders.get(trigger.entity()) else {
return;
};

let density = *density.unwrap_or(&ColliderDensity::default());
let mass_properties = if is_sensor {
ColliderMassProperties::ZERO
} else {
collider.mass_properties(density.0)
};

commands.entity(trigger.entity()).try_insert((
*aabb.unwrap_or(&collider.aabb(Vector::ZERO, Rotation::default())),
density,
mass_properties,
CollidingEntities::default(),
ColliderMarker,
));
}

/// Updates [`ColliderParent`] for colliders that are on the same entity as the [`RigidBody`].
///
/// The [`ColliderHierarchyPlugin`] should be used to handle hierarchies.
#[allow(clippy::type_complexity)]
fn update_root_collider_parents<C: AnyCollider>(
mut commands: Commands,
mut bodies: Query<
Expand Down
8 changes: 2 additions & 6 deletions src/collision/collider/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,13 @@ impl Plugin for ColliderHierarchyPlugin {

app.configure_sets(
self.schedule,
MarkColliderAncestors
.after(PrepareSet::InitColliders)
.before(PrepareSet::PropagateTransforms),
MarkColliderAncestors.before(PrepareSet::PropagateTransforms),
);

// Update collider parents.
app.add_systems(
self.schedule,
update_collider_parents
.after(PrepareSet::InitColliders)
.before(PrepareSet::Finalize),
update_collider_parents.before(PrepareSet::Finalize),
);

// Run transform propagation if new colliders without rigid bodies have been added.
Expand Down
51 changes: 17 additions & 34 deletions src/dynamics/ccd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,11 +226,11 @@
//! Finally, making the [physics timestep](Physics) smaller can also help.
//! However, this comes at the cost of worse performance for the entire simulation.

use crate::{collision::broad_phase::AabbIntersections, prelude::*, prepare::PrepareSet};
use crate::{collision::broad_phase::AabbIntersections, prelude::*};
#[cfg(any(feature = "parry-f32", feature = "parry-f64"))]
use bevy::ecs::query::QueryData;
use bevy::{
ecs::{intern::Interned, schedule::ScheduleLabel},
ecs::component::{ComponentHooks, StorageType},
prelude::*,
};
use derive_more::From;
Expand All @@ -240,36 +240,12 @@ use parry::query::{
};

/// A plugin for [Continuous Collision Detection](self).
pub struct CcdPlugin {
schedule: Interned<dyn ScheduleLabel>,
}

impl CcdPlugin {
/// Creates a [`CcdPlugin`] with the schedule that is used for running the [`PhysicsSchedule`].
///
/// The default schedule is `PostUpdate`.
pub fn new(schedule: impl ScheduleLabel) -> Self {
Self {
schedule: schedule.intern(),
}
}
}

impl Default for CcdPlugin {
fn default() -> Self {
Self::new(PostUpdate)
}
}
pub struct CcdPlugin;

impl Plugin for CcdPlugin {
fn build(&self, app: &mut App) {
app.register_type::<SweptCcd>().register_type::<SweepMode>();

app.add_systems(
self.schedule,
init_ccd_aabb_intersections.in_set(PrepareSet::InitColliders),
);

// Get the `PhysicsSchedule`, and panic if it doesn't exist.
let physics = app
.get_schedule_mut(PhysicsSchedule)
Expand Down Expand Up @@ -397,7 +373,7 @@ impl SpeculativeMargin {
/// ));
/// }
/// ```
#[derive(Component, Clone, Copy, Debug, PartialEq, Reflect)]
#[derive(Clone, Copy, Debug, PartialEq, Reflect)]
#[reflect(Component)]
pub struct SweptCcd {
/// The type of sweep used for swept CCD.
Expand Down Expand Up @@ -481,6 +457,19 @@ impl SweptCcd {
}
}

impl Component for SweptCcd {
const STORAGE_TYPE: StorageType = StorageType::Table;

fn register_component_hooks(hooks: &mut ComponentHooks) {
hooks.on_add(|mut world, entity, _| {
world
.commands()
.entity(entity)
.insert(AabbIntersections::default());
});
}
}

/// The algorithm used for [Swept Continuous Collision Detection](self#swept-ccd).
///
/// If two entities with different sweep modes collide, [`SweepMode::NonLinear`]
Expand Down Expand Up @@ -510,12 +499,6 @@ pub enum SweepMode {
NonLinear,
}

fn init_ccd_aabb_intersections(mut commands: Commands, query: Query<Entity, Added<SweptCcd>>) {
for entity in &query {
commands.entity(entity).insert(AabbIntersections::default());
}
}

#[cfg(any(feature = "parry-f32", feature = "parry-f64"))]
#[derive(QueryData)]
#[query_data(mutable)]
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -735,9 +735,9 @@ impl PluginGroup for PhysicsPlugins {
.add(ContactReportingPlugin)
.add(IntegratorPlugin::default())
.add(SolverPlugin::new_with_length_unit(self.length_unit))
.add(CcdPlugin::new(self.schedule))
.add(CcdPlugin)
.add(SleepingPlugin)
.add(SpatialQueryPlugin::new(self.schedule))
.add(SpatialQueryPlugin)
.add(SyncPlugin::new(self.schedule))
}
}
Loading

0 comments on commit 80cf108

Please sign in to comment.