docs: Update platformer tutorial to latest Flame (#2904)

Updates the  platformer tutorial to Flame v1.11.0
This commit is contained in:
Lukas Klingsbo
2023-12-08 20:19:09 +01:00
committed by GitHub
parent 957db3c1ed
commit eef51968e7
9 changed files with 62 additions and 86 deletions

View File

@ -45,7 +45,6 @@ raycasts # plural of raycast
raytrace # act of raytracing
raytracing # rendering techniques that calculates light rays as straight lines
rects # plural of rect
refactorings # plural of refactoring
respawned # past tense of respawn
respawn # when the player character dies and is brought back after some time and penalties
RGBA # red green blue alpha

View File

@ -2,8 +2,6 @@
bloodlust
collidable
collidables
composability
discoverability
draggables
focusable
gamepad

View File

@ -23,7 +23,7 @@ void main() {
Like in the [klondike](../klondike/klondike.md) tutorial, starting a new game can feel overwhelming.
I like to first decide what platform I am trying to target. Will this be a mobile game, a desktop
game, or maybe a web game, with Flutter and Flame, these are all possible. For this game though, I
game, or maybe a web game, with Flutter and Flame, these are all possible. For this game though, I
am going to focus on a web game. This means my users will interact with the game using their
keyboards.
@ -45,16 +45,16 @@ All of these will be brought together in `EmberQuestGame` derived from `FlameGam
## Assets
Every game needs assets. Assets are images, sprites, animations, sounds, etc. Now, I am not an
Every game needs assets. Assets are images, sprites, animations, sounds, etc. Now, I am not an
artist, but because I am basing this game on Ember, the flame mascot, and Ember is already designed,
it sets the tone that this will be a pixel art game. There are numerous sites available that
it sets the tone that this will be a pixel art game. There are numerous sites available that
provide free pixel art that can be used in games, but please check and comply with the licensing and
always provide valid creator attribution. For this game though, I am going to take a chance and
make my artwork using an online pixel art tool. If you decide to use this tool, multiple online
tutorials will assist you with the basic operations as well as exporting the assets. Now normally,
most games will utilize sprite sheets. These combine many images into one larger image that can be
sectioned and used as individual images. For this tutorial though, I specifically will save the
images individually as I want to demonstrate the Flame engine's caching abilities. Ember and the
always provide valid creator attribution. For this game though, I am going to take a chance and
make my artwork using an online pixel art tool. If you decide to use this tool, multiple online
tutorials will assist you with the basic operations as well as exporting the assets. Now normally,
most games will utilize sprite sheets. These combine many images into one larger image that can be
sectioned and used as individual images. For this tutorial though, I specifically will save the
images individually as I want to demonstrate the Flame engine's caching abilities. Ember and the
water enemy are sprite sheets though as they contain multiple images to create animations.
Right-click the images below, choose "Save as...", and store them in the `assets/images` folder of the
@ -88,8 +88,8 @@ emberquest/
You may ask, why are the images different sizes?
As I was using the online tool to make the assets, I had trouble getting the
detail I desired for the game in a 16x16 block. The heart worked out in 32x32
and the ground as well as the star were 64x64. Regardless, the asset size does
detail I desired for the game in a 16x16 block. The heart worked out in 32x32
and the ground as well as the star were 64x64. Regardless, the asset size does
not matter for the game as we will resize as needed.
```

View File

@ -91,20 +91,15 @@ You can run this file and you should just have a blank screen now. Let's get Emb
## CameraComponent and World
Since `FlameGame.camera` is deprecated, we want to add a `CameraComponent` that we can move around,
and a world that we can add all our components to and move around our player in.
(The `CameraComponent` will be built-in in Flame v2).
To move around in the world we are going the use the built-in `CameraComponent` and `World` that
exists on the `FlameGame` class.
We are going to add all our components to the `world` and follow the player with the `camera`.
```dart
import 'package:flame/components.dart';
import 'package:flame/game.dart';
class EmberQuestGame extends FlameGame {
EmberQuestGame();
final world = World();
late final CameraComponent cameraComponent;
@override
Future<void> onLoad() async {
await images.loadAll([
@ -117,12 +112,10 @@ class EmberQuestGame extends FlameGame {
'water_enemy.png',
]);
cameraComponent = CameraComponent(world: world);
// Everything in this tutorial assumes that the position
// of the `CameraComponent`s viewfinder (where the camera is looking)
// is in the top left corner, that's why we set the anchor here.
cameraComponent.viewfinder.anchor = Anchor.topLeft;
addAll([cameraComponent, world]);
camera.viewfinder.anchor = Anchor.topLeft;
}
}
```
@ -140,7 +133,7 @@ import 'package:flame/components.dart';
import '../ember_quest.dart';
class EmberPlayer extends SpriteAnimationComponent
with HasGameRef<EmberQuestGame> {
with HasGameReference<EmberQuestGame> {
EmberPlayer({
required super.position,
}) : super(size: Vector2.all(64), anchor: Anchor.center);
@ -181,13 +174,8 @@ import 'package:flame/game.dart';
import 'actors/ember.dart';
class EmberQuestGame extends FlameGame {
EmberQuestGame();
late EmberPlayer _ember;
final world = World();
late final CameraComponent cameraComponent;
@override
Future<void> onLoad() async {
await images.loadAll([
@ -200,9 +188,7 @@ class EmberQuestGame extends FlameGame {
'water_enemy.png',
]);
cameraComponent = CameraComponent(world: world);
cameraComponent.viewfinder.anchor = Anchor.topLeft;
addAll([cameraComponent, world]);
camera.viewfinder.anchor = Anchor.topLeft;
_ember = EmberPlayer(
position: Vector2(128, canvasSize.y - 70),

View File

@ -26,17 +26,17 @@ so first create a new folder called `lib/objects`. In that folder, create 3 file
boilerplate code for the class, so create the following in their respective files:
```dart
class GroundBlock{}
class GroundBlock {}
class PlatformBlock{}
class PlatformBlock {}
class Star{}
class Star {}
```
Also, create `water_enemy.dart` in the `lib/actors` folder using this boilerplate code:
```dart
class WaterEnemy{}
class WaterEnemy {}
```
Now we can create a file called `segment_manager.dart` which will be placed in a new folder called
@ -300,10 +300,7 @@ as:
'water_enemy.png',
]);
cameraComponent = CameraComponent(world: world);
cameraComponent.viewfinder.anchor = Anchor.topLeft;
addAll([cameraComponent, world]);
camera.viewfinder.anchor = Anchor.topLeft;
initializeGame();
}
```
@ -329,7 +326,7 @@ import 'package:flame/components.dart';
import '../ember_quest.dart';
class PlatformBlock extends SpriteComponent
with HasGameRef<EmberQuestGame> {
with HasGameReference<EmberQuestGame> {
final Vector2 gridPosition;
double xOffset;
@ -433,11 +430,11 @@ the block in a `Vector2`. So add the following to your `loadGameSegments` method
```dart
case PlatformBlock:
add(PlatformBlock(
gridPosition: block.gridPosition,
xOffset: xPositionOffset,
));
break;
add(PlatformBlock(
gridPosition: block.gridPosition,
xOffset: xPositionOffset,
));
break;
```
If you run your code, you should now see:
@ -453,7 +450,7 @@ import 'package:flutter/material.dart';
@override
Color backgroundColor() {
return const Color.fromARGB(255, 173, 223, 247);
return const Color.fromARGB(255, 173, 223, 247);
}
```

View File

@ -17,7 +17,7 @@ import 'package:flutter/material.dart';
import '../ember_quest.dart';
class Star extends SpriteComponent
with HasGameRef<EmberQuestGame> {
with HasGameReference<EmberQuestGame> {
final Vector2 gridPosition;
double xOffset;
@ -65,7 +65,7 @@ So the only change between the Star and the Platform beyond the anchor is simply
```dart
add(
SizeEffect.by(
Vector2(-24, -24),
Vector2(-24, -24),
EffectController(
duration: .75,
reverseDuration: .5,
@ -76,24 +76,24 @@ add(
);
```
The `SizeEffect` is best explained by going to their [help
docs](../../flame/effects.md#sizeeffectby). In short, we simply reduce the size of the star
The `SizeEffect` is best explained by going to their
[docs](../../flame/effects.md#sizeeffectby). In short, we simply reduce the size of the star
by -24 pixels in both directions and we make it pulse infinitely using the `EffectController`.
Don't forget to add the star to your `lib/ember_quest.dart` file by doing:
```dart
case Star:
add(
Star(
gridPosition: block.gridPosition,
xOffset: xPositionOffset,
),
);
break;
world.add(
Star(
gridPosition: block.gridPosition,
xOffset: xPositionOffset,
),
);
break;
```
If you run your game, you should now see pulsing stars!
If you run your game, you should now see pulsating stars!
## Water Enemy
@ -109,7 +109,7 @@ import 'package:flame/effects.dart';
import '../ember_quest.dart';
class WaterEnemy extends SpriteAnimationComponent
with HasGameRef<EmberQuestGame> {
with HasGameReference<EmberQuestGame> {
final Vector2 gridPosition;
double xOffset;
@ -171,7 +171,7 @@ Don't forget to add the water enemy to your `lib/ember_quest.dart` file by doing
```dart
case WaterEnemy:
add(
world.add(
WaterEnemy(
gridPosition: block.gridPosition,
xOffset: xPositionOffset,
@ -204,7 +204,7 @@ import 'package:flutter/material.dart';
import '../ember_quest.dart';
class GroundBlock extends SpriteComponent with HasGameRef<EmberQuestGame> {
class GroundBlock extends SpriteComponent with HasGameReference<EmberQuestGame> {
final Vector2 gridPosition;
double xOffset;
@ -253,8 +253,8 @@ Now in your Ground Block's `onLoad` method, add the following at the end of the
```dart
if (gridPosition.x == 9 && position.x > game.lastBlockXPosition) {
game.lastBlockKey = _blockKey;
game.lastBlockXPosition = position.x + size.x;
game.lastBlockKey = _blockKey;
game.lastBlockXPosition = position.x + size.x;
}
```
@ -334,7 +334,7 @@ import 'package:flutter/material.dart';
import '../ember_quest.dart';
import '../managers/segment_manager.dart';
class GroundBlock extends SpriteComponent with HasGameRef<EmberQuestGame> {
class GroundBlock extends SpriteComponent with HasGameReference<EmberQuestGame> {
final Vector2 gridPosition;
double xOffset;
@ -391,13 +391,13 @@ Finally, don't forget to add your Ground Block to `lib/ember_quest.dart` by addi
```dart
case GroundBlock:
add(
GroundBlock(
gridPosition: block.gridPosition,
xOffset: xPositionOffset,
),
);
break;
world.add(
GroundBlock(
gridPosition: block.gridPosition,
xOffset: xPositionOffset,
),
);
break;
```
If you run your code, your game should now look like this:

View File

@ -20,7 +20,7 @@ class EmberQuestGame extends FlameGame with HasKeyboardHandlerComponents {
```dart
class EmberPlayer extends SpriteAnimationComponent
with KeyboardHandler, HasGameRef<EmberQuestGame> {
with KeyboardHandler, HasGameReference<EmberQuestGame> {
```
Now we can add a new method:
@ -118,7 +118,7 @@ Next, add the `CollisionCallbacks` mixin to `lib/actors/ember.dart` like:
```dart
class EmberPlayer extends SpriteAnimationComponent
with KeyboardHandler, CollisionCallbacks, HasGameRef<EmberQuestGame> {
with KeyboardHandler, CollisionCallbacks, HasGameReference<EmberQuestGame> {
```
If it did not auto-import, you will need the following:
@ -176,9 +176,7 @@ For the collisions to be activated for Ember, we need to add a `CircleHitbox`, s
method, add the following:
```dart
add(
CircleHitbox(),
);
add(CircleHitbox());
```
Now that we have the basic collisions created, we can add gravity so Ember exists in a game world

View File

@ -26,7 +26,7 @@ enum HeartState {
}
class HeartHealthComponent extends SpriteGroupComponent<HeartState>
with HasGameRef<EmberQuestGame> {
with HasGameReference<EmberQuestGame> {
final int heartNumber;
HeartHealthComponent({
@ -88,7 +88,7 @@ import 'package:flutter/material.dart';
import '../ember_quest.dart';
import 'heart.dart';
class Hud extends PositionComponent with HasGameRef<EmberQuestGame> {
class Hud extends PositionComponent with HasGameReference<EmberQuestGame> {
Hud({
super.position,
super.size,
@ -152,7 +152,7 @@ the number of hearts necessary. The last step is to add the hud to the game.
Go to `lib/ember_quest.dart` and add the following code in the `initializeGame` method:
```dart
cameraComponent.viewport.add(Hud());
camera.viewport.add(Hud());
```
If the auto-import did not occur, you will need to add:

View File

@ -185,10 +185,8 @@ Future<void> onLoad() async {
'star.png',
'water_enemy.png',
]);
cameraComponent = CameraComponent(world: world);
cameraComponent.viewfinder.anchor = Anchor.topLeft;
addAll([cameraComponent, world]);
camera.viewfinder.anchor = Anchor.topLeft;
initializeGame(true);
}