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
.
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.