Log in to access Rust Adventure videos!

Lesson Details

As we progress into building out the movement and merging functionality for tiles, we'll want to be able to see the point values as they change.

To do this we can write a system that is responsible for updating the tile text when the point values change.

Starting off, we'll change the text section we display by default to 4.

Text::from_section("4",...

Running the game with cargo run will now show a board with tiles that display 4.

end result

Note that we didn't change the underlying points value, so if our system is successful the board will change from displaying 4, the default, to 2, the underlying points value.

The system is going to run all the time while we're playing, so we can use .add_system to add the render_tile_points system.

.add_system(render_tile_points)

The render_tile_points system is going to query for all of the Text components that we labelled with TileText. The query is labelled mut and the Text is a mutable reference because we're going to be mutating the text section displaying the score.

We also need to query for all the entities with Points and Children which will give us all of the tiles on the board. The Points and Children come in as shared references because we aren't mutating them and thus don't need exclusive access.

fn render_tile_points(
    mut texts: Query<&mut Text, With<TileText>>,
    tiles: Query<(&Points, &Children)>,
) {
    for (points, children) in tiles.iter() {
        if let Some(entity) = children.first() {
            let mut text = texts
                .get_mut(*entity)
                .expect("expected Text to exist");
            let mut text_section = text.sections.first_mut().expect("expect first section to be accessible as mutable");
            text_section.value = points.value.to_string()
        }
    }
}

We can use Iterators to iterate over all of the tiles, destructuring the points and children from the tuple.

We expect that our tiles will have the entity with the Text component as the first child (because that's how we built them) so we access that with children.first().

if-let allows us to match on the structure of the return value from children.first(). In this case we receive an Option type and we only want to do anything with it if it's some entity. We can destructure the entity out of the Some type, and if the return value is None, the following code isn't executed.

Now that we have what we think is the entity that has the Text component we need to update, we can use the texts query like a database and get a mutable reference to the Text from it.

The Entity we got from the Some destructure is of type &Entity, which is a shared reference, so when we get_mut we can dereference to pass the argument in.

text.sections.first_mut() is similar, but we're grabbing the first section as a mutable reference.

Then we can set the text section to the value of the points for the associated tile. The text section needs to be a string, so we use .to_string() on the points value.

With the system running, you'll see the tiles display 2 again which means everything is working and we can change the original default value from 4 back to 2.

end result