Welcome to Part 2 of the Hero's Trail tutorials!
This tutorial expands on the Hero's Trail project provided with GameMaker Studio 2. We’ll add coins, a sword attack to the player object, and the ability to defeat enemies!
This tutorial has the following sections:
We're going to add coins to Hero's Trail: you will be able to place coins in the level and pick them up in-game!
How Will This Work?
We'll create an object for the coin, which we can place in a level as many times as we want.
We'll program collisions between the player and the coin, so when the player touches a coin, the coin disappears.
We'll increase the existing coins counter in the player so we can see how many coins the player collected.
Let's make the coin object!
We'll start by adding a new Object asset:
Open the “Objects” group in your Asset Browser and select the “Game” group within it.
Click on the “Create Asset” button at the top and double-click on “Object”.
(Alternatively, you can click on "Objects" once and then click on “Create”.)
This will create a new Object asset inside your selected group, and open its Object Editor window in your workspace.
Change its name to obj_coin:
The project already contains a coin sprite that we can use for this object. (If you want to import your own, go ahead!)
In the Object window, click on “No Sprite” to open the Asset Explorer; navigate into “Sprites”, then “Items” and select spr_coin.
Our coin object is ready! You can now open the first room (rm_level_1) and start placing coins.
First of all, make sure that the “Instances” layer is selected:
Now you can drag coins from the Asset Browser into the room! You can also hold Alt and place instances simply by clicking and holding (make sure that obj_coin is selected).
We want the player to collect a coin on touching it. To make this work, we’ll make use of Events and Actions.
Events are placed inside Objects. GameMaker decides when a certain event runs (once, or every frame, or when a key is pressed, etc.)
Actions are placed inside Events. Each action has a unique purpose and effect.
You can add multiple actions inside an event, and when GameMaker runs that event, all actions inside it are executed. This is how you program your objects!
But what are Events and Actions?!
Let's say you have a recipe for pancakes, with all the steps in a list...
- Whisk ingredients
- Heat a pan
- Pour batter
In this case, your recipe is the event and these steps are the actions.
When you start following a recipe, you have to follow all steps inside it; only then the recipe is considered finished.
Similarly, when an event runs, all of the actions inside it are executed.
That is basically how you program an object in GameMaker -- you create a bunch of recipes with steps to control what your object does!
Let's program our coin!
We’ll do the following to program our coins to be collectable:
Open obj_coin. If the Events window is closed, click on the “Events” button to open it:
Click on “Add Event”. This will open a list with all events (recipes) that you can add into your object.
Go under “Collision”. This opens an asset list and lets you select an object to “collide” with.
Navigate to “Objects”, then “Game” and here, select obj_player.
Doing this will add the event to your object and open it in a new window. This is where you can start creating your recipe, to tell GameMaker what should happen when the player collides with a coin.
The new event window will mostly be empty, except for the panel on the right: the Toolbox.
The Toolbox will be your most important tool for programming objects. It contains all the actions that you can use, and allows you to search through them using the “Search...” field at the top.
Going back to the pancake analogy, the Toolbox contains all the possible steps that your recipe can contain -- whisk, pour, heat, etc. -- and they can be placed into your recipe to control exactly what happens when the recipe is run, and in what order!
We are inside a collision event with the obj_player object. This means that the event will run when the coin touches a player, and all actions inside it will run too.
When the coin collides with a player, we want the coin to be removed from the room. We’ll do the following to achieve that:
In the Toolbox, search for the “Destroy Instance” action. Drag and drop that action into the event.
Search for the “Do Effect” action and drag it into the event as well.
The first action will destroy the coin instance, removing it from the room. The second action will create a particle effect for some eye candy.
For the “Do Effect” action, use the same settings shown in the following image:
Make sure to enable the "Relative" checkboxes for X and Y, as that makes sure that the effect appears at the coin's position.
You can select the “Do Effect” action and press F1, which will take you to its manual page. There you can read more information about its options in detail!
Run the game, and you will see that the player is now able to collect coins!
Although you can now collect coins, you will notice that the coin counter at the top does not change. This is because we are not actually changing the player’s coins variable.
What's a Variable?
Let's go back to the pancake recipe.
At the top of the recipe page, let's say you have written:
Bananas = 1
Throughout the recipe you will now remember how many bananas you have to add, just by reading that text!
If you are feeling more hungry for bananas today because you watched a documentary on cute monkeys, you can increase that count...
Bananas = 3
…and you now have more bananas in your recipe!
In this case, 'Bananas' is a variable.
It essentially stores a value and can be changed. We can easily create and modify variables like these in our code, so we know exactly how much we have of something!
The 'coins' variable
Our player object already contains a variable called coins, which stores the amount of coins it has. We simply need to increase this value when a coin is collected.
We previously added a collision event in obj_coin, so it could collide with obj_player. Now, we’ll add a collision event in obj_player, so it can collide with obj_coin and increase its coins value.
Open obj_player. In its “Events” window, add a collision event with obj_coin.
In this event, add the “Assign Variable” action. This action is used to change the value of a variable.
(Refer to this section for instructions on adding actions from the Toolbox.)
Use the following settings for the “Assign Variable” action:
Here, we’re assigning 1 to the coins variable. However, this will not simply set the variable to 1, because we’ve enabled the “Relative” option. This means that the value of “coins” will increase by 1, hence adding one coin!
Run the game now, and you will notice that the coin counter actually goes up when you collect a coin!
Our game now has coins that can be placed anywhere and collected by the player to increase their score!
The player can't attack at all, so we'll make it able to swing a sword so it can defeat any enemies in the way!
How Will This Work?
We'll create a new object that will show a sword slashing animation.
Whenever the player presses Space, this sword object will be displayed.
Finally, when an enemy touches this sword object, it will be defeated.
The project contains a sprite called spr_sword_attack. This is what will be displayed over the player when the Space key is pressed, creating an attack:
Let’s start by creating an object for this.
Open the “Objects” group, then select the "Game" group and create a new Object asset. Name this obj_sword_attack.
Set its sprite to spr_sword_attack. You can find this sprite in the “Sprites” group under "Player".
You can drag it from the Asset Browser and drop it into the Sprite section of the Object:
Refer to this section for instructions on creating objects.
Instances, by default, exist permanently in a room until they are manually destroyed. For example, if you place a coin in the first level, it will remain there until the player touches it.
This sword object will be created by the player, but we don’t want it to keep existing. We want it to destroy itself when its animation ends. This ensures that after pressing space once, the sword also only appears once.
We’ll do the following to implement this behaviour:
In the new obj_sword_attack object, click on “Add Event”, go under “Other” and select “Animation End”.
This event runs when the instance’s animation has ended. When this happens, we want it to destroy itself.
Search for “Destroy Instance” in the Toolbox and drag it into the event.
Our sword object is now ready: if it’s created by another object, its animation will only play once and then destroy itself.
Let’s now allow the player to swing this sword when they press Space. We’ll do the following to achieve this:
Tip: You can press CTRL + T (or CMD + T on macOS) to open the “Go To” menu. This allows you to write the name of an asset and quickly jump to it!
Go into obj_player.
Click on “Add Event”, go under “Key Pressed” and select “Space”.
This event will run when the Space key is pressed. Holding the key will not do anything - to press it a second time, it has to be released and then hit again.
Add the “Create Instance” action from the Toolbox. This action is used to create a new instance of an object.
Then, add the “Assign Variable” action. We’ll use this to change the horizontal scale of the sword (to make it face left or right based on the player).
Use the following settings for both actions:
Each instance has an ID, which can be used to access it and modify its properties. In the “Create Instance” action, we have the “Target” field which holds the variable name that will store the ID. Since we’ve enabled “Temp”, this variable will be temporary.
Temporary variables only exist for the current event. After the event ends, a temporary variable is removed from memory.
The X scale of an instance controls its horizontal size, and it’s stored in the image_xscale variable. This variable is used by the player to flip its horizontal sprite, so that it looks left or right depending on the input:
|image_xscale = -1 (Flipped)||image_xscale = 1 (Default)|
This same scale will also be applied to the sword, so it faces left or right depending on where the player is facing. To achieve this, we’re using the “Assign Variable” action to set sword.image_xscale equal to image_xscale.
This is the sword’s X scale. Its image_xscale variable is accessed using a dot (".") through the sword variable, which stores the instance ID.
This is the player’s own X scale.
Run the game and you will now be able to swing the sword horizontally!
Making the sword swing in all 4 directions is covered in Part 5 as it's a longer process.
We’ll now let the player defeat enemies by hitting them with the sword. Let’s do the following:
In the Asset Browser, go into “Objects”, then “Game” and open “Enemies”.
This group contains an object called obj_enemy_parent. This is a “parent” object for all enemies (currently it has only one "child": obj_baddie). Any events added to this object will automatically be applied to all enemies.
Open obj_enemy_parent and add a collision event with obj_sword_attack. This will run when the enemy touches the player’s sword.
In this event, add a “Destroy Instance” action and a “Do Effect” action. These are the same actions we used in obj_coin to destroy it on colliding with the player!
Since we have used these actions recently, you should be able to find them in the "Recently Used" section of the Toolbox, so you don't have to search for them again.
Use the following settings for these actions:
When an enemy comes in contact with the sword, it will now destroy itself and create a particle effect. Even though we have not added this event into obj_baddie, it will still apply to it because it’s a child of obj_enemy_parent:
Run the game and you will now be able to defeat enemies by swinging your sword! Now we have some real power!
We’ve now developed the Hero’s Trail project further, by adding a coins functionality and allowing the player to attack baddies. Here is a summary of what we've learned:
- Events contain actions, similar to how recipes contain steps
- Objects can collide with each other using collision events
- Variables store values and can be increased/decreased using the "Relative" option in "Assign Variable"
- Pretty particle effects can be created using the "Do Effect" action
- Instances can be flipped using the image_xscale variable
We’re not stopping here -- in the next part, we’ll work on interactive level design by adding chests, gates and more!