mirror of
https://github.com/flame-engine/flame.git
synced 2025-11-01 19:12:31 +08:00
docs: Fix typos and add links to the next tutorial steps (#3134)
- Fixed typos and grammar - Rephrased some sentences for brevity purposes - Added link to next stage (I realise these MD files are probably also used to generate https://docs.flame-engine.org/main/tutorials/space_shooter/space_shooter.html where you add the `prev` and `next` buttons but I think it's useful to have these for those viewing them directly from the GH repo in a web browser) --------- Co-authored-by: Lukas Klingsbo <me@lukas.fyi>
This commit is contained in:
@ -87,3 +87,5 @@ game class, insert it into the Flutter widget tree, and render a simple componen
|
||||
:page: step1
|
||||
:show: popup code
|
||||
```
|
||||
|
||||
[Next step: Controlling the player and adding some graphics](./step_2.md)
|
||||
|
||||
@ -194,3 +194,5 @@ structure for developing our game. And that closes this step!
|
||||
:page: step2
|
||||
:show: popup code
|
||||
```
|
||||
|
||||
[Next step: Adding animations and depth](./step_3.md)
|
||||
|
||||
@ -7,7 +7,7 @@ But our game so far is too boring, the starship is just a static sprite and the
|
||||
just a black screen.
|
||||
|
||||
In this step we will look at how to improve that, we will replace the static graphics of the player
|
||||
to an animation and will create a cool sense of depth and movement by adding a parallax to the
|
||||
with an animation and create a cool sense of depth and movement by adding a parallax to the
|
||||
background of the game.
|
||||
|
||||
So lets start by adding the animation to the player ship! For that, we will something that we
|
||||
@ -62,7 +62,7 @@ So lets break down the changes:
|
||||
|
||||
The `SpriteAnimationData` class might look complicated at first glance, but it is actually quite
|
||||
simple, note how we used the `sequenced` constructor, which is a helper to load animation images
|
||||
where the frames are already layed down in the sequence that they will play, then:
|
||||
where the frames are already laid down in the sequence that they will play, then:
|
||||
|
||||
- `amount` defines how many frames the animation has, in this case `4`
|
||||
- `stepTime` is the time in seconds that each frame will be rendered, before it gets replaced
|
||||
@ -135,3 +135,5 @@ more convincing feeling to the player that the spaceship is really crossing the
|
||||
:page: step3
|
||||
:show: popup code
|
||||
```
|
||||
|
||||
[Next step: Adding bullets](./step_4.md)
|
||||
|
||||
@ -3,11 +3,10 @@
|
||||
For this next step we will add a very important feature to any space shooter game, shooting!
|
||||
|
||||
Here is how we will implement it: since we already control our space ship by dragging on the screen
|
||||
with the mouse/fingers, we will make the ship auto shoot when the player stars the dragging and
|
||||
stops shooting when the gesture/input has ended.
|
||||
with the mouse/fingers, we will make the ship auto shoot when the player starts dragging and
|
||||
stop shooting when the gesture/input has ended.
|
||||
|
||||
So let's start, to begin let's first create a `Bullet` component that will represent the
|
||||
shots in the game.
|
||||
First, let's create a `Bullet` component that will represent the shots in the game.
|
||||
|
||||
```dart
|
||||
class Bullet extends SpriteAnimationComponent
|
||||
@ -78,8 +77,8 @@ in the y axis means getting closer to `0` since the top left corner of the scree
|
||||
completely off the screen and it can be removed.
|
||||
|
||||
Right, we now have a `Bullet` class ready, so lets start to implement the action of shooting.
|
||||
First thing, let's create two empty methods in the `Player` class, `startShooting` and
|
||||
`stopShooting`.
|
||||
First thing, let's create two empty methods in the `Player` class, `startShooting()` and
|
||||
`stopShooting()`.
|
||||
|
||||
```dart
|
||||
class Player extends SpriteAnimationComponent
|
||||
@ -97,8 +96,8 @@ class Player extends SpriteAnimationComponent
|
||||
}
|
||||
```
|
||||
|
||||
And let's hook into those methods from the game class, we will do that by using the `onPanStart`
|
||||
and `onPanEnd` methods from the `PanDetector` mixin that we already have been using for the ship
|
||||
And let's hook into those methods from the game class by using the `onPanStart()`
|
||||
and `onPanEnd()` methods from the `PanDetector` mixin that we already have been using for the ship
|
||||
movement:
|
||||
|
||||
```dart
|
||||
@ -183,17 +182,17 @@ to be an variable accessible to the whole component since we will be accessing i
|
||||
`startShooting` and `stopShooting` methods.
|
||||
- We initialize our `_bulletSpawner` in the `onLoad` method. In the first argument, `period`, we set
|
||||
how much time in seconds it will take between calls, and we choose `.2` seconds for now.
|
||||
- We set `selfPositioning: true` so the spawn component don't try to position the created
|
||||
component itself since we want to handle that ourselves to make the bullets spawn out of the ship.
|
||||
- The `factory` attribute receives a function that will be called every time the `period` is reached.
|
||||
and must return the create component.
|
||||
- Then we set that it should not auto start by default.
|
||||
- We set `selfPositioning: true` so the spawn component doesn't try to position the created component
|
||||
since we want to handle that ourselves to make the bullets spawn out of the ship.
|
||||
- The `factory` attribute receives a function that will be called every time the `period` is
|
||||
reached and return the created component.
|
||||
- We set `autoStart: false` so it does not start by default.
|
||||
- Finally we add the `_bulletSpawner` to our component, so it can be processed in the game loop.
|
||||
- Note how the `_bulletSpawner` is added to the game instead of the player, since the bullets
|
||||
are part of the whole game and not the player itself.
|
||||
|
||||
With the `_bulletSpawner` all setup, the only missing piece now is to start the
|
||||
`_bulletSpawner.timer` at `startShooting` and stop it in the `stopShooting`!
|
||||
With the `_bulletSpawner` all set up, the only missing piece now is starting the
|
||||
`_bulletSpawner.timer` in `startShooting()` and stopping it in the `stopShooting()`!
|
||||
|
||||
And that closes this step, putting us real close to a real game!
|
||||
|
||||
@ -202,3 +201,5 @@ And that closes this step, putting us real close to a real game!
|
||||
:page: step4
|
||||
:show: popup code
|
||||
```
|
||||
|
||||
[Next step: Adding Enemies](./step_5.md)
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
Now that the starship is able to shoot, we need something for the player to shoot at! So for
|
||||
this step we will work on adding enemies to the game.
|
||||
|
||||
So first things first, let's create an `Enemy` class that will represent the enemies in game:
|
||||
First, let's create an `Enemy` class that will represent the enemies in game:
|
||||
|
||||
```dart
|
||||
class Enemy extends SpriteAnimationComponent
|
||||
@ -50,13 +50,13 @@ Note that for now, the `Enemy` class is super similar to the `Bullet` one, the o
|
||||
their sizes, animation information and that bullets travel from bottom to top, while enemies travel from
|
||||
top to bottom, so nothing new here.
|
||||
|
||||
Next we need to make the enemies spawn in the game, the logic that we will do here will be simple,
|
||||
we will simply make enemies spawn from the top of the screen at a random position on the `x` axis.
|
||||
Next we need to make the enemies spawn in the game, the logic here will be simple:
|
||||
we will make enemies spawn from the top of the screen at a random position on the `x` axis.
|
||||
|
||||
Once again, we could manually make all the time based event in the game's `update` method, maintain
|
||||
a random instance to get the enemy x position and so on and so forth, but Flame provides us a
|
||||
way to avoid having to write all that by ourselves, we can use the `SpawnComponent`! So in the
|
||||
`SpaceShooterGame.onLoad` method let's add the following code:
|
||||
Once again, we could manually add all the time based events in the game's `update()` method, maintain
|
||||
a random instance to get the enemy x position and so on and so forth, but Flame provides us with a
|
||||
way to avoid having to write all that by ourselves: we can use the `SpawnComponent`! So in the
|
||||
`SpaceShooterGame.onLoad()` method let's add the following code:
|
||||
|
||||
```dart
|
||||
add(
|
||||
@ -87,3 +87,5 @@ And this concludes this short step!
|
||||
:page: step5
|
||||
:show: popup code
|
||||
```
|
||||
|
||||
[Next step: Collision Detection](./step_6.md)
|
||||
|
||||
@ -4,8 +4,7 @@ Right, we are really close to a playable game, we have enemies and we have the a
|
||||
at them! We now need to do something when a bullet hits an enemy.
|
||||
|
||||
Flame provides a collision detection system out of the box, which we will use to implement our
|
||||
logic that will handle when a bullet and an enemy comes into contact. The result will be that
|
||||
both are removed!
|
||||
logic when a bullet and an enemy come into contact. The result will be that both are removed!
|
||||
|
||||
First we need to let our `FlameGame` know that we want collisions between components to
|
||||
be checked. In order to do so, simply add the `HasCollisionDetection` mixin to the declaration
|
||||
@ -18,19 +17,18 @@ class SpaceShooterGame extends FlameGame
|
||||
}
|
||||
```
|
||||
|
||||
With that, Flame now will start to check if components has collided with each other. Next we need to
|
||||
With that, Flame now will start to check if components have collided with each other. Next we need to
|
||||
identify which components can cause collisions.
|
||||
|
||||
In our case those are the `Bullet` and `Enemy` components and we need to add hitboxes to them.
|
||||
|
||||
A hitbox is nothing more than a defined part of the component's area that can hit
|
||||
other objects. Flame offers a collection of classes to define a hitbox, the simplest of them is
|
||||
the `RectangleHitbox`, which like the name implies will make a rectangular area as the component's
|
||||
the `RectangleHitbox`, which like the name implies, will set a rectangular area as the component's
|
||||
hitbox.
|
||||
|
||||
Hitboxes are also components, so in order to add them to our components we can simply add
|
||||
them to the components that we want to have hitboxes, so let's do it, let's start by adding the
|
||||
following line to the `Enemy` class:
|
||||
Hitboxes are also components, so we can simply add them to the components that we want to have hitboxes.
|
||||
Let's start by adding the following line to the `Enemy` class:
|
||||
|
||||
```dart
|
||||
add(RectangleHitbox());
|
||||
@ -51,28 +49,28 @@ performance!
|
||||
|
||||
There are three types of collisions in Flame:
|
||||
|
||||
- `active` collides with other `Hitbox`es of type active or passive
|
||||
- `passive` collides with other `Hitbox`es of type active
|
||||
- `inactive` will not collide with any other `Hitbox`es
|
||||
- `active` collides with other hitboxes of type active or passive
|
||||
- `passive` collides with other hitboxes of type active
|
||||
- `inactive` will not collide with any other hitbox
|
||||
|
||||
Usually it is smart to mark hitboxes from components that will have a higher number of instances
|
||||
Usually it is smart to mark `hitboxes` from components that will have a higher number of instances
|
||||
as passive, so they will be taken into account for collision, but they themselves will not check
|
||||
their own collisions, drastically reducing the number of checking, giving a better performance
|
||||
to the game!
|
||||
|
||||
And since in this game we anticipate that there will be more bullets than enemies, we choose the
|
||||
And since in this game we anticipate that there will be more bullets than enemies, we set the
|
||||
bullets to have a passive collision type!
|
||||
|
||||
From this point on, Flame will take care of checking the collision between those two components,
|
||||
we now need to do something when they come in contact.
|
||||
From this point on, Flame will take care of checking the collision between those two components and
|
||||
we now need to do something when this occurs.
|
||||
|
||||
We can start that by receiving the collision events in one of the classes. Since `Bullet`s have a
|
||||
We start by receiving the collision events in one of the classes. Since `Bullet`s have a
|
||||
passive collision type, we will also add the collision checking logic to the `Enemy` class.
|
||||
|
||||
To listen to collision events we need to add the `CollisionCallbacks` mixin to the component.
|
||||
By doing so we will be able to override some methods like `onCollisionStart` and `onCollisionEnd`.
|
||||
To listen for collision events we need to add the `CollisionCallbacks` mixin to the component.
|
||||
By doing so we will be able to override some methods like `onCollisionStart()` and `onCollisionEnd()`.
|
||||
|
||||
So let's do that and make a few changes to the `Enemy` class:
|
||||
So let's make a few changes to the `Enemy` class:
|
||||
|
||||
```dart
|
||||
class Enemy extends SpriteAnimationComponent
|
||||
@ -101,7 +99,7 @@ we remove both the current `Enemy` instance and the `Bullet`.
|
||||
|
||||
If you run the game now you will finally be able to defeat the enemies crawling down the screen!
|
||||
|
||||
To add some final touches, let's add some explosion animations and add more action to the game!
|
||||
To add some final touches, let's add some explosion animations to introduce more action to the game!
|
||||
|
||||
First, let's create the explosion class:
|
||||
|
||||
@ -139,7 +137,7 @@ that we are passing `loop: false` in the `SpriteAnimationData.sequenced` constru
|
||||
setting `removeOnFinish: true;`. We do that so that when the animation is finished, it will
|
||||
automatically be removed from the game!
|
||||
|
||||
And finally, we make a small change in the `onCollisionStart` method from the `Enemy` class
|
||||
And finally, we make a small change in the `onCollisionStart()` method in the `Enemy` class
|
||||
in order to add the explosion to the game:
|
||||
|
||||
```dart
|
||||
|
||||
Reference in New Issue
Block a user