#How would I do this for more than 1 entity?

58 messages · Page 1 of 1 (latest)

narrow hawk
#

So I'm using this let mut ground_pos = ground_transform.single_mut(); let x = ground_pos.translation.x; to get the x of one entity but then when I spawn that entity again it panics because it's "single_mut". What is an alternative that works for multiple entities at once? Iter mut gives me an error on "translation".

tiny thunder
#

many_mut and related friends

narrow hawk
#

it expects 1 argument "entities" what exactly do I put there

#

like ""ground_query: Query<Entity, With<Ground>>"" ?

#

and then ground_query

tiny thunder
#

For example, to work with two entities you might call many_mut([entity_a, entity_b])

narrow hawk
#

well I'm basically spawning 1 entity twice

tiny thunder
#

Well you can't mutably access one entity more than once at a time

narrow hawk
#

I see

tiny thunder
#

You need to guarantee that any mutable access to an entity is unique

narrow hawk
#

I think I know how to do it using single_mut

#

nvm

#

I'm trying to make an endless runner that spawns the ground again once the old one is close to finishing

#

idk how to explain it

#

basically make an infinite ground

#

so I'm trying to detect when the x of the end of the ground approaches 10 pixels ahead of the right border

#

and then spawn another ground

#

but then when the second ground spawns

#

my game crashes

#

because the ground is spawned twice and I'm using single mut

tiny thunder
#

Yes, I would generally avoid using single and friends unless you know you'll have exactly one

narrow hawk
#

I didn't know it worked like that

tiny thunder
#

Instead, iterate the query and just assume that the logic may repeat for each instance

narrow hawk
#

I can send you the system it's pretty simple

#
pub fn obstacles(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut ground_transform: Query<&mut Transform, With<Ground>>,
    obstacles: ResMut<Obstacles>,
) {
    if obstacles.run {

        // Move the ground
        let mut ground_pos = ground_transform.single_mut();
        let x = ground_pos.translation.x;

        ground_pos.translation.x -= 10.0;

        if x == 1410.0 {
            commands.spawn((SpriteBundle {
                transform: Transform::from_xyz(0.0, -378.0, 0.0),
                texture: asset_server.load("ground.png"), 
                ..Default::default()
            },
            Ground,
            ))
            .insert(RigidBody::KinematicVelocityBased);

            
        }

    }
    
}
``` Keep in mind I have't played around with the coordinates so they aren't really accurate
#

its set to 1410 rn as the screen widht is 1400 but it spawns the second ground when the first one is in the middle of the screen but i'll fix that later

#

also ignore obstacles.run

tiny thunder
#

Really those units don't matter much in the grand scheme

narrow hawk
#

I need to fix the error first, then I'll play around with the coordinates

#

by error I mean it crashes when the ground tries to spawn again

#

Do you have any suggestions?

#

I know you said something about iterating the query but I'm not sure how that would work

#

I actually don't even have the qeury there at the moment

tiny thunder
#

One route involves using a special marker component. Essentially, when you go to spawn a new ground you:

  • Remove the marker from the current ground
  • Spawn new ground with the marker
    At the same time, you can look for the ground without a marker component (this is the "old" ground) and despawn it. This effectively buffers two ground chunks for your runner.
narrow hawk
#

that could work

tiny thunder
#

You can use hierarchy to achieve an effectively infinite ground plane. Structure it essentially as a parent entity representing the ground, and all its children represent chunks.
You start off querying for this parent (using a unique marker) and get its Children component. The children's last() will give you the Entity for the latest ground chunk (the one you want to check against), which you can plugin to a second Query using single(entity) and friends to do the same work.
As a bonus, you can check for the children's length against some pre-determined size, and start despawning the first once it exceeds that limit, thus giving you as many chunks as you want

narrow hawk
#

that sounds complicated

tiny thunder
#

It's a very useful pattern for a lot of things in general

#

Probably overcomplicated for this specific case (hence the other suggestion first), but much more flexible

narrow hawk
#

how do marker components work?

#

I can't find any documentation

tiny thunder
#

Basically you just define some random struct like rs #[derive(Component)] pub struct SomeNameYo; and attach it to an entity. Now you can With<SomeNameYo> in your query, and it will uniquely identify that entity

narrow hawk
#

I do have one of these attached to it

#

it's called "Ground"

#

how would I despawn the old one if I remove it from it

#

you suggested removing "Ground" from the old one then spawning a new one but then I wouldn't be able to despawn the old one I think

#

What if I used a timer to spawn the grounds

#

that should work

#

depsawning them also would work

#

as I know I can despawn multiple entities at ones with the same component attached to them

tiny thunder
#

In this case, you would keep "Ground" on all of these and use another like "LatestGround" to uniquely identify the newest one

narrow hawk
#

Your suggestion should work but I feel like using a timer to just spawn a new ground every X seconds and despawning the old ones if they leave the screen would be much easier

#

I know the despawning will work cuz I have a similar thing in my old project

#

and the timer part is really easy as well

#

I'm gonna try the timer solution and if it doesn't work I'll try your suggestion. I'll also keep this post open for now.

#

Thank you for the help

tiny thunder
#

Or in the case of using parent rs parent_query: Query<&Children, With<Ground>>, child_query: Query<&mut Transform, Without<Ground>>,

// Here we've already checked and decided that we need to spawn a new ground chunk
let children = parent_query.single();
if let Some(child) = children.last() {
    if let Ok(latest_ground_transform) = child_query.get(child) {
        // Do stuff with the latest chunk of ground
    }
}
if children.len() >= 10 { // Despawns chunks older than the latest 10
    commands.entity(children.first().unwrap()).despawn();
}```
#

This approach assumes that the "Ground" parent does little more than organize its children