#Confused about best practices for dividing functionality across systems.

7 messages · Page 1 of 1 (latest)

sharp remnant
#

Hello!

I'm building a 2D antfarm simulation on a grid. I have some ant sprites which move around and dig up dirt through an ant system. I also have a gravity system which causes dirt and ants to fall downward when they're above air.

I'm not sure if it's good practice, but I also have a "render" system. This is my attempt at separating model concerns from view concerns.

Both my ant system and my gravity system affect a Position component which is just an xy offset. Ants walk around on the surface and their Position's x-offset is updated. Ants/dirt fall from the sky and Position's y-offset is updated.

In both ant system and gravity system I am updating my model, the Position component, and have not reflected the changes visually by updating an associated Transform. I thought this would be a good role for my render system to fulfill.

My render system has this:

fn render_translation(
    mut query: Query<
        (
            &mut Transform,
            &Position,
        ),
        Changed<Position>,
    >,
) {
    for (mut transform, &position) in query.iter_mut() {
        transform.translation.x = position.x as f32;
        transform.translation.y = -position.y as f32;
    }
}

Here, I watch for changes to position and reflect the change in the UI.

A problem I experience with this approach is:

  • Ant falls from the sky and is one unit above the ground both in the view and model.
  • Gravity system runs such that ant model is now on the ground.
  • Ant system runs such that ant takes a step forward.
  • Render system runs and reflects the change visually.

This results in a visual glitch where the ant is never shown landing on the ground without having taken a step because the gravity system runs and the ant system runs before visuals are updated.

I'm curious what approaches I should consider to fix this issue. The most obvious solution is to abandon my render system and instead have any system that updates position also update transform. I was hesitant to take this approach because I'm trying to "think ECS" and it seemed good to have a generic query that handles rendering for all Position components instead of duplicating that effort inside of each system that updates position.

How am I thinking about this incorrectly? Thanks!

#

I guess another option is, instead of getting rid of the render system, to have two render systems and have one run after the gravity system and one after the ant system, but that seems wrong. I would end up needing to create one for every system that affects position to render immediately

#

It also wouldn't be great for performance since Changed<T> wouldn't clear until the next frame, so each render system would try and update translations that had already been handled by previous systems.

sharp remnant
#

Ohh I think I see what I should do

sharp remnant
#

Okay, so my misunderstanding was that I thought I could rely on an implicit system run order since I was building a WASM app and don't get benefits from parallelism

#

I have my systems added to app across three plugins and I thought that controlling the order in which the plugins were added would guarantee that the systems declared in that plugin would run adjacently

#

but they do not