Jondolf / avian

ECS-driven 2D and 3D physics engine for the Bevy game engine.
https://crates.io/crates/avian3d
Apache License 2.0
1.5k stars 119 forks source link

[FeatureRequest] Add a way to add multiple `RayCaster` or `ShapeCater` on an entity. #515

Closed Aleod-m closed 1 month ago

Aleod-m commented 2 months ago

As described in the title.

One implementation that is interresting as it preserve current api:

pub trait CasterTag {}

pub struct DefaultRayCaster;
impl CasterTag for DefaultRayCaster {}

#[derive(Component)]
pub struct TaggedRayCaster<T: CasterTag> { ... }

impl<T: CasterTag> TaggedRayCaster<T> { ... }

pub type RayCaster = TaggedRayCaster<DefaultRayCaster>;

pub RayCasterPlugin<CasterTag>(PhantomData<CasterTag>);

impl<T: CasterTag> Plugin for RayCaterPlugin<T> {
    fn build(&mut self) -> {
        app.add_systems(raycaster_system::<T>)
            ...
    }
}
Jondolf commented 1 month ago

The intended way to have multiple ray or shape casters on an entity is to simply add them as child entities.

commands.spawn((
    SpatialBundle::default(),
    // ...the rest of your components
))
.with_children(|child_builder| {
    child_builder.spawn(RayCaster::new(Vec3::new(-2.0, 0.0), Dir3::NEG_Y));
    child_builder.spawn(RayCaster::new(Vec3::new(2.0, 0.0), Dir3::NEG_Y));
});

These should automatically follow the parent entity.

Having multiple ray caster components on a single entity would make queries more annoying, and it wouldn't be very ECS-friendly. We could extend the generic tag approach proposed here to almost any component, like colliders, joints, or even Bevy's meshes and sprites, but it's just generally not a good idea to have multiple instances of a "thing" on a single entity.

If you need to tag entities, use marker components, and if you need multiple instances of something, use a separate entity for each instance. If those entities should be attached to another entity, add them as children.