Skip to content

Suggestion: A variant of ChangeTrackers that also allows access to the component #7066

Closed

Description

@recatek

What problem does this solve or what need does it fill?

Suppose you have a system that you want to run if any of components A, B, and C are changed, but you want to know which of the three specifically changed when the system has run. Bevy currently presents you with two different ways to do this:

fn some_system(q: Query<(&A, &B, &C, ChangeTrackers<A>, ChangeTrackers<B>, ChangeTrackers<C>)>) {
    for (a, b, c, t1, t2, t3) in q.iter() {
        if (t1.is_changed()) {
            // ...
        }
        if (t2.is_changed()) {
            // ...
        }
        if (t3.is_changed()) {
            // ...
        }
    }
}
fn some_system(mut q: Query<(&mut A, &mut B, &mut C)>) {
    for (&mut a, &mut b, &mut c) in q.iter_mut() {
        if (a.is_changed()) {
            // ...
        }
        if (b.is_changed()) {
            // ...
        }
        if (c.is_changed()) {
            // ...
        }
    }
}

Neither of these are ideal. The former is pretty verbose and makes query grow at double their normal rate. The second forces you to be overly pessimistic when locking components and prevents potential system-level parallelism on component bands even when you don't want to mutably access them.

What solution would you like?

Some Query decorator that provides an is_changed() and is_added() accessor to a component reference, while also allowing immutable access to the component itself, without the pessimistic lock of mutable access.

What alternative(s) have you considered?

The above two options work for now. The first one is functional and meets the requirements of the task without harming parallelism (to my knowledge), but it isn't very ergonomic.

Additional context

We discussed this on Discord here: https://discord.com/channels/691052431525675048/1058204047791898684

One thing that came up is that keeping ChangeTrackers separate from the component reference may be good for data locality reasons (creating a SoA instead of AoS setup in interation). However, some back-of-the-envelope benchmarks indicated that the &mut approach was faster. I don't know enough about the internals to really say which might be more performant, but it is a valid consideration.

Activity

  1. added
    C-FeatureA new feature, making something new possible
    S-Needs-TriageThis issue needs to be labelled
    on Dec 31, 2022
  2. added
    A-ECSEntities, components, systems, and events
    C-UsabilityA targeted quality-of-life change that makes Bevy easier to use
    and removed
    S-Needs-TriageThis issue needs to be labelled
    on Dec 31, 2022
  3. added 6 commits that reference this issue on Jan 9, 2023
    8045c3e
    01868f8
    6cded5c
    8752488
    4790c0d
    9dd8fbc
  4. added a commit that references this issue on Jan 22, 2023
    041823e
  5. added a commit that references this issue on Feb 1, 2023
    95433d2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ECSEntities, components, systems, and eventsC-FeatureA new feature, making something new possibleC-UsabilityA targeted quality-of-life change that makes Bevy easier to use

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions