Create a Breakout Game With Flame and Forge2D – Part 2
Learn how to create a Flutter version of the classic Breakout game using Flame and Forge2D. By Michael Jordan.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Create a Breakout Game With Flame and Forge2D – Part 2
25 mins
- Getting Started
- Creating the Brick Wall
- Creating a Brick
- Creating a Custom Flame Component
- Creating the Brick Wall
- Creating the Paddle
- Giving User Control of the Paddle
- Setting Up Draggable Mixin
- Constraining Body Movement with Joints
- Creating a Mouse Joint
- Creating a Prismatic Joint
- Adding Collision Detection
- Where to Go From Here?
Creating a Prismatic Joint
Now you're going to limit the paddle’s movement to the horizontal plane with PrismaticJoint
.
The MouseJoint
is associated with the drag event, and it is created and destroyed when the user drags the paddle. You need something more durable than that.
The PrismaticJoint
is valid for the life of the paddle body and can be created just once after the paddle body is mounted. That sounds more viable, no?
Open paddle.dart and add the following onMount
method to the Paddle
class:
@override
void onMount() {
super.onMount();
// 1
final worldAxis = Vector2(1.0, 0.0);
// 2
final travelExtent = (gameRef.size.x / 2) - (size.width / 2.0);
// 3
final jointDef = PrismaticJointDef()
..enableLimit = true
..lowerTranslation = -travelExtent
..upperTranslation = travelExtent
..collideConnected = true;
// 4
jointDef.initialize(body, ground.body, body.worldCenter, worldAxis);
final joint = PrismaticJoint(jointDef);
world.createJoint(joint);
}
Step through the code:
- Set the
worldAxis
to restrict the paddle's movement to the x-axis. - Set the extent that the paddle can move. The paddle movement is relative to the origin of the paddle, which is at its center. Set
travelExtent
to a distance of half the width of the game area minus half the width of the paddle to keep the movement within the arena. - Create the prismatic joint definition with the movement limits.
- Create the joint then add it to the game world.
Build and run. The paddle movement is now limited to moving from side to side.
Cool! Your game is beginning to look like the Breakout game. Now you need to add some logic so you can destroy those bricks.
Adding Collision Detection
To destroy a brick, you must know when the ball collides with a brick. Your Forge2D collision detection code must uniquely identify the rigid bodies that have come in contact.
To determine the bodies involved in a given collision, you need to add userData
to the body definition to identify the bodies uniquely.
Open ball.dart then set the userData
property to reference this
instance of the ball, like this:
final bodyDef = BodyDef()
..userData = this
..type = BodyType.dynamic
..position = position;
Now, open brick.dart and add a similar userData
property for the bricks:
final bodyDef = BodyDef()
..userData = this
..type = BodyType.static
..position = position
..angularDamping = 1.0
..linearDamping = 1.0;
Your new this
reference makes it so each brick in the wall is uniquely identified from other bricks. When a ball collides with a brick, Forge2D will use this data to identify the rigid bodies.
When a collision between the ball and a brick happens, the brick is responsible for recording the collision. Then, when the game loop updates, the brick wall checks for destroyed bricks and removes them from the Forge2D world.
In brick.dart, add the mixin ContactCallbacks
to the Brick
class.
class Brick extends BodyComponent<Forge2dGameWorld> with ContactCallbacks {
This mixin provides access to the contact methods.
Now, add the below:
var destroy = false;
@override
void beginContact(Object other, Contact contact) {
if (other is Ball) {
destroy = true;
}
}
You just added a flag to indicate if this brick collided with the ball —beginContact
sets the flag and is one of the ContactCallbacks
Forge2D provides to alert you to collisions between bodies.
Add the below to brick.dart:
import 'ball.dart';
Your code needs this to import the Ball
class.
The ball may collide with one or more bricks in a game loop cycle. The brick wall component is an excellent place to check the status of and remove destroyed bricks.
Open brick_wall.dart then add the following update
method:
@override
void update(double dt) {
// Check for bricks in the wall that have been flagged for removal.
// Note: this is a destructive process so iterate over a copy of
// the elements and not the actual list of children and fixtures.
//
for (final child in [...children]) {
if (child is Brick && child.destroy) {
for (final fixture in [...child.body.fixtures]) {
child.body.destroyFixture(fixture);
}
gameRef.world.destroyBody(child.body);
remove(child);
}
}
super.update(dt);
}
The above code helps us verify which of our bridges have been marked for removal, then destroys their fixtures and bodies. Remember that, when removing bodies from Forge2D, you must first remove the body's fixtures then you can remove the body.
Build and run and see if you can smash some bricks now.
Another round of congratulations is in order!
You've created a ball, paddle and wall of bricks. The user can control the paddle to bounce the ball into the bricks and destroy them.
Where to Go From Here?
You can download the completed project files by clicking the Download Materials button at the top or bottom of the tutorial.
During part two of this series, you learned how to:
- Create a custom Flame
Component
for the brick wall. - Add
Draggable
user input controls to Forge2D rigid bodies. - Move bodies in Forge2D using
setTransform
andMouseJoint
. - Constrain the movement of a rigid body using a
PrismaticJoint
. - Detect collisions between rigid bodies using
ContactCallbacks
.
When you're ready to deep dive into Forge2D joints, visit this article: Box2D C++ tutorials - Joints - overview.
The third and final part of the Create A Breakout Game With Flame and Forge2D tutorial series will show you how to complete your Breakout game.
Right now, you have all the mechanics needed for a Breakout game, but it is a lawless land. It's missing rules and logic to enforce them.
Your game also lacks visual appeal — everything is black and white.
By the end of part three, these issues will be addressed and you'll have a beautiful, addictive game to play when you're bored: Create A Breakout Game With Flame and Forge2D - Part 3
We hope you enjoyed this tutorial, and if you have any questions or comments, please join the forum discussion below!