Create a Flappy Bird-like Game Using Flame and Flutter

Tiempo de lectura: 5 minutos

Flutter is an open-source mobile development framework that enables developers to create high-quality mobile applications for Android and iOS. One of the most popular tools in Flutter for game development is the animation and graphics library known as Flame.

Flappy Bird is a simple and addictive platformer game where a bird must fly through pipes without colliding with them.

In this tutorial, we will create a simple game using the Flame library in Flutter.

Our game will be called “Flappy Bird Clone” and will focus on the gameplay mechanics of “Flappy Bird.” The objective of the game is to guide a bird through a series of pipes without colliding with them.

  1. Flutter and Flame Setup

First, you need to install Flutter and set up a Flutter project. You can follow the official Flutter documentation to do so. Once you have created a Flutter project, you can add the Flame dependency to your project in the pubspec.yaml file:

dependencies:
  flutter:
    sdk: flutter
  flame: ^1.0.0-rc11

Then, run the command flutter pub get in your terminal to install the dependencies.

  1. Game Setup

In your Flutter project, create a new file called “game.dart”. This file will contain all the game code. First, import the necessary dependencies:

import 'dart:math';
import 'package:flame/flame.dart';
import 'package:flame/game.dart';
import 'package:flame/sprite.dart';
import 'package:flame/components/component.dart';
import 'package:flame/position.dart';
import 'package:flutter/gestures.dart';

Then, create a class called “FlappyBirdCloneGame” that extends the “BaseGame” class from Flame:

class FlappyBirdCloneGame extends BaseGame {
  @override
  void update(double dt) {
    // TODO: Implement game logic here
  }
  
  @override
  void render(Canvas canvas) {
    // TODO: Implement game rendering here
  }
}

This class will be the core of the game and will contain all the game logic and rendering.

  1. Create the Background

To create the game’s background, we need to load a background image and render it in the game. First, load the image in the game’s constructor:

class FlappyBirdCloneGame extends BaseGame {
  Sprite background;
  
  FlappyBirdCloneGame() {
    background = Sprite('background.png');
  }
  
  // ...
}

Then, in the “render” function, draw the background image on the canvas:

@override
void render(Canvas canvas) {
  background.renderPosition(canvas, Position(0, 0));
  // ...
}
  1. Create the Bird

To create the bird, we need to load a bird image and render it in the game. Additionally, we need to detect user touch inputs to make the bird fly.

First, load the bird image in the game’s constructor:

class FlappyBirdCloneGame extends BaseGame {
  Sprite birdSprite;
  Position birdPosition;
  double birdVelocity = 0.0;
  
  FlappyBirdCloneGame() {
    birdSprite = Sprite('bird.png');
    birdPosition = Position(100, 100);
  }
  
  // ...
}

In this code, we use a position variable to control the bird’s position in the game and a velocity variable to control the bird’s speed.

Then, in the “render” function, draw the bird image on the canvas:

@override
void render(Canvas canvas) {
  background.renderPosition(canvas, Position(0, 0));
  birdSprite.renderPosition(canvas, birdPosition);
  // ...
}

To make the bird fly,

void onTap() {
  birdVelocity = -300.0;
}

In this function, we set the bird’s velocity to a negative value to make the bird fly upward when the user taps the screen.

  1. Create the Pipes

To create the pipes, we need to load a pipe image and render it in the game. Additionally, we need to detect collisions between the bird and the pipes.

First, load the pipe image in the game’s constructor:

class FlappyBirdCloneGame extends BaseGame {
  Sprite tubeSprite;
  
  FlappyBirdCloneGame() {
    // ...
    tubeSprite = Sprite('tube.png');
  }
  
  // ...
}

Then, create a class called “Tube” that extends the “Component” class from Flame:

class Tube extends Component {
  Sprite tubeSprite;
  double topY, bottomY, x;
  
  Tube(this.tubeSprite, this.x, this.topY, this.bottomY);
  
  @override
  void render(Canvas canvas) {
    tubeSprite.renderPosition(canvas, Position(x, topY));
    tubeSprite.renderPosition(canvas, Position(x, bottomY));
  }
  
  @override
  void update(double dt) {
    x -= 200.0 * dt;
  }
}

In this class, we use the position variables “topY” and “bottomY” to control the pipes’ position in the game. Additionally, we use the “x” variable to control the horizontal position of the pipes, and the “update” function to move the pipes to the left.

In the game’s “update” function, create new pipes and add them to the game:

@override
void update(double dt) {
  super.update(dt);
  
  if (timer >= 1.0) {
    timer = 0.0;
    double y = rnd.nextDouble() * (size.height - 300.0) + 150.0;
    add(Tube(tubeSprite, size.width, y - 150.0, y + 150.0));
  }
  
  timer += dt;
}

In this code, we use a timer variable to create new pipes every second. In the game’s “add” function, we add the new pipe to the game.

To detect collisions between the bird and the pipes, add a collision detection function to the game:

bool collidesWithTube(Tube tube) {
  double birdRadius = birdSprite.size.width / 2;
  double birdX = birdPosition.x + birdRadius;
  double birdY = birdPosition.y + birdRadius;
  double topTubeY = tube.topY + tube.tubeSprite.size.height;
  double bottomTubeY = tube.bottomY;
  
  if (birdX > tube.x - birdRadius && birdX < tube.x + tube.tubeSprite.size.width + birdRadius) {
    if (birdY > topTubeY  birdY < bottomTubeY) {
      return true;
    }
  }
  
  return false;
}

In this function, we check if the bird’s position overlaps with the pipe’s position. If a collision is detected, the function returns true.

  1. Create the Game Screen

Now that we have created the game logic, we need to create a game screen where the user can play.

Create a new screen called “GameScreen” and add a “FlappyBirdCloneGame” object to the screen:

class GameScreen extends StatefulWidget {
  @override
  _GameScreenState createState() => _GameScreenState();
}

class _GameScreenState extends State<GameScreen> {
  final game = FlappyBirdCloneGame();
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: game.widget,
    );
  }
}

In this screen, we use a “Scaffold” widget to wrap the game widget. The game widget is created using the “widget” function of the “FlappyBirdCloneGame” object.

  1. Create the Main Menu

To allow the user to start the game, we need to create a main menu with a start button.

Create a new screen called “MainMenuScreen” and add a start button:

class MainMenuScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(context, MaterialPageRoute(builder: (context) => GameScreen()));
          },
          child: Text('Start'),
        ),
      ),
    );
  }
}

In this code, we use an “ElevatedButton” widget to create the start button. When the button is pressed, we navigate to the game screen using the “push” function of the “Navigator” object.

  1. Create the Complete Game

Now that we have created all parts of the game, we can create the complete game using a “MaterialApp” object in the main class:

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flappy Bird Clone',
      home: MainMenuScreen(),
    );
  }
}

Conclusion In this tutorial, we have created a Flappy Bird Clone game using the Flame game engine with Flutter. We have created a game object, a background, a bird, pipes and a game screen. We have also created a menu screen for the user to launch the game. This tutorial is just an introduction to creating games with Flutter and Flame. With the skills learned in this tutorial, you can create more complex and exciting games in the future. Have fun creating games!

Leave a Comment