Files
flame/doc/game.md
Jochum van der Ploeg f9f4167d02 Added a required to GameWidget and updated the docs (#638)
* Added a required to GameWidget and updated the docs

* Removed entry from CHANGELOG
2021-01-20 22:11:33 +01:00

4.8 KiB

Game Loop

The Game Loop module is a simple abstraction over the game loop concept. Basically most games are built upon two methods:

  • The render method takes the canvas ready for drawing the current state of the game.
  • The update method receives the delta time in seconds since last update and allows you to move to the next state.

The Game class can be extended and will provide these gameloop methods and then its instance Flutter widget tree via the GameWidget.

You can add it into the top of you tree (directly as an argument to runApp) or inside the usual app-like widget structure (with scaffold, routes, etc.).

Example of usage directly with runApp:


class MyGameSubClass extends Game {
  @override
  void render(Canvas canvas) {
    // TODO: implement render
  }

  @override
  void update(double t) {
    // TODO: implement update
  }
}
    
  
main() {
  final myGame = MyGameSubClass();
  runApp(
    GameWidget(
      game: myGame,
    )
  );
}

Note: Do not instantiate your game in a build method. Instead create an instance of your game and reference it within your widget structure. Otherwise your game will be rebuild every time the Flutter tree gets rebuild.

It is important to notice that Game is an abstract class with just the very basic implementations of the gameloop.

As an option and more suitable for most cases, there is the full-featured BaseGame class. For example, Forge2D games uses Forge2DGame class;

The BaseGame implements a Component based Game for you; basically it has a list of Components and passes the update and render calls appropriately. You can still extend those methods to add custom behavior, and you will get a few other features for free, like the passing of resize methods (every time the screen is resized the information will be passed to the resize methods of all your components) and also a basic camera feature. The BaseGame.camera controls which point in coordinate space should be the top-left of the screen (defaults to [0,0] like a regular Canvas).

A BaseGame implementation example can be seen below:

    class MyCrate extends SpriteComponent {

        // creates a component that renders the crate.png sprite, with size 16 x 16
        MyCrate() : super.fromSprite(16.0, 16.0, new Sprite('crate.png'));

        @override
        void onGameResize(Size size) {
            // we don't need to set the x and y in the constructor, we can set then here
            this.x = (size.width - this.width) / 2;
            this.y = (size.height - this.height) / 2;
        }
    }

    class MyGame extends BaseGame {
        MyGame() {
            add(new MyCrate()); // this will call resize the first time as well
        }
    }

To remove components from the list on a BaseGame the markToRemove method can be used.

Flutter Widgets and Game instances

Since a Flame game can be wrapped in a widget, it is quite easy to use it alongside other Flutter widgets. But still, there is a the Widgets overlay API that makes things even easier.

Game.overlays enables to any Flutter widget to be shown on top of a game instance, this makes it very easy to create things like a pause menu, or an inventory screen for example. This property that will be used to manage the active overlays.

This management happens via the .overlays.add and .overlays.remove methods that marks an overlay to be shown and hidden, respectively, via a String argument that identifies an overlay.
After that it can be specified which widgets represent each overlay in the GameWidget declaration by setting a overlayBuilderMap.

// inside game methods:
final pauseOverlayIdentifier = "PauseMenu";

overlays.add(pauseOverlayIdentifier); // marks "PauseMenu" to be rendered.
overlays.remove(pauseOverlayIdentifier); // marks "PauseMenu" to not be rendered.
// on the widget declaration
final game = MyGame();

Widget build(BuildContext  context) {
  return GameWidget(
  game: game,
  overlayBuilderMap: {
    "PauseMenu": (ctx) {
       return Text("A pause menu");
     },
   },
 );
}

The order in which the overlays are declared on the overlayBuilderMap defines which overlay will be rendered first.

Here you can see a working example of this feature.

BaseGame debug mode

Flame's BaseGame class provides a method called debugMode, which by default returns false. It can however, be overridden to enable debug features over the components of the game. Be aware that the state returned by this method is passed through its component when they added to the game, so if you change the debugMode in runtime, it may not affect already added components.

To see more about debugMode on Flame, please refer to the Debug Docs