#How would I do this for more than 1 entity?
58 messages · Page 1 of 1 (latest)
many_mut and related friends
it expects 1 argument "entities" what exactly do I put there
like ""ground_query: Query<Entity, With<Ground>>"" ?
and then ground_query
For example, to work with two entities you might call many_mut([entity_a, entity_b])
well I'm basically spawning 1 entity twice
Well you can't mutably access one entity more than once at a time
I see
You need to guarantee that any mutable access to an entity is unique
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
Yes, I would generally avoid using single and friends unless you know you'll have exactly one
I didn't know it worked like that
Instead, iterate the query and just assume that the logic may repeat for each instance
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
Really those units don't matter much in the grand scheme
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
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.
that could work
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
that sounds complicated
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
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
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
In this case, you would keep "Ground" on all of these and use another like "LatestGround" to uniquely identify the newest one
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
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