#Mutable Vectors With Queries

17 messages · Page 1 of 1 (latest)

faint elk
#

I fear I might be Begging The Question here, but I attempt to push a variable to a vector of the type &mut Boid in a query, but iterating through the query returns Mut<'_, Boid>. Do I have to cast it? Refactor? Or is there another way?

Here's the code:

// Somewhere exists: pub static mut BOIDS: Vec<&mut Boid> = Vec::new();

pub fn start(mut query: Query<&mut Boid>)
        {
            for mut boid in query.iter_mut()
            {
                unsafe
                {
                    BOIDS.push(boid); // Of course this doesn't work, but how can I cast it?
                }
            }
        }

Thanks!

chrome tartan
#

static boids is basically a resource, nah?

#

what are you trying to do in the first place

umbral meadow
#

You are trying to query for a boid, so I guess it should be a component

#

And then you try to put the reference of your boid into the static BOIDS

#

But this is surely going to lead to a few problems:

  1. you now have the unique mutable borrow of the bond inside BOIDS, so it can't be used anywhere else (any other systems)
  2. the lifetime of a bond reference is probably shorter than of BOIDS
    There's probably a but more I'm missing
#

If you want to store all your Boids in one place, use a boids resource which is just a Vec<Boid>

#

Otherwise what's wrong with just querying for the boids each time you use them?

twilit flower
#

Mut<'_, T> implements DerefMut<Target=T>, so you can just do &mut*boid to get a &mut T.

However your snippet of code has much bigger problems than this:

  • don't use mutable statics, they are almost never what you want
  • don't use unsafe if you don't 100% know what you're doing and what are all the caveats associated to the specific unsafe operation you're doing
  • don't store mutable references persistently (e.g. in a static or a resource). References you get from queries are only valid as long you're in the system which has that query, and only for that specific invocation of it. The borrow checker will yell at you if you try this and using unsafe to make it shut up won't solve the underlying problem. Either make a copy of the component or store Entity
faint elk
# twilit flower `Mut<'_, T>` implements `DerefMut<Target=T>`, so you can just do `&mut*boid` to ...

Thank you so much! (To Comma as well of course).

I'm sure you can tell I come from an wait for it OOP langauge, as using statics come naturally to me. However, I can tell that statics in rust and statics in C++ or C# (ewww) are very different, due to the ownership and borrowing system.

So my question is: how might I go about having a global vector that stores mutable types accessible from the module or component?

twilit flower
#

The solution in Bevy is that you just use a Query. Queries are what give you access to components. You don't and can't store references to components anywhere.

#

BTW globals/statics are also generally a bad practice in OOP languages

#

There's a reason they invented the dependency injection pattern

#

In Rust the problem is much less present because statics are much more restricted, but the result is kinda the same in that dependency injection is everywhere but we just don't call it explicitly with that name

#

For example system parameters in Bevy are a form of dependency injection (hence why the solution is to just use a Query, because it means using dependency injection)

umbral meadow
#

Considering you are using boids, I imagine each boid is an entity with a transform and velocity component, alongside perhaps a marker component. Since each boid moves according to the others, most likely you will want to Query<(&mut GlobalTransform, &mut Velocity), With<Boid>>. What you then do inside the system with this query is up to you

faint elk
#

Yep, all of what you both said definitely proved that I was indeed Begging The Question. The easiest method, in hindsight would just be using queries. Thank you!