-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New Flappy Bird example #19282
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
New Flappy Bird example #19282
Conversation
Welcome, new contributor! Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨ |
839f771
to
6e4a60f
Compare
@@ -4361,3 +4361,14 @@ name = "Extended Bindless Material" | |||
description = "Demonstrates bindless `ExtendedMaterial`" | |||
category = "Shaders" | |||
wasm = false | |||
|
|||
[[example]] | |||
name = "flappy_bird" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Should we choose a name other than "Flappy Bird"? I would assume the name is trademarked, and unlike "Breakout", it's reasonably recent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are probably right. I'll think about a nice bevy-inspired name!
Fun fact: apparently there is a whole thing around the copyright of Flappy Bird. Some crypto bros did a Flappy Bird thing and then the original creator got mad. There's also some people claiming the original Flappy Bird infringes on Nintendo copyright.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Quick search for Floppy Bevy
led me to https://github.com/rust-adventure/floppy-corgi haha...
examples/games/flappy_bird.rs
Outdated
const BACKGROUND_COLOR: Color = Color::srgb(0.9, 0.9, 0.9); | ||
|
||
/// Timer spawning a pipe each time it finishes | ||
const PIPE_TIMER_DURATION: Duration = Duration::from_millis(2000); | ||
|
||
/// Movement speed of the pipes | ||
const PIPE_SPEED: f32 = 200.; | ||
|
||
/// The size of each pipe rectangle | ||
const PIPE_SIZE: Vec2 = Vec2::new(100., 500.); | ||
|
||
/// How large the gap is between the pipes | ||
const GAP_HEIGHT: f32 = 300.; | ||
|
||
/// Gravity applied to the bird | ||
const GRAVITY: f32 = 700.; | ||
|
||
/// Size of the bird sprite | ||
const BIRD_SIZE: f32 = 100.; | ||
|
||
/// Acceleration the bird is set to on a flap | ||
const FLAP_POWER: f32 = 400.; | ||
|
||
/// Horizontal position of the bird | ||
const BIRD_POSITION: f32 = -500.; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Controversial Nit: This is consistent with our other examples, but I'm not a fan of these hard-coded constants. They're all-caps and I don't believe particularly good practice (these kinds of settings would normally be controlled in a configuration file read by the build system for example). I think it would be nicer if all of this was wrapped in a Settings
resource (ideally implementing Reflect
for runtime configuration...), with these values being in the Default
implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would be so good with this RFC: https://github.com/rust-lang/rfcs/blob/master/text/3681-default-field-values.md. I'll give your suggestion a go.
const BIRD_POSITION: f32 = -500.; | ||
|
||
#[derive(Component)] | ||
struct Bird; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super tiny nit: I believe we refer to the Bevy bird as birb
in the examples, might be nice to be consistent here, even if it is a little silly.
) { | ||
commands.spawn(Camera2d); | ||
|
||
let score_sound = asset_server.load("sounds/breakout_collision.ogg"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let score_sound = asset_server.load("sounds/breakout_collision.ogg"); | |
// TODO: Replace with a specific sound, or rename file | |
let score_sound = asset_server.load("sounds/breakout_collision.ogg"); |
examples/games/flappy_bird.rs
Outdated
for ent in bird { | ||
commands.entity(ent).despawn(); | ||
} | ||
|
||
for ent in pipes { | ||
commands.entity(ent).despawn(); | ||
} | ||
|
||
for ent in pipe_markers { | ||
commands.entity(ent).despawn(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Future PR: Surprised we don't have a Commands::despawn_batch
to make this cleaner! Might be nice to create a new EntityBatchCommands
(similar to EntityCommands
) for operations which could be applied to many entities, just as a quality-of-life improvement.
commands.batch([e1, e2, e3]).despawn();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cart once said something about a despawn_batch
: #2693 (comment)
It seems to be valid today in principle.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll make it slightly cleaner by combining all the entities in a single query. Then at least it just becomes one for loop.
examples/games/flappy_bird.rs
Outdated
for mut text in score_text { | ||
text.0 = 0.to_string(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: We expect a single entity to exist with the ScoreText
component. That query should be changed to Single<>
and this for loop removed.
#[derive(Component)] | ||
struct Pipe; | ||
|
||
#[derive(Component)] | ||
struct PipeMarker; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Might be nice to use required-components to ensure these are added together. Likewise for Score
and ScoreText
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think required components are correct here. At least as far as I understand required components. The pipes are represented with 1 marker and 2 pipes, so there isn't really a 1-1 requirement. For the scoring part, the Score
is a resource, not a component, so I'm not sure that works either?
I might be totally off here, please correct me if I'm wrong.
I wonder a bit about using flappy bird specifically as an example. There's just a great deal of overlap in what this is demonstrating and what we already have in |
I was wondering about that too. One solution to that would be to, for example, to put more emphasis on sprites and adding menus. Then this might become different enough to merit another example. |
I added some menus to see how complex that would make it. I'm not sure whether that makes it better as an example. As far as I can see there is no example that features both a menu and a game, but it's also not too hard to infer. Anyway, I'm having fun learning those parts of bevy (also this is my first time using states, so ideas on how to make it cleaner are very welcome). I can revert this commit if a more trimmed down version is preferred. I guess it comes down to what the goal of this example would be. Either we keep it very small (possibly stepping on the toes of breakout) or it's more complex (possibly too complex). Opinions welcome! |
Hi!
Objective
This adds a new example to the repository implementing Flappy Bird, as was suggested during the RustWeek unconf. As far as I understand, the goal is to add another example implementing a "full" game, combining multiple Bevy features.
Solution
This is a simplified implementation of Flappy Bird using the logo as the titular bird and simply using black rectangles as pipes. It features a scoring mechanism and resets on collision. Since this is an example, I tried to document even the more obvious parts.
While I've used Bevy a bit before, I do not have a very good idea of what idiomatic Bevy code looks like. I would appreciate any feedback there.
Missing from this implementation are:
A menu screenA game over screenTesting
I tested this on my own machine. One thing that probably needs some tweaking is handling of other window sizes and resizing as the game is largely tailored to a particular screen size.
Showcase
This is what it looks like: