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
| Component | Draws | Use for |
|---|---|---|
PositionComponent | Nothing (you draw in render) | Anything with a position and size |
RectangleComponent | A rectangle | Walls, paddles, simple players |
CircleComponent | A circle | Balls, bullets, coins |
TextComponent | Text | Score, labels |
SpriteComponent | An image | Characters, items |
SpriteAnimationComponent | An animated image | Walking, explosions |
TimerComponent | Nothing | Doing 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)),
));
}
}
positionis aVector2(x, y).xgrows to the right,ygrows down.anchordecides which point of the component sits atposition:Anchor.topLeft,Anchor.center,Anchor.bottomCenterand so on. Rotation and scale happen around the anchor.angleis in radians:piis 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.