Lesson Details

Cleanup and Polish

And that’s Flappy Bird!

Let’s finish off the application.

Turn the Gizmos off if you haven’t already in startup.

let (config, _) = config_store
.config_mut::<DefaultGizmoConfigGroup>();
config.enabled = false;

And we can make the gap invisible by setting Visibility::Hidden on it.

(
Visibility::Hidden,
Sprite {
color: Color::WHITE,
custom_size: Some(Vec2::new(
10.0, GAP_SIZE,
)),
..default()
},
Transform::from_xyz(
0.0,
gap_y_position,
1.0,
),
PointsGate,
),
Figure 1: The cleaned up visuals

Moving the Pipes Vertically

The pipes in Flappy Bird are supposed to be in different positions. This can be accomplished more effectively using noise, but we’ll start off with just a sin wave.

Add the Time resource to spawn_pipes.

fn spawn_pipes(
mut commands: Commands,
asset_server: Res<AssetServer>,
time: Res<Time>,
) { ... }

and use it to produce a sine wave. I multiply it here by an arbitrary number so that the output doesn’t look exactly periodic like a sine wave. The .sin function returns a value between -1 and 1, so multiplying that by one quarter of our CANVAS_SIZE height means it will move up and down a total of half the size of the canvas.

let gap_y_position = (time.elapsed_secs() * 4.2309875)
.sin()
* CANVAS_SIZE.y
/ 4.;
Figure 2: Pipes in new places

Pointing the Bird

Our bird doesn’t really move much either. We can add a little life by having it point in the direction of the arc it is following. Our pretend horizontal speed is PIPE_SPEED and our vertical speed is the velocity value.

Make PIPE_SPEED pub so we can use it in main.rs.

pub const PIPE_SPEED: f32 = 200.0;

Then we’ll use that value in a new enforce_bird_direction system. This system takes advantage of the fact that the angle of a 2d vector is just… that vector. So since our x and y speeds are already relative to our bird, we consider the bird to be the velocity vector’s local Vec2::ZERO. calculated_velocity - Vec2::ZERO is calculated_velocity. So we take advantage of glam’s Vec2::to_angle function (which uses atan2 under the hood), and make that a rotation around the Z axis, which is the one coming out of our screen.

fn enforce_bird_direction(
mut player: Single<
(&mut Transform, &Velocity),
With<Player>,
>,
) {
let calculated_velocity =
Vec2::new(PIPE_SPEED, player.1.0);
player.0.rotation = Quat::from_rotation_z(
calculated_velocity.to_angle(),
);
}

Since the system is only visual, and not gameplay related, we can put it in the Update schedule.

.add_systems(
Update,
(
controls,
score_update
.run_if(resource_changed::<Score>),
enforce_bird_direction,
),
)
Figure 3: Bird facing up
Figure 4: Bird facing down