Build a Flappy Bird Clone in Rust and Bevy 0.14Part 4 - Adding Resources
In the previous part of the tutorial we added the systems to create some animations in the game. In this part we will add some resources to the game. Resources are data that is shared between systems. In this case we will add a resource to store the current state of the game.
Resources in Bevy
Resources are global data that can be accessed by the systems. The difference between resources and components is that resources allow you to store a single global instance of some type of data. This data can be accessed by any system in the game. Components, on the other hand, are attached to entities, they are not a single instance of data, instead they can be attached to multiple entities.
Adding Game State Resource
In our case, we need to create a resource to store some information about the game state. We need to store a few things:
- Game State (active, inactive, game over)
- The score of the player
A Resource in bevy is a struct or enum that implements the trait Resource
.
Let's create new file resources.rs
in the src
directory:
Update main.rs
to include the new file:
We can create a struct to store the game state and the score.
We can now add this resource to the game. We can do this by adding the resource to the App
in the main.rs
file, using the init_resource
method which takes in one generic which is the struct that implements the Resource
trait.
However, this gets us a compile error, because bevy expects the Resource
to also implement the Default
trait. To do that, we can use the derive
macro and implement the Default
trait for the Game
struct, and implement Default
for the GameState
manually to set the default state of the game to Inactive
.
Conditional Systems
In the previous part of the tutorial, we added systems to create animations in the game, but they were always running, even when the game wasn't started. We can add a helper function to check the game state and only run the system if the game is in a specific state.
To use the ==
operator, we need to implement the PartialEq
trait for the GameState
enum.
Now we can use these functions to run the systems only when the game is active.
The run_if
method takes a function that returns a boolean, if the function returns true
, the system will run, otherwise it will be skipped.
If you run the game, you'll see the animations are stopped, and the game is not running.
Now, we need a way to detect the user input when they press the space bar to start the game.
Detecting user input
To detect the user input, we can create another system that listens for the space bar key press. We can use the ButtonInput resource to listen for the key press event.
Adding it to the Bevy App
We only want to start the game if the user pressed Space
and the game is not already active. We can use the just_pressed
method on the ButtonInput
resource to check if the key was pressed. We also set the GameOverText
and PressSpaceBarText
Visibility
to Hidden
when the game starts.
Using the Without<PressSpaceBarText>
here is critical, because in the previous query we have queried for PressSpaceBarText
and Visibility
, so we need to exclude the PressSpaceBarText
from this query. If we don't use the Without<PrestSpaceBarText>
to exclude the PressSpaceBarText
from this query, Bevy will panic, if you want to learn more about this error, read more about it here
That's it for this part, we added a resource to store the game state and the score, and we added systems to start the game when the user presses the space bar and to show the GameOverText
when the game is over.
In the next part of the tutorial, we're going to implement the physics of the game. We will add gravity to the bird and make it fall down when the game is active, we'll create the jump mechanic for the bird, and we'll add collision detection to detect when the bird hits the ground.