Welcome to Part 5 of the Hero’s Trail tutorials!
This tutorial expands on the Hero’s Trail project provided with GameMaker Studio 2. We’ll give the player the ability to attack in all four directions and use a shield, as well as add heart pickups and speed/invincibility power ups!
This tutorial has the following sections:
Currently the player can only attack to the left or right, so now we’ll allow it to attack in all 4 directions. For this we’ll create a variable to store the direction that the player is facing in.
Let’s do the following:
Go to obj_player and open its Create event.
Add the “Assign Variable” action and create a variable called input_direction.
This variable will have four possible values indicating the input direction:
This variable will be set in each arrow key event, so the following events will need the actions shown next to them:
Add the following action to the Key Down - Left event:
Add the following action to the Key Down - Up event:
Add the following action to the Key Down - Right event:
Add the following action to the Key Down - Down event:
Now when the player presses an arrow key, the input direction will be set accordingly. We can use this value to swing our sword in the correct direction!
When the sword is created, we’ll change its rotation so it uses the input_direction value as its angle. Let’s do the following:
Open obj_player’s Key Press - Space event.
This event will already have an “Assign Variable” action which changes the image_xscale of the sword. Remove this action.
Add a new “Assign Variable” action. Make sure to place it after the “Create Instance” action.
We’ll use this action to change the image_angle of the sword, which is the rotation of its sprite.
Set its value to input_direction so the sword faces in the direction stored in that variable.
Run the game now and you will be able to attack in all four directions. We just made the game a lot more fun and easier!
The player can lose hearts, so we need to resupply them with heart pickups throughout the level so they can keep fighting.
Let’s start by creating a heart pickup object:
Go to "Objects" -> "Game".
Here, create a new object called obj_heart_pickup.
Assign the spr_heart_pickup sprite to it, which can be found in the “Items” group under “Sprites”.
You can now go ahead and place these hearts in the room, inside the “Instances” layer.
We’ll now make the player able to collect these hearts. Let’s do the following:
Open obj_player and add a collision event with the new obj_heart_pickup object.
Add the “If Variable” action in this event. This condition should check if the hearts variable is less than max_hearts, meaning that the player is missing some hearts.
Add an “Assign Variable” action and attach it to the condition. Use this to increase the value of the hearts variable by 1.
Attach an “Apply To” action, click on the little arrow next to the X button and select “Other”.
Any actions attached to this event will now be applied to the “other” instance in the collision, which is the heart pickup (as the player is the “self”).
Attach the “Destroy Instance” and “Do Effect” actions to “Apply To”.
Use the following settings for your actions:
You can now run the game and pick up hearts! You’ll notice that you can’t collect them when your hearts are full. This makes sure that any excess heart pickups are saved for later.
We’ll now create a power up that makes the player super fast. Let’s start by setting up the object:
Create a new object called obj_powerup_speed.
Assign the spr_powerup_speed sprite to it, found in the “Items” folder under “Sprites”.
Now go ahead and place this power up anywhere in your room. Right now try to place it somewhere near the player’s starting position so you can test it quickly.
We’ll create a power up system in the player object, so it can equip powers that last for a certain amount of seconds (or for as long as you like!).
Let’s do the following to create our power up system:
Go into obj_player and open the Create event.
Use the “Assign Variable” action to create a variable called powerup_active with a value of false.
Create another variable called default_move_speed and set its value to move_speed.
The player should be able to collect a power up and have its properties change based on the power up.
Let’s implement the effects of the speed power up by doing the following:
In the player object, add a collision event with obj_powerup_speed.
We should only be able to collect this power up if the player does not already have one, so we’ll add an “If Variable” condition to make sure that powerup_active is equal to false.
Now we’re going to attach some actions to this condition:
“Assign Variable” - Set powerup_active to true as a power up is now active.
“Assign Variable” - Set the move_speed to twice the default_move_speed, so the player moves twice as fast.
“Set Animation Speed” - Double the animation speed too as the player is now moving faster
“Set Alarm Countdown” - Tell Alarm 1 to run after a few seconds. Alarm 1 will reset the effects of the active power up.
Tip: You can resize an action by dragging it from its sides. This makes it easier to see fields that are too long.
Since we’re setting Alarm 1 to 300, it means our speed effect will last for 5 seconds.
We also need to destroy the speed power up instance, so let’s do the following:
In the same chain of actions, add the “Destroy Instance” and “Do Effect” actions.
Apply them both to the “Other” instance, which in this case is the speed power up.
Use the following settings for the particle effect:
Picking up the speed power up will tell Alarm 1 to run after 300 steps. That event should then disable the power up, so let’s implement that:
Add the Alarm 1 event to obj_player.
Use the “Assign Variable” action to reset the powerup_active variable to false.
Use another “Assign Variable” action to reset the move_speed back to the default_move_speed.
Then reset the animation speed to 1.
This will now handle disabling the power up a few seconds after it has been collected.
You can now run the game, collect the power up and run around faster than ever before!
The power up works well, however we can make it better by adding a “trailing frame” behind the player.
While the speed power up is active, we’ll draw a transparent image of the player one frame behind it so it looks like the player is going fast.
We’ll use the Draw event for this, which allows us to draw something over the instance. Let’s begin by adding the event:
Add the Draw event to obj_player.
Use “Draw Self” to draw the player instance.
Use “If Variable” to check if the player’s current move speed is greater than the default move speed. This means that the player is using a power up to speed itself up.
If that is true, we want to draw the player sprite with extended options so we can control its scale and alpha. Add the “Draw Sprite Transformed” action and attach it to the condition.
Use the following settings for the new actions:
For the “Sprite” and “Frame” options we’re simply passing in the sprite_index and the image_index, which store the current sprite and frame of the instance respectively.
Using these options, the player’s sprite will be drawn at its previous position, so it will appear “behind” the player.
Now run the game, collect the speed power up and you will see the trailing frame behind the player, giving a nice “boost” effect!
We’ll now add an invincibility power up that enables the player to defeat any enemy just with a single touch. This pickup will be useful as a reward for the player discovering a hidden area!
Let’s start by adding the object:
Create a new object called obj_powerup_invinc.
Assign the spr_powerup_invinc sprite to it, found in the “Items” folder under “Sprites”.
You can now go ahead and place this somewhere in the room.
The star power up will be activated in the same way as the speed power up: in a collision event. However before we do that, we need to create a new variable.
Go to obj_player and open its Create event.
Create a new variable called star_powerup_active and set it to false. This tells us whether the star power up is currently active or not.
We’ll later use this variable to immediately defeat enemies on contact.
Let’s now make the player able to collect a star power up:
In the player object, add a collision event with obj_powerup_invinc.
The contents of this event will be similar to the collision event with obj_powerup_speed.
We need a condition to make sure that a power up is not active.
In that case, we will set the powerup_active variable to true.
We’ll also set star_powerup_active to true since this enables the star power up.
This power up will make the player fast too, but not as much as the speed power up. We’ll increase the player’s move speed and animation speed by 1.5x.
We’ll also change its colour to yellow to indicate that it’s invincible.
Finally, we'll set Alarm 1 to 600 steps (10 seconds).
Here are all the new actions:
As you can see, this power up will last 10 seconds. Of course, feel free to change this to your liking!
After these actions we also need to destroy the power up itself and create a particle effect; for this, we’ll use the same actions we used for the speed power up (make sure to apply them both to “Other”). Also make sure to attach them to the condition.
We used Alarm 1 to disable the speed power up, and we’ll use the same event to disable the star power up too:
Open the Alarm 1 event in obj_player.
This event already resets the player’s speed back to normal, so we don’t need to worry about that.
Add "Assign Variable" and set the star_powerup_active variable to false, as the star power up should not be active anymore.
Add a “Set Instance Colour” action to reset the player’s colour to white.
You can now run the game, pick up a star and roam around for some seconds with a changed colour, however it doesn’t make you invincible yet. Let’s work on that!
While the star power up is active, the player should be able to defeat all enemies it touches. We’ll achieve that by creating an invisible sword instance when the player touches an enemy, which will defeat the enemy without the player seeing the sword at all!
Let’s do the following:
Go to obj_player and open its collision event with obj_enemy_parent.
At the top of the event, add a condition to check if star_powerup_active is true.
Attach an "Apply To" action to this condition and apply that to the other instance (which is the enemy).
Attach a "Create Instance" action to "Apply To", and use it to create an instance of the obj_sword_attack object at the relative position of the instance. Store its ID in a temporary variable called sword.
Make this sword invisible by setting its visible variable to false.
After that, exit the event by adding the “Exit” action. This stops the event, making sure that the rest of the actions do not run and the player doesn’t get hurt!
Place the "Exit" action below "Apply To", not inside it.
Here are the actions:
You can now run the game, pick up an invincibility power up and go on a rampage!
We’ll now give the player an energy shield so they can protect themselves, and add a limited “energy” meter that drains while the shield is active.
Let’s start by creating the shield object -- this will be the actual shield that will spawn on the player to protect them, not a pickup.
Under "Objects" -> "Game", create a new object called obj_energy_shield.
Assign the spr_energy_shield sprite to it, which can be found in the “Player” group under “Sprites”.
We want this shield to always move with the player. Our player moves in the Step event, so we’ll use the End Step event to move the shield after the player has moved.
Add the “End Step” event to the shield object.
In this event, add the “Jump to Point” action. This action teleports the instance to the given point.
Pass in the X and Y position of the player so that the shield moves to the player’s position.
To pass in the position of the player, use obj_player.x and obj_player.y.
This makes sure that the shield always sticks to the player, by jumping to its position every frame.
Before the player can activate its shield, it needs to have a variable to store the shield energy. The shield can only be activated if this energy level is above 0, so let’s add it:
Go to obj_player and open the Create event.
Create a new variable called shield_energy and set its value to 100 -- this is the maximum shield energy the player can have.
We’ll now make the player able to activate the shield by pressing the Shift key. Here’s how we’ll do it:
Go to obj_player and add the “Key Pressed - Shift” event. This event will run when the Shift key is hit (not held).
Use a condition to check if the shield energy is greater than 0.
This is done by adding the "If Variable" action, using shield_energy as the "Variable", "Greater" as "Is" and 0 as the "Value".
If it is, create an instance of the shield at the player’s position.
This is done by attaching the "Create Instance" action to the condition and using obj_energy_shield as the object.
Make sure to create it at the player's relative position, as shown in the image below.
This will now create a shield instance whenever the Shift key is hit!
When the Shift key is released, the shield should be destroyed. We’ll do the following to make that work:
Add the “Key Up - Shift” event in the player object. This event runs when the Shift key is released.
Here we’ll destroy the shield instance, however we will first make sure that it exists in the room, as later we'll make it so it can be destroyed when the player runs out of energy.
Add the “If Instance Exists” action and check if the obj_energy_shield object has any instances in the room.
This is a condition, so you can attach instances to it. Add a “Destroy Instance” action and attach that to the condition.
Apply this action to obj_energy_shield so the shield is destroyed. If you don't do this, the player instance will be destroyed instead!
Here is what your event should look like:
You can now run the game, press Shift and the shield will appear. It also moves with the player so they're protected at all times; then release Shift and the shield will disappear!
We’ve got a basic shield system working, however it can’t block enemy attacks yet. Let’s work on that!
While the player’s shield is up, all enemy attacks should be ignored. Here’s how we’ll do that:
Open obj_player’s collision event with obj_enemy_parent.
At the top, add "If Instance Exists" to check if a shield exists in the room. This means that the player’s shield is active.
If the condition is true, use "Exit" to exit the event.
Now, when an enemy collides with the player, it will check if a shield exists in the room, and in that case it will exit the collision event. This means the player will not be hurt.
You can now run the game, activate the shield, go near an enemy and see that it won’t hurt you at all!
Now this does make the player a little too powerful, as you’re able to attack enemies while holding the shield up. This shouldn’t be allowed, so we’ll disable the player’s sword while the shield is up.
Let’s do the following:
Open the “Key Press - Space” event in obj_player. This is the event that creates the sword.
At the top of the event, add “If Instance Exists” to check if the shield exists.
If it does, exit the event.
This will now stop the event if the shield is being used, preventing the player from attacking.
So we have added a mechanic (shield) that blocks two other mechanics:
Enemies attacking the player
The player using the sword
Drawing the Energy Meter
We have a shield_energy variable in the player that stores the player's shield energy (up to 100). Let's draw this as part of the game's HUD so the player can see how much energy they have left!
Go to obj_manager and open the Draw GUI event. This is where we draw the player hearts, so we’ll use it to draw the energy meter as well.
Add the “Draw Healthbar” action to this event. As the name suggests, it’s used for drawing a “health” bar, but it can be used to display any value as a meter.
Make sure this action is attached to the existing condition in the event.
Attach a "Draw Sprite" action into the same chain, and use it to draw spr_hud_shield.
Use the following settings for drawing the energy meter:
The “Left” and “Top” properties define the top-left corner of the bar (the point where it starts), and the “Right” and “Bottom” properties define its bottom-right corner (where it ends). You can modify these values to move the bar.
The “Min Colour” is the bar’s colour when it’s empty, and the “Max Colour” is its colour when it’s full. The colour is then mixed based on the bar’s value - for example, at 50% energy the bar’s colour will be a mix of both colours.
You can now run the game and see the bar on the HUD!
The player’s shield energy should deplete while the shield is being used, so let’s implement that:
Open obj_player and add the Step event.
Here, add "If Instance Exists" to again check if the shield exists.
If it does, reduce the shield_energy variable by 0.4 (by adding -0.4 to it). This is how much energy the shield uses up every frame.
Inside the same chain, add a condition to check if the shield_energy is Less or Equal to 0.
In that case, destroy the shield instance. Make sure to apply the “Destroy Instance” action to obj_energy_shield.
Your event should look like this:
The energy will now go down while the shield is out, and once it runs out, the shield will be destroyed. Try it out!
The energy should recharge after it has run out. We’ll do this in the same event (Step):
Add an “Else” block and place it below the “If Instance Exists” action (at the root of the event).
This "Else" will run when the shield does not exist.
Attach an “If Variable” condition to the “Else” action. Use this to check if the shield_energy is less than 100 (meaning it's not full).
If that condition is true, increase shield_energy by 0.1.
Basically, when the shield is not activated and the energy meter is unfilled, it will fill up by 0.1 every frame until it reaches 100.
Try it out: see how the shield automatically disappears when you run out of energy, and how it starts filling again automatically!
You can also modify the depletion and recharge values of the shield energy in this event, customising the difficulty of your own game!
Our player is now more powerful than ever, with collectible power ups that give them an edge over all enemies and an energy shield that can be used for strategic combat.
In the next part, we’ll finish up our game and work on game essentials such as music, sound effects, pausing and a help window.