Want more GameMaker AI Pathfinding content? Explore GameMaker Academy where you can find a comprehensive, project-based learning pathway on it!
Chart a course for success with our expert GameMaker pathfinding tutorial!
In this tutorial, we will guide you through the essential steps to set up both the player and enemy in GameMaker – with the ability for both to automatically pathfind their way through your room. By the end, you will have a functional framework with defined rooms, organized sprites and objects, and foundational pathfinding mechanics for both characters and obstacles. This setup will serve as the base for building more advanced gameplay features in a variety of genres!
To make the most out of this tutorial, you should have a basic understanding of:
- GameMaker’s interface and workflow
- Setting up sprites and objects
- Game design basics such as rooms, layers, and collisions
Additionally, you can review our full course, Build a Real-Time Strategy Mini-Game with GameMaker which covers these concepts in-depth.
Let’s get started with our GameMaker pathfinding tutorial!
Project Files
To assist you, we have included the sprites, objects, and other assets used in this tutorial. Download them with the following link to follow along seamlessly: GameMaker Pathfinding Tutorial Assets
Player And Enemy Setup
To start our GameMaker pathfinding tutorial, we will be setting up both the player and the enemy in GameMaker. To achieve this, we will create two main rooms: the menu room and the game room. Let’s get started!
Creating the Menu and Game Rooms
Currently, we only have one room. Let’s rename it and create a duplicate for our game room.
- Right-click on the existing room and select ‘Rename’. Name it ‘rm_menu’.
- Right-click on the room again and select ‘Duplicate’. Name the duplicate ‘rm_game’.
Note the home icon next to the room name. This icon determines the main room that runs when the game starts. Since most games start with a menu, we’ll keep ‘rm_menu’ as the main room.
Organizing Sprites and Objects
To set up the player and enemy, we need to create sprites and objects. Let’s organize them into groups for better management.
- In the ‘Sprites’ folder, right-click and create a new group called ‘units’.
- Inside the ‘units’ group, create two sprites: ‘spr_player’ and ‘spr_enemy’.
- Repeat the process in the ‘Objects’ folder, creating a ‘units’ group with two objects: ‘obj_player’ and ‘obj_enemy’.
Now, load the corresponding sprites into their respective objects and import the appropriate images for each sprite.
Modifying Sprite Anchors
By default, sprite anchors are set to the top-left corner. For better positioning and easier calculations, we’ll change the anchors to the center.
- Select each sprite (spr_player and spr_enemy) and modify their anchors to the middle center.
This change will make more sense when we implement the enemy AI pathfinding system.
Adding Instances to the Game Room
Now that our objects are set up, let’s add instances of the player and enemy to the game room.
- Ensure you are in the ‘rm_game’ room.
- Go to the ‘Instances’ layer and drag and drop the ‘obj_player’ and ‘obj_enemy’ objects onto the room.
- If you don’t see the objects, make sure the ‘Instances’ layer is above the ‘Tiles’ layer. GameMaker renders layers from bottom to top.
You can add multiple players and enemies to the room for testing purposes.
Congratulations! You have successfully set up the basic structure for the player and enemy in GameMaker.
Manager Object
In this next step for our GameMaker pathfinding tutorial, we’re going to be covering how to create the manager object and also the init script. Let’s start by understanding what the manager object is.
What is the Manager Object?
The manager object is essentially an empty object in terms of sprite, collision, etc. It is an object that you can see in the scene and move around. However, its primary purpose is to store some variables and information that will be used inside the game. These variables are global variables, meaning they can be accessed by any object in the game, such as the player, enemy, or any other object.
Technically, you could avoid using a manager object and just declare these global variables in the player or enemy objects. However, it is much better to keep things organized by using a manager object.
Creating the Manager Object
Let’s start by creating the manager object:
- Right-click on the objects folder.
- Select “Create” and then “Object”.
- Name the object
obj_manager
.
Declaring Global Variables
To declare these global variables, we will use the Create event, which is called as soon as the game starts. Here’s how you can do it:
// Enable GML code global.framerate = game_get_speed(gamespeed_fps); global.units_margin = 20; global.game_over = false; global.viewport_width = view_wport[0]; global.viewport_height = view_hport[0]; global.path = noone; global.grid = mp_grid_create(0, 0, room_width / 16, room_height / 16, 16, 16);
Let’s break down what each of these variables does:
global.framerate
: This variable stores the current frame rate of the game. It will be useful for calling different alarms in the game and ensuring that every alarm is called at the exact same rate, regardless of the current frame rate.global.units_margin
: This variable sets a margin between units. It is used to ensure that when moving an enemy towards a player, there is some space between them, making the movement look better.global.game_over
: This variable determines if the game is over or not.global.viewport_width
andglobal.viewport_height
: These variables store the width and height of the viewport, respectively.global.path
: This variable initializes the path for pathfinding. Initially, it is set tonoone
, meaning it is empty.global.grid
: This variable creates a grid for the pathfinding system. The grid is initialized at the top-left corner of the room and covers the entire room. It is divided into cells of 16×16 pixels, matching the size of the tileset.
Adding the Manager Object to the Scene
To ensure that the manager object has access to all game-related information, you need to add it to the instances layer:
- Select the instances layer.
- Drag and drop the
obj_manager
object onto the layer.
Improving the System with Scripts
While the current setup works well, there is a small improvement that can be made by using scripts instead of just an object. For now, you have successfully created the manager object and initialized the necessary global variables.
Want to create games that stand out from the crowd? Our GameMaker Academy learning pathway provides in-depth video tutorials, hands-on projects to help you build a portfolio of innovative games, and expert guidance to aim you towards success.
Init Script
Next for our GameMaker pathfinding tutorial, we are going to be taking a look at scripts in GameMaker. Even though our current code is quite good and functional, we can make it even better by using scripts. Let’s start by creating a script to initialize our global variables more effectively.
Creating a Script
To create a script in GameMaker, follow these steps:
- Navigate to the scripts folder.
- Right-click and select “Create Script.”
- Name the script
scr_init
.
The main difference between a script and an object is that scripts are loaded before the actual rooms and objects are created. This means scripts do not have access to certain elements like the viewport until the game is fully initialized.
Initializing Global Variables
Let’s initialize our global variables in the script. We’ll start by setting up the script to initialize the variables that do not depend on the game’s elements being fully loaded.
global.framerate = game_get_speed(gamespeed_fps); global.units_margin = 20; global.game_over = false; global.viewport_width = 0; global.viewport_height = 0;
In this script, we initialize the global framerate, units margin, game over flag, and viewport dimensions. The viewport dimensions are set to 0 initially because the viewport isn’t created yet when the script runs.
Assigning Values in the Manager Object
Next, we need to assign values to the variables that depend on the game’s elements being fully loaded. We’ll do this in the manager object’s create event.
global.viewport_width = view_wport[0]; global.viewport_height = view_hport[0];
Here, we assign the actual viewport width and height to the global variables once the game is fully initialized.
Conclusion
To summarize, you should initialize your variables in the script and then assign values to those variables in the manager object if the assignment depends on elements that only exist once the game is fully loaded. This approach ensures that your variables are properly initialized and avoids errors related to accessing uninitialized variables.
Wall
In this next part of our GameMaker pathfinding tutorial, we will create the walls for our game using the Godot game engine. The purpose of these walls is to define boundaries that both the player and enemy units cannot cross. By the end of this section, you will have a clear understanding of how to set up these barriers within your game environment.
Understanding Wall Functionality
Walls serve as obstacles that units cannot pass through. For instance, if an enemy is chasing the player, the enemy should detect the wall and navigate around it. Similarly, the player should not be able to move outside the defined game area.
Creating the Wall Sprite and Object
To create the walls, we need to set up both a sprite and an object. Here’s how you can do it:
- Right-click and select Create Sprite. Name it spr_wall.
- Right-click again and select Create Object. Name it obj_wall.
- Drag and drop the spr_wall sprite onto the obj_wall object.
Why Create Both a Sprite and an Object?
You might be wondering why we need both a sprite and an object if the walls are not visible to the player. The reason is that the walls serve as collision detectors rather than visual elements. By creating an empty object with no visible sprite, we ensure that the walls do not appear in the game but still function as barriers.
Adjusting the Sprite Size
To make it easier to position the walls, we need to adjust the size of the sprite to match our tile size. Follow these steps:
- Go to the spr_wall sprite and select the Resize Sprite option.
- Scale the image to 16×16 pixels to match the tile size.
- Click Apply to save the changes.
Positioning the Walls
Now that the sprite size is adjusted, we can position the walls within the game environment. Here’s how:
- Create a new instance layer and name it walls.
- Drag and drop the obj_wall into the walls layer.
- Use the grid (set to 16×16) to position the walls accurately.
- Hold down the Alt key while clicking to instantiate multiple walls quickly.
Ensuring Invisibility
To ensure that the walls are not visible to the player, make sure the sprite has no color or drawing. If you accidentally add color, you can use the eraser tool to remove it.
Finalizing the Walls
Once you have positioned all the walls, your game environment should have defined boundaries that units cannot cross. This setup will be crucial for implementing enemy AI and pathfinding systems.
Ready to turn your GameMaker ideas into reality? Our GameMaker Academy learning pathway offers in-depth video tutorials to help you master the platform, hands-on projects to build a portfolio of games, and written summaries to solidify your understanding of game development principles.
Enemy Pathfinding – Part 1
Moving on in our GameMaker pathfinding tutorial, we will set up the basic structure for our units and implement the initial pathfinding functionality.
Creating the Unit Parent Object
First, we need to create a parent object for our units. This parent object will contain shared properties and behaviors that both the player and enemy units will inherit.
- Inside the units folder, create a new object called
obj_unit_parent
. - Open the parent menu and add both the enemy and player objects as children of
obj_unit_parent
.
Defining Variables
Next, we will define some variables in the obj_unit_parent
object.
- Add a new boolean variable called
is_player
and set it tofalse
by default. - In the player object, set
is_player
totrue
. - In the enemy object,
is_player
will remainfalse
.
Setting Up the Create Event
Now, let’s set up the create event for our units.
velocity = 1; target_enemy = noone;
Here, we are defining the velocity of the units and initializing the target_enemy
variable to noone
.
Adjusting the Enemy’s Velocity
We want the enemy to move slower than the player. To do this, we will override the create event in the enemy object.
event_inherited(); velocity = 0.5;
This code first inherits the create event from the parent object and then sets the velocity to 0.5 for the enemy.
Creating the moveWithPath Function
Now, let’s create a function called moveWithPath
that will handle the pathfinding for our units.
function moveWithPath(_object_x, _object_y, _target_x, _target_y, _speed) { // Add the wall to the grid mp_grid_add_instances(global.grid, obj_wall, false); // Create path global.path = path_add(); mp_grid_path(global.grid, global.path, _object_x, _object_y, _target_x, _target_y, true); path_start(global.path, _speed, path_action_stop, true); } }
This function takes the object’s position, the target position, and the speed as arguments. It adds the wall to the grid, creates a path, and starts the path.
Enemy Pathfinding – Part 2
With some basics covered, let’s hone in further on enemy pathfinding for our GameMaker pathfinding tutorial. Our goal now is to ensure that the enemy always maintains some space between itself and the player. This will prevent the enemy from matching the player’s position exactly, which can lead to undesirable behavior.
Maintaining Distance Between Enemy and Player
To achieve this, we will implement a check to ensure that the enemy keeps a minimum distance of 20 units from the player. This value is stored in a variable in the script. Here’s how we can do it:
- Check if the current object is not the enemy (i.e., it is the player).
- Call a method named
point_distance
to calculate the distance between the enemy and the player. - If the distance is smaller than or equal to the unit’s margin (20 units), end the path to stop the enemy from moving closer.
if (!is_player) { if (point_distance(_object_x, _object_y, _target_x, _target_y) <= global.units_margin) { path_end(); } }
Updating the Enemy Path
Next, we need to ensure that the enemy’s path is continuously updated. This is crucial because the player will be able to move, and the enemy needs to adjust its path accordingly. We will use an alarm to update the path at regular intervals.
- Set an alarm to update the enemy’s path every 0.3 seconds initially and then every 0.5 seconds.
// Update enemy path if (!is_player) alarm[2] = global.framerate*.3;
- In the alarm event, check if the game is over. If it is, return to avoid further updates.
- Find the nearest player using
instance_nearest
. - Move the enemy towards the nearest player using
move_with_path
. - Set the alarm to trigger again after 0.5 seconds.
// Alarm[2] event if (global.game_over) return; var _nearest_player = instance_nearest(x, y, obj_player); move_with_path(x, y, _nearest_player.x, _nearest_player.y, velocity); alarm[2] = global.framerate * 0.5;
Testing the Implementation
To test our implementation, we need to ensure that the game starts with the correct room. Since we don’t have a main menu with a play button yet, we will temporarily set the game room as the first room to be played.
- Change the first room to be played to the game room instead of the menu room.
- Run the game and observe the enemies moving towards the player while maintaining the specified margin.
By following these steps, you will ensure that the enemies move towards the player while maintaining a safe distance. This will make the gameplay more dynamic and challenging.
GameMaker Pathfinding Wrap-Up
And that wraps up this GameMaker pathfinding tutorial! You’ve successfully learned how to set up rooms, sprites, objects, and basic game elements in GameMaker. With the player and enemy framework in place, you are now ready to dive deeper into coding behaviors – implementing pathfinding and adding dynamic interactions to your game.
Feel free to experiment further by customizing the sprites, adjusting player/enemy speeds, or adding unique features to the rooms. These small tweaks can personalize your project and make it more engaging.
If you’re eager to learn more, Zenva offers a variety of courses covering topics like game mechanics, AI systems, and advanced GameMaker techniques through the GameMaker Academy. Whether you’re a hobbyist or aspiring professional, there’s always more to explore in the world of game development!
We hope this tutorial has been helpful, and we can’t wait to see what amazing games you create. Best of luck, and happy coding!
Get industry-ready with the GameMaker Academy! Perfectly suited to any skill level, you’ll get the tools you need to succeed while building a slew of projects!
Did you come across any errors in this tutorial? Please let us know by completing this form and we’ll look into it! FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.