Flutter Tutorial

Flutter Intermediate Lesson 105 of 135 3 min read

Flame Components: Position, Size, Anchor, Lifecycle and Children

Understand Flame components: Rectangle, Circle and Text components, position, size, anchor, angle and scale, lifecycle methods and child components.

On this page

Everything in a Flame game is a component: the player, enemies, bullets, the score, even the world and the camera. Components form a tree, just like Flutter widgets: a component can have children, which move and rotate with it.

The most useful components

ComponentDrawsUse for
PositionComponentNothing (you draw in render)Anything with a position and size
RectangleComponentA rectangleWalls, paddles, simple players
CircleComponentA circleBalls, bullets, coins
TextComponentTextScore, labels
SpriteComponentAn imageCharacters, items
SpriteAnimationComponentAn animated imageWalking, explosions
TimerComponentNothingDoing something every N seconds

Position, size, anchor, angle and scale

import 'dart:math';
import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';

void main() => runApp(GameWidget(game: ShapesGame()));

class ShapesGame extends FlameGame {
  @override
  Future<void> onLoad() async {
    camera.viewfinder.anchor = Anchor.topLeft;

    world.add(RectangleComponent(
      position: Vector2(100, 100),
      size: Vector2(80, 50),
      paint: Paint()..color = Colors.orange,
    )); // anchor defaults to topLeft: position is the top-left corner

    world.add(RectangleComponent(
      position: Vector2(300, 125),
      size: Vector2(80, 50),
      anchor: Anchor.center,   // position is the centre
      angle: pi / 6,            // rotated 30 degrees around the anchor
      paint: Paint()..color = Colors.lightGreen,
    ));

    world.add(CircleComponent(
      radius: 30,
      position: Vector2(200, 260),
      anchor: Anchor.center,
      scale: Vector2.all(1.5), // 1.5 times bigger
      paint: Paint()..color = Colors.pinkAccent,
    ));

    world.add(TextComponent(
      text: 'Anchors, angles and scale',
      position: Vector2(20, 20),
      textRenderer: TextPaint(style: const TextStyle(color: Colors.white, fontSize: 20)),
    ));
  }
}
  • position is a Vector2(x, y). x grows to the right, y grows down.
  • anchor decides which point of the component sits at position: Anchor.topLeft, Anchor.center, Anchor.bottomCenter and so on. Rotation and scale happen around the anchor.
  • angle is in radians: pi is 180°.

The lifecycle

class Enemy extends PositionComponent {
  @override
  Future<void> onLoad() async {
    // Once, before the component is first shown. Load images, add children.
  }

  @override
  void onMount() {
    // Every time it is added to the tree. The parent and game are available.
  }

  @override
  void update(double dt) {
    super.update(dt);
    // Every frame: move, check rules.
  }

  @override
  void render(Canvas canvas) {
    super.render(canvas);
    // Every frame: draw. (0, 0) is the component's own top-left corner.
  }

  @override
  void onRemove() {
    // When it is removed. Clean up.
  }
}

Add a component with add(component) (or world.add), remove it with component.removeFromParent().

Drawing your own shape

Extend PositionComponent and draw on the canvas in render:

import 'package:flame/components.dart';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';

void main() => runApp(GameWidget(game: StarGame()));

class Heart extends PositionComponent {
  Heart({required super.position}) : super(size: Vector2.all(80), anchor: Anchor.center);

  final _paint = Paint()..color = Colors.redAccent;

  @override
  void render(Canvas canvas) {
    final w = size.x, h = size.y;
    final path = Path()
      ..moveTo(w / 2, h * 0.85)
      ..cubicTo(-w * 0.2, h * 0.35, w * 0.25, -h * 0.1, w / 2, h * 0.25)
      ..cubicTo(w * 0.75, -h * 0.1, w * 1.2, h * 0.35, w / 2, h * 0.85);
    canvas.drawPath(path, _paint);
  }

  @override
  void update(double dt) {
    super.update(dt);
    angle += dt; // spin slowly
  }
}

class StarGame extends FlameGame {
  @override
  Future<void> onLoad() async {
    camera.viewfinder.anchor = Anchor.topLeft;
    world.add(Heart(position: Vector2(200, 200)));
  }
}

Children move with their parent

class Car extends RectangleComponent {
  Car() : super(size: Vector2(120, 40), paint: Paint()..color = Colors.blue);

  @override
  Future<void> onLoad() async {
    // Positions are relative to the car.
    add(CircleComponent(radius: 12, position: Vector2(10, 30)));
    add(CircleComponent(radius: 12, position: Vector2(86, 30)));
  }
}

Move or rotate the car and its wheels follow. This is how you build a character from parts, or attach a health bar to an enemy.

Priority: what is drawn on top

Components with a higher priority are drawn later, so on top: RectangleComponent(priority: 10, ...). Use it to keep the score above everything else.

Try it yourself

Build a simple “sun”: a yellow CircleComponent with eight thin RectangleComponent rays as children, each rotated by i * pi / 4, and make the whole sun rotate in update.

Practise in the playground Updated