Skip to content

Use a single layer as the default membership instead of all.#476

Merged
Jondolf merged 5 commits into
avianphysics:mainfrom
Aceeri:default-layers
Aug 22, 2024
Merged

Use a single layer as the default membership instead of all.#476
Jondolf merged 5 commits into
avianphysics:mainfrom
Aceeri:default-layers

Conversation

@Aceeri

@Aceeri Aceeri commented Aug 2, 2024

Copy link
Copy Markdown
Contributor

Objective

Using ALL memberships requires a lot more effort to correctly use the layer system in gameplay, since interactions you wanted exclusive to one object now trigger on all defaulted objects as well.

This system is similar to those used in Box2d (one memberships, all filters) and Godot (one memberships, one filters), however the current system is the same as Rapier and Unity (all memberships, all filters). Unity is actually exclusively one membership, all filters with configurable filters in your project.

Solution

  • Reserve layer 1 << 0 for a default layer.
    - Adjust PhysicsLayer derive to start at 1 << 1. keep it the same, just document the change, this shouldn't actually change any behavior aside from other special interactions relying on the default being all membership (which should be few and might indicate a bug)

Additional Questions

- Should we use the default layer for filters as well?
No, this doesn't make sense unless we swap to using || for the calculation and/or allow default configuration as it forbids some valid usecases like a default member not interacting with default.

Changelog

  • Reserved 1 << 0 as a default LayerMask, default CollisionLayers now only includes a single bit for membership, while including all bits for filters.

Migration Guide

  • Make sure your 1 << 0/1 collision layer is fine with being a default membership, you may need to add a CollisionLayers component to entities that have did not have one before to allow interactions to happen again. However this may also indicate a bug in logic.

@janhohenheim janhohenheim left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bit of a footgun regarding implicitness, but then again Bevy does the exact same thing with RenderLayers, so we are at least consistent.
In any case, this is way better then the current behavior, as I can just tell my Sensors to filter out CollisionLayers::DEFAULT.

@Aceeri

Aceeri commented Aug 4, 2024

Copy link
Copy Markdown
Contributor Author

Bit of a footgun regarding implicitness, but then again Bevy does the exact same thing with RenderLayers, so we are at least consistent. In any case, this is way better then the current behavior, as I can just tell my Sensors to filter out CollisionLayers::DEFAULT.

It's a footgun the current way too since you cannot actually ignore the default objects ever. E.g. you shape cast for a dumpster or interactable infront of the player, but it'll just return any physics object it touches aside from custom ones.

@janhohenheim

Copy link
Copy Markdown
Member

@Aceeri yes, I definitely agree

@Jondolf Jondolf left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've let this sit for a while (sorry about that!) but I'm largely in favor of this. I pushed a quick commit to fix some docs, and to add a Default variant to the enums, since imo it doesn't make sense for the Ground layer to be the default layer that everything belongs to. I hope that's fine; if you disagree on something, we can revert.

One thing I don't really like is how implicit the default is with the enum-based approach. For a follow-up, I think it could be interesting to require users to explicitly derive Default and specify the default layer with the #[default] attribute. I have this implemented already, so I'll put up a PR for consideration after this is merged.

@Jondolf Jondolf merged commit e443720 into avianphysics:main Aug 22, 2024
@Aceeri

Aceeri commented Aug 23, 2024

Copy link
Copy Markdown
Contributor Author

I've let this sit for a while (sorry about that!) but I'm largely in favor of this. I pushed a quick commit to fix some docs, and to add a Default variant to the enums, since imo it doesn't make sense for the Ground layer to be the default layer that everything belongs to. I hope that's fine; if you disagree on something, we can revert.

One thing I don't really like is how implicit the default is with the enum-based approach. For a follow-up, I think it could be interesting to require users to explicitly derive Default and specify the default layer with the #[default] attribute. I have this implemented already, so I'll put up a PR for consideration after this is merged.

Yeah I was considering that might be better and initially just changed the derive macro start at 2 instead of 1, but I agree with all those changes.

@Aceeri Aceeri deleted the default-layers branch August 23, 2024 00:43
Jondolf added a commit that referenced this pull request Aug 23, 2024
# Objective

#476 changed collision layers to reserve the first bit for a default layer. However, for enums implementing `PhysicsLayer`, the default layer is rather implicit and potentially footgunny.

The default layer should ideally be more explicit.

## Solution

Change `PhysicsLayer` to require `Default` to be implemented. The proc macro orders the variants such that the layer set as the default is always the first bit.

Note that `Default` *must* currently be derived instead of implemented manually, as the macro can only access the default variant if the `#[default]` attribute exists. An error is emitted if `#[default]` does not exist. If someone knows a way to make it work with the manual impl, let me know or consider opening a PR!

I also added documentation for the `PhysicsLayer` macro, and improved error handling.

---

## Migration Guide

Enums that derive `PhysicsLayer` must now also derive `Default` and specify a default layer using the `#[default]` attribute.

Before:

```rust
#[derive(PhysicsLayer)]
enum GameLayer {
    Player,
    Enemy,
    Ground,
}
```

After:

```rust
#[derive(PhysicsLayer, Default)]
enum GameLayer {
    #[default]
    Default, // The name doesn't matter, but Default is used here for clarity
    Player,
    Enemy,
    Ground,
}
```

The default layer always has the bit value `0b0001` regardless of its order relative to the other variants.

---------

Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
@Jondolf Jondolf added A-Collision Relates to the broad phase, narrow phase, colliders, or other collision functionality M-Migration-Guide A breaking change to Avian's public API that needs to be noted in a migration guide C-Usability A quality-of-life improvement that makes Avian easier to use labels Nov 27, 2024
Jondolf added a commit that referenced this pull request Feb 5, 2025
# Objective

#476 changed `CollisionLayers` to use one membership (the first layer) and all filters by default. However, `ColliderConstructorHierarchy` is still using the old default!

## Solution

Use `CollisionLayers::default()` (one membership, all filters) by default for `ColliderConstructorHierarchy`.

---

## Migration Guide

`ColliderConstructorHierarchy` now defaults to one membership (the first layer) and all filters for the `CollisionLayers` of generated colliders. This is consistent with how `CollisionLayers` already works normally.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-Collision Relates to the broad phase, narrow phase, colliders, or other collision functionality C-Usability A quality-of-life improvement that makes Avian easier to use M-Migration-Guide A breaking change to Avian's public API that needs to be noted in a migration guide

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants