Your First Flutter Flame Game

Mar 6 2024 · Dart 3, Flutter 3.10.1, Android Studio 2021.3.1 or higher, Visual Studo Code 1.7.4 or higher

Part 3: Collision Detection & Overlays

18. Make a Game Menu

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 17. Add a Heads-Up Display Next episode: 19. Challenge: Create a Game Over Overlay

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Notes: 18. Make a Game Menu

Check out Flame’s documentation about overlays.

Transcript: 18. Make a Game Menu

The first thing a player sees in any game is a menu.

You could think of it as the face of the game, it’s where you give the first impression about your game.

Menus are your game’s first impression, so it’s important that they:

  1. Are user-friendly and intuitive.
  2. In-theme with your game’s idea.
  3. Quickly convey what your game is about.

This is the game menu you’ll be building.

As you can see it keeps a consistent design in line with what the game uses while playing.

It also uses a custom font to display the game’s title and has buttons that go in-theme with the game’s look and feel.

Demo

Time to create the game menu.

MainMenu

Let’s start with a basic stateless widget.

class MainMenu extends StatelessWidget {
}

Add a variable containing the name for the overlay.

Then, define a constructor that receives an instance of MeteormaniaGame and store the reference within the widget..

static const String overlayName = 'MainMenu';

// Reference to parent game.
final MeteormaniaGame game;

const MainMenu({super.key, required this.game});

Now, replace the default build widget returned for a Material widget.

return Material()

Set the color to Colors.transparent.

As a child, use a Center widget with an empty Container.

Add some padding using EdgeInsets.all(16)

Also, set height to 250.

color: Colors.transparent,
child: Center(
  child: Container(
    padding: const EdgeInsets.all(16.0),
    height: 250,
  ),
),

Let’s add a decoration. Making a rounded corners outlined box with a very retro feeling.

BoxDecoration(
  color: const Color.fromRGBO(255, 255, 255, 0.15),
  border: Border.all(
    color: Colors.white,
    width: 4,
  ),
  borderRadius: const BorderRadius.all(
    Radius.circular(20),
  ),
),

As child of Container, set a Column with its mainAxisAlignment to MainAxisAlignment.center.

Add a header for the game as the first widget on Column.

const Text(
  'Meteormania',
  style: TextStyle(
    fontFamily: 'PressStart2P',
    color: Colors.white,
    fontSize: 24,
  ),
),

Then, include a bit of spacing with

const SizedBox(height: 48),

Create a new button to start a new game with a SizedBox.

Set width to 200 and height to 52.

Use OutlinedButton as child.

The child should be a Text that says ‘Play’ with the game’s font PressStart2P and a fontSize of 16.

style will be based from OutlinedButton.styleFrom. foregroundColor will be Colors.white and side should be const BorderSide(width: 3.0, color: Colors.white).

Finally, onPressed should make two calls: one to remove the overlay of MainMenu and the other one to start the game.

onPressed: () {
  game.overlays.remove(overlayName);
  game.initializeGame();
},

Saucer, Spaceship, Meteorite, Bullet

Now, you’ll have to check on the different components to see if the game is over so that they only appear when a new game has started.

Add an if check in update from Saucer component.

if (game.manager.isGameOver) {
  removeFromParent();
}

Do the same for Spaceship. Override update and check isGameOver.

if (game.manager.isGameOver) {
  removeFromParent();
}

Next, check that Bullet components also disappear.

if (game.manager.isGameOver) {
  removeFromParent();
}

And also for Meteorite

if (game.manager.isGameOver) {
  removeFromParent();
}

MeteormaniaGame

Now, in MeteormaniaGame you’ll also have to check if the game is over to re-add the overlay if the player’s spaceship was hit. Add an if check on spaceshipHit.

if (manager.isGameOver) {
  overlays.add(MainMenu.overlayName);
}

Make sure you also remove initializeGame from onLoad.

Main

As the final step, change main to a controlled GameWidget. This allows you to handle the game and also overlays built as a widget.

Set gameFactory to MeteormaniaGame.new.

Now, set overlayBuilderMap to a map. The key of the first item in the map is the name for the overlay so use MainMenu.overlayName. The value of the item is a function, it has two parameters, the first one is the BuildContext and the second one is a reference to the game created by the game factory.

For now, just create an arrow function that creates a new MainMenu.

Finally, as the initialActiveOverlays, use an array that only contains MainMenu.overlayName. This enables the overlay to be presented as soon as the game starts.

GameWidget<MeteormaniaGame>.controlled(
  gameFactory: MeteormaniaGame.new,
  overlayBuilderMap: {
    MainMenu.overlayName: (_, game) => MainMenu(game: game),
  },
  initialActiveOverlays: const [MainMenu.overlayName],
),

Build and run the game.

The main menu overlay now shows at the start of the game, and the other components only appear after you press ‘Play’.