Slide 1

Slide 1 text

Introduction to Game Dev in Flame March 20, 2024 Flame 1.16, Flutter 3.19

Slide 2

Slide 2 text

Let’s begin with some questions! Game development familiarity? Unity? Unreal?

Slide 3

Slide 3 text

About me Song Yang Data scientist, Outlier Previously teaching at Vanier College + + Game dev hobbyist (portfolio) Currently building a startup! + + Song Yang | LinkedIn

Slide 4

Slide 4 text

Agenda 1 2 3 4 5 6 Game development basics How Flame fits in Flutter Importing art Controls Physics and collisions Making use of Flutter for UI

Slide 5

Slide 5 text

1. Game development basics

Slide 6

Slide 6 text

The 3Cs of game development Character What does your game models look like? ● 2D ✅ ● 2D with physics ✅ ● 3D Flame does not support 3D art, yet. - Flutter pinball (article) Controls How intensive are the player controls? ● Just clicking around ✅ ● Minimal ✅ ● Intensive Flame is best for minimal controls. - Platformer - Card games - 2D shooter Camera How is the game presented visually? ● Static 2D camera ✅ ● Moving 2D camera ✅ ● 3D camera The world is treated as a 2D plane in Flame.

Slide 7

Slide 7 text

2. How Flame fits within Flutter

Slide 8

Slide 8 text

Dart Everything is a widget. Widgets are in a tree. + + + Flutter Widget Widget … Widget … …

Slide 9

Slide 9 text

Introduce the GameWidget. The GameWidget has Flame components. + + Flutter + Flame Widget Widget … Widget … … GameWidget No Flutter widgets can be a descendant of the GameWidget.* +

Slide 10

Slide 10 text

import 'package:flame/game.dart'; void main() { runApp( GameWidget.controlled( gameFactory: EmberQuestGame.new, ), ); }

Slide 11

Slide 11 text

3. Importing art assets

Slide 12

Slide 12 text

Images and sound can be treated like in Flutter. Add them to the asset path designated by the pubspec.yaml. By default, every image is in /assets/images. Adding files to the Flutter-Flame project flutter: assets: - assets/images/ Let’s see an example for the platformer game Ember Quest!

Slide 13

Slide 13 text

Let’s see the game in action.

Slide 14

Slide 14 text

import 'package:flame/game.dart'; class EmberQuestGame extends FlameGame { @override Future onLoad() async { await images.loadAll([ 'block.png', 'ember.png', 'ground.png', 'heart_half.png', 'heart.png', 'star.png', 'water_enemy.png', ]);

Slide 15

Slide 15 text

Introduce the camera The camera is part of the extended FlameGame. Anchors are similar to their counterparts in Unity. - Anchors help the positioning of components. @override Future onLoad() async { await images.loadAll([ '...', ]); camera.viewfinder.anchor = Anchor.topLeft; }

Slide 16

Slide 16 text

Loading a sprite animation The sprite is stored as a PNG file. (ember.png) All frames of the animation are sequentially positioned from left to right. Assumption: looping animation class EmberPlayer extends SpriteAnimationComponent with HasGameReference { EmberPlayer({required super.position}) : super(size: Vector2.all(64), anchor: Anchor.center); @override FutureOr onLoad() { animation = SpriteAnimation.fromFrameData( game.images.fromCache('ember.png'), SpriteAnimationData.sequenced( amount: 4, stepTime: 0.12, textureSize: Vector2.all(16), ), ); }

Slide 17

Slide 17 text

Adding to the world The world is part of the extended FlameGame. World coordinates are in 2D. The origin is in the upper left corner. Going to the right is +x. Going down is +y. canvasSize tells the size of the game’s viewport dimension. class EmberQuestGame extends FlameGame { @override Future onLoad() async { await images.loadAll([ '...', ]); camera.viewfinder.anchor = Anchor.topLeft; _ember = EmberPlayer( position: Vector2(128, canvasSize.y - 128), ); add(_ember); }

Slide 18

Slide 18 text

4. Controls

Slide 19

Slide 19 text

Flame uses mixins Mixin (Dart concept) A mixin is an implemented interface with properties. Like inheritance, but without the need to be inherited. A class can have as many mixins as desired. As such, mixins do not make classes polymorphic. HasKeyboardHandler Components This mixin is added to the FlameGame to enable keyboard events for the game. KeyboardHandler This mixin is added to the classes that respond to keyboard events. class EmberQuestGame extends FlameGame with HasKeyboardHandlerComponents {

Slide 20

Slide 20 text

class EmberPlayer extends SpriteAnimationComponent with KeyboardHandler { @override bool onKeyEvent(KeyEvent event, Set keysPressed) { horizontalDirection = 0; horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.keyA) || keysPressed.contains(LogicalKeyboardKey.arrowLeft)) ? -1 : 0; horizontalDirection += (keysPressed.contains(LogicalKeyboardKey.keyD) || keysPressed.contains(LogicalKeyboardKey.arrowRight)) ? 1 : 0; return true; }

Slide 21

Slide 21 text

@override void update(double dt) { velocity.x = horizontalDirection * moveSpeed; position += velocity * dt; super.update(dt); } Performing the move Let’s make Ember move! The update method is called each game frame, similar to the update method in a Unity GameObject.

Slide 22

Slide 22 text

5. Physics and collisions

Slide 23

Slide 23 text

By default, Flame has no physics. You would have to implement them. Flame has an ecosystem of bridge packages. Forge2D is a 2D physics package. + + + Physics in Flame +

Slide 24

Slide 24 text

Collision mixins Hitboxes A hitbox is an area (or surface for 3D) around something that takes part in collisions. Flame offers a very simple collision matrix. - Active: collides with everything - Passive: collides only with active HasCollisionDetection This mixin is added to the FlameGame to enable collision detection for the game. CollisionCallback This mixin is added to the classes representing things that can collide with each other. class EmberQuestGame extends FlameGame with HasCollisionDetection

Slide 25

Slide 25 text

class EmberPlayer extends SpriteAnimationComponent with CollisionCallbacks { @override void onCollision(Set intersectionPoints, PositionComponent other) { if (other is GroundBlock || other is PlatformBlock) { ... a bunch of physics, like calculating the normal ...

Slide 26

Slide 26 text

6. Making use of Flutter for UI

Slide 27

Slide 27 text

Flutter + Flame Widget Widget … Widget … … GameWidget No Flutter widgets can be a descendant of the GameWidget.* + Flutter widgets can be added to the GameWidget as an overlay. * Widget overlay … … Components This is the way to leverage Flutter for the game’s UI. +

Slide 28

Slide 28 text

class MainMenu extends StatelessWidget { // Reference to parent game. final EmberQuestGame game; const MainMenu({super.key, required this.game}); @override Widget build(BuildContext context) { return Material( ... all the widgets you need ... ElevatedButton( onPressed: () { game.overlays.remove('MainMenu'); },

Slide 29

Slide 29 text

● Build games for many platforms at once. ● Build relatively simple games (no 3D or AAA). ● Leverage the power of Flutter for UI. ● No drag-and-drop GUI (Unity inspector). Repository: https://github.com/songyang-dev/flame_platformer_tutorial Conclusion What is Flame?

Slide 30

Slide 30 text

THANK YOU! v