Overview
This tutorial expands on the Hero’s Trail project provided with
GameMaker. We’ll make an animation for the baddie and create a brand new AI enemy from scratch. We’ll also build a hearts
system for the player and add knockback!
This tutorial has the following sections:
Editing Paths
Creating Animations
Using Sequences
Adding Assets to the Sequence
Animating the Defeated Enemy
Playing the Sequence
Building a New Enemy
Adding the Object
Following the Player
Enemy-Wall Collisions
Idle Flying Behaviour
Turning Left/Right
Defeating the Enemy
Shooting Projectiles
Adding the Object
Projectile Behaviour
Projectile Destroy Animation
Spawning the Projectile
Managing the Alarm
Player Hearts
Adding the Variable
Drawing Hearts on HUD
Hurt Knockback
Defeating the Player
Editing Paths
The enemies in our game (called “baddies”) follow predefined
paths that are designed in the Room Editor. You can easily edit these
to change where they walk.
The “Instances” layer in the game room contains all our enemy instances.
You can double-click on an enemy, open its Variables and see its
assigned path asset in the path_to_follow variable:
For the enemy shown above, the assigned path is path_enemy_1.
You can find it in the “Paths” group in the Asset Browser, open
it and edit it:
However, you cannot see where the path is placed as it’s only shown
on a blank canvas. This is precisely why the Room Editor allows you
to create Path Layers, so you can edit a path asset right inside the room!
You can read more about Path Layers under the “Paths”
section on this manual
page.
Modifying Enemy Paths
Let’s do the following to change where our first enemy walks:
Go to the game room and find the layer called “EnemyPath1”.
If you click on the layer, under the “Layer Properties” window you will see the path asset name: path_enemy_1.
This is the path that was assigned
to the enemy previously shown, so editing this layer will change that enemy’s
path.
c
You can click on the eye icon to turn this layer invisible and then
visible, so you can find where the selected path is in the
room.
You can now move any of the points around to modify the path.
Right-clicking on any point will open a menu allowing you to delete
it.
If you click anywhere else within the room, a new point will be
created on the path, right after the last point.
You can now run the game and see that the enemy follows your modified path!
Under the Layer Properties, you will see that the “Closed”
property is enabled for this path. This means that the last and the
first points in this path will stay connected, forming a loop. You
can disable this if you want your path to have separate starting and ending
points.
The "Start Following Path" action has an "On End" argument to control what happens when the instance reaches the end of its path. Our enemy object simply continues following the path (which you can see in the Create event of obj_baddie), however if you prefer to use a non-closed path with separate starting and ending points, you can use the "Reverse" option so it starts following the path in reverse when it reaches an ending point.
Creating New Enemy Paths
If you want to add a new enemy to the room and create a new path for
it, follow these steps:
Place a new baddie instance in the room.
In the Layers panel, select the “EnemyPaths” group and click on
the following button to create a new Path Layer inside it:
Name this layer "EnemyPath4" (as this is our fourth enemy path in this room). You now need to create an actual path asset for this layer.
Under the Layer Properties, click on “Select Path…” and then
select “Create New”.
This will create a new path asset that will be assigned to this
layer. You can now click anywhere in the room to start adding points
to your new path!
Under the Layer Properties, you can change the “Connection Kind”
to “Smooth Curve” to make the enemy's movements look realistic. You can
also make it closed to form a loop.
We've just created the path itself though, so we need to tell the enemy instance to use it.
Using the Path
You can now assign this path to your new enemy instance:
First of all, select your new Path Layer and look under Layer
Properties to find the name of the assigned path asset. It may be
something like “PathX” where X is a number.
This step is not required but is recommended for good organisation: find the path asset in the Asset Browser (it will usually be at the very bottom of the list) and move it into the "Level1" group under "Paths".
Double click on your enemy instance and open its Variables.
Edit the path_to_follow variable (by clicking on the pencil
icon) and set its value to the new path asset (Path6). This is the path that this enemy will now follow.
If you run the game, you will now see your new enemy following your
new path!
Using Sequences
Sequences are assets that allow you to create your own animations;
you can use them to animate sprites, objects and sounds and then play the
Sequence anywhere in-game!
We’ll create a Sequence animation for the baddie being defeated,
and play that animation when it’s destroyed.
How Will This Work?
We'll create a Sequence asset, which is simply an animation.
This animation will show the baddie falling down.
When a baddie instance is hit with the sword, we'll remove the instance and play the Sequence.
Let’s do the following to create a new Sequence asset:
In the Asset Browser, select the “Sequences” group.
Go to the Create Asset menu at the top and create a
Sequence asset.
Name this asset seq_baddie_defeat. The “seq_” in the
beginning stands for “sequence”.
Sequence Editor
This will open the Sequence Editor in your workspace, which has the
following parts:
The Canvas is where you create and see your animation
The Track Panel is a list of your tracks (which are just your
sprites/objects/sounds)
The Dope Sheet is where you can edit the timings of your
animations (when they move, rotate, etc.)
We will now start creating our enemy’s defeat animation step-by-step,
but for a detailed introduction to Sequences, you may check out the
following resources first:
Adding Assets to the Sequence
Let’s add the baddie's defeated sprite into our Sequence:
In the Asset Browser, go under “Sprites” and open the “Baddie”
group.
Drag and drop the spr_baddie_defeat sprite anywhere into the
Sequence:
If you placed it somewhere within the Canvas, move it so that it’s exactly
in the centre.
If you hit Play in the Dope Sheet, you will see the sprite for a couple frames, and it will then disappear. This is not ideal as we want it to be present throughout the whole Sequence.
Tracks & Dope Sheet
On the left, the Track Panel contains your spr_baddie_defeat
track.
On the right, the Dope Sheet contains the “asset key” for the
track.
You can move and resize this asset key to change when and for how
long the track is visible. We'll extend this to last for the entirety of the Sequence.
You can use the “playhead” in the Dope Sheet to see different
frames. By default, any edits made to a track will be recorded at the current playhead frame.
Currently there is no difference between any of the Sequence's frames, however as we start creating our animation, the playhead will become more useful.
Animating the Defeated Enemy
We'll create a simple animation of the enemy falling down and disappearing. For this, we'll need to create two "keyframes".
A keyframe is a special frame that records the position, rotation, etc. of the sprite. If you have two keyframes, say keyframe A and keyframe B, your sprite will be animated so it gradually goes from its state in keyframe A to its new state in keyframe B.
Our enemy's defeat Sequence will have two keyframes:
- The first keyframe will be its default state, as it currently appears in the Sequence (where the enemy is standing upright).
- The second keyframe will be the enemy rotated and shrunken so it appears fallen down.
The Sequence will then automatically interpolate all frames between those two keyframes to create an animation, so it looks like the enemy actually fell down!
Creating the First Keyframe
The first keyframe will be at the first frame of the animation.
Make sure that the playhead is on frame 0, and then click on the "Record A New Key" button. This will record the current position, rotation and scale of the sprite and create a keyframe at the current frame.
Once you have clicked on that button, your first keyframe is ready (as no other changes are required to it).
Creating the Second Keyframe
The second keyframe will be of the enemy fallen down. We'll do the following to create it (the steps listed below are also shown in a GIF under it):
- Move your playhead to around frame 15 (or an earlier one if you wish to have a shorter animation).
- Rotate the enemy so it faces downwards.
- Move it down and to the right so it appears fallen down.
This will record our second keyframe at the selected frame!
Finishing the Animation
The enemy now appears to fall down, but it does not disappear. We'll now make it shrink (only on one axis) and shorten its asset key so it completely disappears.
Let's do the following (the steps listed below are also shown in a GIF under it):
- Keep the playhead on the second keyframe (you will see it on your asset key with a diamond icon).
- Scale the sprite down vertically and move it up to correct its position.
- Shorten the asset key so the enemy disappears after its second keyframe.
The enemy's defeat animation is now ready!
Keep in mind that you can shorten your animation easily if you feel it is too long: in the Track Panel, expand your track, and in the Dope Sheet move the second keyframe(s) so the animation is shorter. Also make sure to adjust the total asset key length.
Playing the Sequence
We’ll now play our new Sequence when the enemy is defeated, and
destroy the enemy instance so only the Sequence is visible. However, there is something important to
keep in mind.
If you play the defeat Sequence when the sword hits the enemy, the
animation will only appear after 1 frame. If you destroy the instance
at that moment then you will have 1 blank frame where neither the
Sequence nor the enemy is visible.
To work around this, we’ll do the following:
Play the Sequence
Wait 1 frame
Destroy the enemy instance
How Will This Work?
We'll create an "Alarm" in our enemy object.
An Alarm is an event that you can run yourself.
What's special about it is that you can run it later.
So we'll run an Alarm event one frame after the Sequence has played, and in that Alarm event, destroy the enemy instance.
To achieve that, let’s follow these steps:
Go to obj_baddie. This object has a collision event with the
sword object, however it’s greyed out because it’s inherited
from the enemy’s parent object.
The parent object is what currently controls how the baddie loses, which is why it inherits the parent event and simply uses that.
We want to redefine this event for this particular enemy, so
right-click on the event and select “Override Event”.
You will now have a new, empty event.
Search for the “Set Alarm Countdown” action and drop it into the
event.
Search for the “Create Sequence” action and drop it into the
event.
Use the following settings for the new actions:
Alarm Events
GameMaker's Alarm events can be told to run after a
specific number of frames. In the above event, we are telling Alarm 0
to run after 1 frame.
Let’s program this Alarm to destroy the enemy instance:
Now in the same object (obj_baddie) add a new event: go under
“Alarm” and select “Alarm 0”:
This event runs 1 frame after the enemy’s collision with a sword,
because we told it to.
Add the “Destroy Instance” action in this event.
Now run the game, attack an enemy and you will see your Sequence
animation!
(Optional) Sequence Depth-Sorting
NOTE: This section is optional; keep reading to learn how to implement Sequence depth-sorting, or skip to "Building a New Enemy".
You may notice that the defeated enemy Sequence sometimes appears above the
player even when it should be behind it:
This happens because the Sequence is simply displayed on the
“Instances” layer and is not depth-sorted like object instances.
What is Depth-Sorting?
Depth-sorting is how the game figures out whether an instance should appear behind or in front of another instance.
It's already implemented in the base project, however it only applies to object instances, not Sequences (as Sequences don't run code like objects do).
We now have to carry the baddie instance's depth over to its defeat Sequence.
As a simple workaround, we can create a new layer that uses the depth value of the baddie instance and display the Sequence there.
Here’s how you can implement that:
Go to obj_baddie and open its collision event with obj_sword_attack.
Before "Create Sequence", add the "Function Call" action.
Use this action to call the layer_create function. Enter depth as the argument. Set the
“Target” to seq_layer so the layer ID is stored in that
variable (make it temporary).
This will create a new layer at that depth, so anything in this
layer will appear at the same depth as the baddie.
In the “Create Sequence” action, pass in the seq_layer
variable so the Sequence is created in that layer.
Your event should now look like this, with the new "Function Call" action in the middle:
The baddie defeat Sequence will now always appear at the correct
depth; e.g., if the enemy is behind the player, the Sequence will
also appear behind it, and if the enemy is in front, the Sequence will also be in the front:
Building a New Enemy
We’ll create a new bat enemy that flies around and follows the
player. It will also shoot projectiles at the player.
How Will This Work?
We'll create a new object for the bat, and it will be a child of the enemy parent.
The bat will create an imaginary rectangle around itself, and check whether the player resides within that rectangle.
If the player is in the rectangle, the bat will start moving towards the player.
Later, we will use Alarm events so the bat can repeatedly fire projectiles towards the player.
Let’s start by creating its object!
In the Asset Browser, open "Objects", then “Game” and select the “Enemies”
group.
Here, create a new object and name this obj_bat.
Assign the spr_bat_fly sprite to it, which can be found in
the “Bat” group under “Sprites”.
Open its Parent menu and assign obj_enemy_parent as its
parent.
Since we’ve made this a child of obj_enemy_parent, it will
automatically hurt the player on collision, and the player’s sword
will also be able to defeat it!
Go ahead and place it anywhere in the room (make sure to use the "Instances" layer):
Keep in mind that it's completely up to you how you want to organise your layers, so if you like, you can create a new Instance layer for your enemies and put the baddie and bats in there!
Following the Player
The bat should follow the player when they’re close to each other.
For this, we’ll create an imaginary rectangle around the bat that spreads 200 pixels in each
direction, and check if the player is simply touching that rectangle:
If the player overlaps that rectangular area, the bat will start going after it!
Let’s program that:
Add the Step event to obj_bat. This event runs every frame,
so we can program our AI behaviour here.
Add the “If Collision Shape” action to the event. This is a
condition that allows you to check for collisions within a rectangular area.
Attach the following actions to this condition:
"Set Speed" (not to be confused with "Set Animation Speed")
"Set Point Direction"
Use the following settings for these actions:
The bat will now constantly check for the player being in that rectangular area, and if it's found, the bat will start following it!
At the end of that GIF, you will notice a problem: the bat can move
through walls! We need to give it collisions, just like the player.
Enemy-Wall Collisions
This is very simple as we can copy the player’s collision
event, and paste it into the enemy parent object (so all enemies get collisions!):
Go to obj_player. Right-click on the obj_collision_parent event and select “Copy Event”.
Go to obj_enemy_parent. Right-click anywhere in the Events
window and select “Paste Event”.
Voila! All enemies now have collisions, just like the player!
This means that bats will now be stopped by walls:
If you are curious to know how the collision event was implemented,
read this section of the Hero’s Trail breakdown page.
Idle Flying Behaviour
Before the bat starts following the player, it stands still. We want
it to fly around in a circle when the player is out of its range, so
let’s do the following:
Go to obj_bat and open its Step event.
Search for the “Else” action and drop it below the “If
Collision Shape” action.
The “Else” action always comes after a condition. You can
attach actions to it, and they will run when the original condition
is not true.
This means that any actions attached to this Else will run when the bat doesn't find the player near it.
More detailed explanation about the Else action is given in the next section.
Attach the following actions to the “Else” action:
"Set Speed"
"Set Direction Variable"
Use the following settings for the new actions:
What is Else?
Else is always used after a condition, and other
actions can be attached to Else, just like in a condition.
When the previous condition is true, only the actions attached to that
condition are executed.
When the previous condition is false, only the actions attached to the
Else action are executed.
This way we can control which actions run and don’t run depending
on one condition!
So what does the event do?
If the bat finds the player near it, it starts following it.
Otherwise, it simply keeps adding +2 to its direction value, so that
it keeps moving in a circle.
Run the game now, keep away from the bat and you will see it keeps
flying in a circle!
When the player runs away, the bat starts flying in a circle again. We've got our "idle" behaviour set up!
You will notice that the bat doesn’t look in the correct direction
- it’s always looking to the right. Let’s change that!
Turning Left/Right
We’re basically going to flip the bat’s sprite depending on
whether it’s moving left or right.
By default, the bat’s
sprite faces right. This means that we need to flip it in order to
make it face left.
Let’s do the following:
Open obj_bat and add the End Step event.
This event runs after the Step event (which is when the instance
moves). We’re using End Step to run actions after the
instance has moved.
Add the “Declare Temp” action to the event. This is used to
declare (create) a temporary variable, which is only usable within the same event.
Then add the following actions:
"If Variable"
(Attach) "Set Instance Scale"
"Else"
(Attach) "Set Instance Scale"
Use the following settings for the added actions:
Moving to the left requires a negative X speed, which is how we know
that the bat is moving left when its X speed (that we calculated) is
less than 0.
Run the game now, and you will see that the bat now correctly faces left or right
depending on where it’s going!
Defeating the Enemy
Currently you can defeat the bat, however it uses the generic dust
effect that was implemented in the enemy parent. We’re going to
change it up for this bat specifically.
Let’s do the following:
Go to obj_bat. This will have a collision event with
obj_sword_attack, but it’ll be greyed out because it’s
inherited from the parent object.
We want to redefine this for the bat specifically, so right-click on
it and select “Override Event”. (This is the same thing with did in obj_baddie earlier!)
In the event, destroy the instance, and then create a “Smoke Up”
particle effect as shown in the image below -- you can set its
colour to match the look of the bat itself:
This is the same thing the parent’s event did; we’ve only changed
up what particle is shown when the bat is destroyed. Looks much nicer
than before!
Tip: You don't have to stick to just one particle effect! You can place more than one "Do Effect" actions in the event and set up a combination of different particle effects!
You can also follow the same steps as the baddie and create a
Sequence animation for the bat
being defeated.
Shooting Projectiles
We’re going to give extra powers to the bat: it’ll shoot
projectiles at the player. More difficulty, yay!
Let’s start by adding an object for the projectile:
In the Asset Browser, open "Objects" -> “Game” and select the “Enemies”
group.
Here, create a new object and name this obj_bat_projectile.
Assign the spr_bat_projectile sprite to it, which can be
found in the “Bat” group under “Sprites”.
Open its Parent menu and assign obj_enemy_parent as its
parent.
Since this projectile is also a child of the enemy parent, it means
that it can hurt the player and it can be defeated with a sword too.
See how easy it is to create new objects that reuse the same
features? That’s the power of object parenting!
Projectile Behaviour
We want this projectile to move towards the player. To implement
that, let’s do the following:
Add the Create event to this object.
Add the “Set Speed” action to this event. Set the speed to 4 (or
any other speed you prefer). This is the speed the projectile moves at.
Add the “If Instance Exists” action to make sure that an
obj_player instance exists in the room.
To this condition, attach the “Set Point Direction” action and
make it point towards obj_player.x and obj_player.y.
Then attach a “Set Instance Rotation” action, which is used to
rotate the instance’s sprite (as opposed to its movement
direction). Set this to direction so it faces in the same
direction it’s moving in.
direction is a variable that stores the angle of the direction that the instance is moving in.
Whenever the projectile instance is created, it will automatically
move and face towards the player.
Particle Trail
The projectile should leave a trail of particles behind it as it
shoots towards the player. We can do the following to implement that:
Add the Step event to this object (obj_bat_projectile).
Each frame we’ll create a new particle, but it should be placed
randomly around the projectile; so we need to calculate random
values for the particle's X and Y.
Add the “Get Random Number” action to calculate a random value
between -5 and 5 (you can change this if you want the
particle to move more or less); store the result in a temporary
variable called relative_x.
Add the same action again (you can also copy/paste it); this time,
store the result in a temporary variable called relative_y.
Now we have separate random values for X and for Y!
Add the “Do Effect” action to this event and create a
small-sized “Spark” particle with a green colour.
Set “X” and “Y” to the previously calculated
relative_x and relative_y variables, and make sure to
enable the “Relative” checkbox for both of them.
Since this particle is being created every step (or, every frame) it
will appear like a trail within the game; it will also be somewhat
random and not completely straight, thanks to our “Get Random”
actions:
Wall Collision
The projectile is a child of the enemy parent, and so it will have
inherited the obj_collision_parent Collision event. This will
stop the projectile from moving through a wall, however we simply
want it to be destroyed as soon as it comes in contact with a wall.
Let’s do the following:
Go to the obj_bat_projectile object and open its Events
window.
Right-click on the obj_collision_parent event and select
“Override Event”.
Add the "Destroy Instance" action in this event.
Sword Collision
Now we need to set up the effect that is shown when the player’s
sword hits the projectile:
In the same object, override the Collision event with
obj_sword_attack.
In this event, destroy the instance and create a small “ring” effect.
Spawning the Projectile
The bat should shoot a projectile every 1.5 seconds while it’s near
the player. This will be achieved using an Alarm event, so let’s
create it:
Go to obj_bat and add the Alarm 0 event.
Add the “Create Instance” action to create an instance of the
bat projectile.
Add the “Set Alarm Countdown” action to run this alarm again
after 1.5 seconds. Since 1 second has 60 frames, we’ll pass in the
value 90 for 1.5 seconds.
Feel free to change this value if you want the bat to shoot more or less frequently!
Managing the Alarm
Our Alarm 0 event creates a projectile, so let’s make sure that the
event runs when the player is in the bat’s range.
Open obj_bat’s Step event.
The actions that we’re going to add below should be attached to
the “If Collision Shape” action.
Add the “If Variable” action to check if Alarm 0’s value (alarm[0]) is
less than 0, meaning it’s inactive.
Add the “Set Alarm Countdown” action and attach it to the new “If
Variable” action. Set Alarm 0 to 1.
This will tell Alarm 0 to run after 1 frame, as long as it is
inactive. We’re checking that using a condition to make sure that
the alarm is not constantly being called even while it’s active, as
that would cause it to never run.
Stopping the Alarm
The actions we’ve added above would tell Alarm 0 to run when the
bat has found the player, however after that it would never stop
running. We have to make sure that it stops shooting when the player goes out
of the bat’s range, so we’ll do the following:
Search for the “Set Alarm Countdown” action and attach it to the Else
action.
Set Alarm 0 to -1 to make it inactive. This makes sure that
it stops running.
Run the game now, and you will see that bats start shooting
projectiles as soon as you go near it!
You are also able to defeat the projectile itself using your sword.
Should make for some interesting gameplay!
You can change the interval between each shot by going into Alarm 0
and modifying the value in the “Set Alarm Countdown” action
(which is currently set to 90 frames, or 1.5 seconds). If you think
the projectile is too fast or too slow, you can modify its speed in
its Create event.
Projectile Destroy Animation
Whenever the bat’s projectile is destroyed, whether it’s from touching a wall or being hit by the player, it should play the spr_bat_projectile_splatter animation:
We’ll create an object for this that only plays once and then destroys itself:
Create an object called obj_bat_projectile_splatter, then assign the spr_bat_projectile_splatter sprite to it.
Add the Animation End event to it.
In this event, add the “Destroy Instance” action. This will make sure that the instance is destroyed once its animation ends playing.
We’re now going to create this splatter instance when the projectile itself is destroyed, which should be straightforward to implement:
Go to obj_bat_projectile.
Add the Destroy event -- this runs when the instance is destroyed using the “Destroy Instance” action.
Here, add a “Create Instance” action to create an instance of obj_bat_projectile_splatter. Create it at the current instance’s relative position, inside the “Instances” layer.
The splatter animation will now play whenever a projectile is destroyed!
Player Hearts
With all these powerful enemies, it’s unfair that the player goes
down with just one hit. We should allow the player to have multiple
hearts so they can strike back!
Adding the Variables
The player needs a variable to store the number of maximum hearts
that it can have, and the number of hearts it currently has. Let’s
do the following:
Go to obj_player and open its Create event.
Add the “Assign Variable” action, which we’ll use to create
new variables.
Create a variable with the name max_hearts and a value of 4.
Then click on the plus sign to add a new variable. Name this
hearts and set its value to max_hearts.
We’re setting hearts to max_hearts, which means that
the hearts variable will start with the same value that was
assigned to max_hearts (which is 4). As a result the player
will start with 4 hearts, but you can change that value to make the
game easier or harder.
Drawing Hearts on HUD
We’ll now draw the hearts on the HUD. This is done using the Draw
GUI event, which is used to draw sprites/text on the “GUI Layer”.
This layer is automatically drawn above the game and stays on-screen,
no matter where the in-game camera moves.
Existing Draw GUI
In the Asset Browser, open “Objects” and expand the “Game”
group.
Open the obj_manager object. This object “manages” our
game in the background, and it also draws the HUD.
Open the Draw GUI event.
This event will already have some actions, which handle drawing the
player’s coins. The existing actions do the following in the given order:
If the player exists in the room,
Draws the coin HUD sprite
Sets the font
Draws the player’s coins value (by writing
obj_player.coins)
We’ll now add another action to this event so it draws the player’s
hearts.
Drawing Hearts
Let’s do the following to draw the player’s hearts:
Add the “Draw Stacked Sprites” action to the Draw GUI event. Make sure it is attached to the existing "If Instance Exists" condition.
This action draws the same sprite a specified number of times,
either horizontally or vertically (as specified in the options).
Set the “Sprite” to spr_hud_heart. You will find this
sprite in the “HUD” group under “Sprites”.
Use the following settings for the rest of the arguments:
You can change the X and Y values if you want to position the hearts differently.
If you run the game, you will see the number of hearts on-screen that
you specified in the max_hearts variable:
The player still goes down with one hit, so let’s make it so the
hearts go down on each hit.
Hurt Knockback
When the player touches an enemy, it should go into a “hurt”
state and get knocked back. It should also lose a heart.
Let’s do the following:
Go to obj_player and open its collision event with
obj_enemy_parent.
This event runs when the player touches an enemy. Currently it stops the
player, changes its color to red and sets Alarm 0, which restarts
the room after some frames.
You will find an “Assign Variable” action here which sets the
player’s move_speed to 0, so that it can’t move.
We don’t need this action anymore, so click on the X button to
delete it.
Let’s now apply knockback movement to the player and reduce the hearts
value.
Make sure that all the new actions are attached to the “If
Variable” action, just like the existing actions in this event.
We’ll add the following actions to create a knockback effect:
“Set Point Direction”: This will be used to set the
player’s direction towards the colliding enemy.
“Set Direction Variable”: This will be used to reverse
the direction so the player ends up facing away from the
enemy.
“Set Speed”: This will set the speed of the player so it
moves in the given direction.
Finally, we’ll add the “Assign Variable” action to reduce the
hearts value by adding -1 to it.
Now whenever the player comes in contact with an enemy, it will
receive a knockback and its hearts value will go down.
However, this event calls Alarm 0 which currently restarts the game, so
we need to make sure that that only happens when the player is fully
defeated.
Defeating the Player
Let's now take care of what happens when the player runs out of all hearts.
Defeated Object
We’ll create a new object for the player’s “defeated” state.
Let’s do the following:
Under "Objects" -> "Game", create a new object called obj_player_defeated.
Assign the spr_player_defeated sprite to it, which can be
found in the “Player” group under “Sprites”.
Add the “Animation End” event to this object (this event can be
found under “Other”).
In the event, add the “Restart Room” action to restart
the room when the animation ends.
We now need to create an instance of this object, which will play the
defeat animation and then automatically restart the room.
Transition to Defeat
We’ll now handle stopping the player after its knockback, and
restarting the game if the hearts are all gone.
Open the player’s Alarm 0 event and remove any existing
actions so that it’s empty.
It used to restart the room after being hit but now it should only do that if the player has run out of hearts.
Add the “Set Speed” action to reset the speed back to 0.
This will stop the player’s knockback.
Add an “If Variable” condition to check if the hearts
variable is greater than 0, meaning that the player still has
some hearts remaining.
If that is true, set the instance’s colour back to white by
attaching the “Set Instance Colour” action to it.
Add an “Else” action which will run when the player has
run out of hearts.
Attach “Create Instance” to “Else” to create
an instance of obj_player_defeated, and then destroy the
player instance itself.
Here is what your event should look like now:
This will effectively “transition” the player into its defeated
state once the hearts value is at 0.
If you run the game now and run into an enemy, you will see the
player getting knocked back and losing a heart. Once all hearts are
gone, the defeat animation plays and the level restarts.
Summary
Our baddie now has a great defeat animation thanks to Sequences, we
have a brand new enemy that flies in circles and spits acid at the
player and a solid health and knockback system for the player. Our
game’s on the next level already!
Here are some of the things we learned in this part:
- You can assign path assets to Path Layers in a room, and assign the path asset to an instance for use in its events
- You can create your own animations in Sequences, and play them using the "Create Sequence" action
- You can use Alarms to perform actions at a later time, and to run repeated actions (like shooting projectiles)
- You can use "If Collision Shape" to check if an object is intersecting with a shape
- You can create particle trails in the Step event
Enemies have gotten too much attention though! In the next part,
we’ll work on player upgrades and power ups, and also give it a
rechargeable energy shield!
-> Continue to next part
-> Go back to index page