Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use hooks for component initialization #483

Merged
merged 2 commits into from
Aug 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 32 additions & 38 deletions src/collision/collider/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,37 @@ impl<C: ScalableCollider> Plugin for ColliderBackendPlugin<C> {
app.insert_resource(ColliderRemovalSystem(collider_removed_id));
}

let hooks = app.world_mut().register_component_hooks::<C>();

// Initialize missing components for colliders.
hooks.on_add(|mut world, entity, _| {
let entity_ref = world.entity(entity);

let collider = entity_ref.get::<C>().unwrap();
let aabb = entity_ref
.get::<ColliderAabb>()
.copied()
.unwrap_or(collider.aabb(Vector::ZERO, Rotation::default()));
let density = entity_ref
.get::<ColliderDensity>()
.copied()
.unwrap_or_default();

let mass_properties = if entity_ref.get::<Sensor>().is_some() {
ColliderMassProperties::ZERO
} else {
collider.mass_properties(density.0)
};

world.commands().entity(entity).try_insert((
aabb,
density,
mass_properties,
CollidingEntities::default(),
ColliderMarker,
));
});

// 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 +228,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 +244,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 @@ -250,43 +278,9 @@ impl<C: ScalableCollider> Plugin for ColliderBackendPlugin<C> {
#[derive(Reflect, Component, Clone, Copy, Debug)]
pub struct ColliderMarker;

/// Initializes missing components for [colliders](Collider).
#[allow(clippy::type_complexity)]
pub(crate) fn init_colliders<C: AnyCollider>(
mut commands: Commands,
mut colliders: Query<
(
Entity,
&C,
Option<&ColliderAabb>,
Option<&ColliderDensity>,
Has<Sensor>,
),
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,
));
}
}

/// 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
6 changes: 2 additions & 4 deletions src/collision/collider/hierarchy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,16 +58,14 @@ 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)
.after(PrepareSet::PropagateTransforms)
.before(PrepareSet::Finalize),
);

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