Skip to content

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

@recatek

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.

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