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

17. Add a Heads-Up Display

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: 16. Break Down Meteorites Next episode: 18. Make a Game Menu

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.

Transcript: 17. Add a Heads-Up Display

While playing, it’s important to keep the player informed of what’s happening in the game at all times.

The player might be interested in specific information like health, level or similar stats that might affect the way they play the game. This information is usually displayed in the form of a heads up display.

A heads up display, also known by its initials HUD, is a portion of the screen that displays important information about a game while in gameplay like the main character’s health, items, and an indication of game progression such as score or level.

Meteormania also needs to display a HUD. In this case, you’ll want to display:

  • the current level that the player is in
  • the health of the player
  • the points accumulated so far

All this information is already getting tracked by GameManager, so all you’ll have to do is display them in a component.

Demo

HUD

Open overlays/hud.dart to start.

Define a new component called Hud that extends PositionComponent. Also add HasGameRef as a mixin since you’ll need information about the game’s state.

class Hud extends PositionComponent with HasGameRef<MeteormaniaGame> {
}

For Meteormania, you’ll want to showcase three stats: current level, player’s health and the score.

So, create three properties of type TextComponent, make them late so that you can instantiate them later in onLoad.

late TextComponent _levelComponent;
late TextComponent _healthComponent;
late TextComponent _pointsComponent;

TextComponent is a special type of component that allows you to render strings onto the screen. This component can also receive a TextPaint renderer that you can use to customize the style of the text. For now, define a global hudTextStyle using a custom font family and white as the text color.

static const hudTextStyle = TextStyle(
  fontFamily: 'PressStart2P',
  color: Color.fromRGBO(255, 255, 255, 1),
);

Now, initialize all three of the TextComponents in onLoad. You’ll have to override it.

@override
Future<void>? onLoad() async {
  return super.onLoad();
}

Start by initializing _levelComponent.

_levelComponent = TextComponent()

Use string interpolation to showcase the level stored in the game manager.

text: 'LVL ${game.manager.level}',

Define textRenderer and use hudTextStyle as a base style; change the size to 18.

textRenderer: TextPaint(
  style: hudTextStyle.copyWith(
    fontSize: 18,
  ),
),

Set anchor to Anchor.center.

anchor: Anchor.center,

And now, set position to be at the middle and in the bottom of the game’s screen.

position: Vector2(
  GameConstants.cameraWidth / 2,
  GameConstants.cameraHeight - 32,
),

Do the same for _healthComponent.

_healthComponent = TextComponent(
  text: 'Lives: ${game.manager.health}',
);

This time, set fontSize to 14.

textRenderer: TextPaint(
  style: hudTextStyle.copyWith(
    fontSize: 14,
  ),
),

Also, set position to the top left corner. Leave some margin to the top and left.

anchor: Anchor.centerLeft,
position: Vector2(32, 32),

Initialize _pointsComponent now. This time, set position’s height to be 32 points more than _healthComponent

_pointsComponent = TextComponent(
  text: 'Points: ${game.manager.points}',
  textRenderer: TextPaint(
    style: hudTextStyle.copyWith(
      fontSize: 14,
    ),
  ),
  anchor: Anchor.centerLeft,
  position: Vector2(32, 64),
);

Finally, use addAll to include your components to the Hud.

addAll([
  _levelComponent,
  _healthComponent,
  _pointsComponent,
]);

onLoad serves as a way to initialize components but you’ll also need to update the HUD when the player hits an enemy or gets hit by one. Because of that, the best place to do it is update.

@override
void update(double dt) {
  super.update(dt);
}

Since all TextComponents are already initialized, all you have to do is update the text inside each one to make sure they maintain updated all the time.

_levelComponent.text = 'LVL ${game.manager.level}';
_healthComponent.text = 'Lives: ${game.manager.health}';
_pointsComponent.text = 'Points: ${game.manager.points}';

Finally, check if the game is over by calling isGameOver from manager. If so, just remove it from the parent component. This way, the HUD is only visible while in game.

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

MeteormaniaGame

In meteormania_game.dart, import your heads up display.

import 'overlays/hud.dart';

Now, in initializeGame, add a new Hud to the _world. This takes care of displaying your new component when in-game.

_world.add(Hud());

Build and run the game. Notice the new information displayed on screen like lives, points and current level. That’s your new HUD, great Job!

In the next episode, you’ll work on creating a game menu for your game. Keep up the good work!