If you find this tutorial helpful, please consider showing support by trying my latest game
Insane Number Run
***
In the case of being too ADD, you can download the completed project for this lesson here:
[Windows]
Part 3 Editable Project Download
[Mac]
Part 3 Editable Project Download (Slightly outdated)
If you have not already done so, I highly suggest going through parts 1 and 2 of this series first, as this lesson will be based upon their existing code.
Part 1: The Basics
Part 2: Collision Detection
Welcome to part 3 of my series on Grid Based Movement for Game Maker!
In this lesson, we are going to look at implementing character animation for our player object. There are a few ways to go about doing this with Game Maker, but today I will teach one of the techniques which I prefer and continue to use myself.
The result of this lesson should look like this: Grid Animation Example
Alright, onto the Lesson!
First, lets get ourselves some sprite strips to work with. Go ahead and download the following files to use for our lesson. You can use your own if you like, but note that you will likely need to make minor adjustments to the example code if you do so.
Sprite Strip 1
Sprite Strip 2
(Big thanks to Cody Penner for the sprites! )
For this lesson, we are going to continue where we left off from Part 2: Collision Detection. You can download the completed editable project for that lesson here: Part 2 Project Download
With our existing project from Part 2, add the new sprite strips to the Sprites folder.
The first 4 images of the sprite strip are for the standing “animations”, one for each direction. Following them are the walking frames for all 4 directions containing 4 images for each animation.
Noting the placement, order and length of our images/animations within the sprite strip is important. We will be using this information to properly set up our animations for our player object. Be aware that the numerical values of the images in the strip are zero-based. This means that 0 refers to the first image, 1 to the second, 2 to the third, and so on. We can explicitly change an instance’s displayed image at runtime by modifying its built in image_index variable, setting it to the appropriate offset we want, relevant to the current sprite strip. Soon, you will see how this is used to create smooth walking/standing animations for our grid based movement system.
Before doing anything else, open up the properties for obj_player and change Sprite to one of the sprites we just imported.
Within obj_player, highlight the Create Event and open the existing Execute Code action.
Below the already existing code in our action, insert the new variables we will use to support our animation system.
// ...PREVIOUS OLDER CODE
// We will now keep track of our direction
direction = 270;
// Used to help set standing animations
justStoppedMoving = true;
// Initialize animation properties
animIndex = 0; // first frame in current animation
animLength = 0; // current animation length in frames
animSpeed = 0; // current animation speed
animIndexRelative = 0; // relative from first frame of animation
// Set animation length properties
animLengthStanding = 1;
animLengthWalking = 4;
// Set animation speed properties
animSpeedStanding = 0.0;
animSpeedWalking = 0.2;
// Standing animation index offsets
animIndexStandRight = 0;
animIndexStandUp = 1;
animIndexStandLeft = 2;
animIndexStandDown = 3;
// Walking animation index offsets
animIndexWalkRight = 4;
animIndexWalkUp = 8;
animIndexWalkLeft = 12;
animIndexWalkDown = 16;
Because we want our character facing downward at the start, we will set direction
to 270
As a refresher: right = 0, up = 90, left = 180, down = 270
We have also created a new variable justStoppedMoving
which will enable us to easily manage code for when our player stops walking. This can be helpful for setting standing animations.
Following that, we have initialized some required properties to make our animation system work. animIndex, animLength, animSpeed and animIndexRelative hold the status of the active animation.
animIndex receives the value of the first frame in the animation we want to use. We can easily assign it one of the animation indexes we have created, such as animIndexWalkRight.
animLength holds the length of the current animation in frames. We will assign in the value from either animLengthStanding or animLengthWalking.
animSpeed is simply how fast our animation will animate. Make sure to keep the value relatively small. We will assign it the value held by animLengthStanding or animLengthWalking.
Finally, we initialized animIndexRelative. This variables holds the current animation’s frame value relative to its starting animIndex frame. It will allows us to repeatedly cycle through and select the appropriate frames needed for each animation.
With that set up, we are now going to set up a script so that we can comfortably change the required properties needed to set up the appropriate animations we want.
In GameMaker’s ‘Scripts’ folder, create a new script called ‘SetAnimation’
Inside this script, go ahead and input the following code:
animIndex = argument0;
animLength = argument1;
animSpeed = argument2;
This script takes 3 arguments. It will be used to change our animation Index, Length, and Speed.
With that inputted, close it up and once again open the properties for obj_player.
We are now going to add the code which will make our animation system work. But we are not going to add it to the Normal Step Event. Instead, we will add an End Step Event, and place our code inside there. By placing our animation system here, we separate it from our Normal Step Event code, ensuring the intended animations are drawn after all our other updates are finished.
Inside the End Step event, add a new action -> Execute Code. Inside this code action, place the following:
image_index = animIndex + animIndexRelative;
animIndexRelative += animSpeed;
if (animIndexRelative >= animLength)
{
image_index = animIndex;
animIndexRelative = 0;
}
With that code in place, the animation will always be within our set boundaries.
As long as we use the SetAnimation script, we can be certain that our animation system will function properly.
We are now going to return to the Normal Step event for obj_player and edit the existing code action.
We will start by adding a new line at the bottom of our existing code for when our character has just stopped moving.
Add the line of code where it is commented: // *** NEW CODE ***
//... OTHER CODE
if (isMoving == true)
{
x += speedX;
y += speedY
moveTimer -= moveSpeed;
if (moveTimer)
{
isMoving = false;
justStoppedMoving = true; // *** NEW CODE ***
}
}
We can now return to the top of the code action and utilize the justStoppedMoving
variable to set standing animations when our player finishes walking.
// Set standing animations if just stopped
if (justStoppedMoving == true)
{
justStoppedMoving = false;
// Set appropriate standing animations
if (direction == 0)
SetAnimation(animIndexStandRight, animLengthStanding, animSpeedStanding);
else
if (direction == 90)
SetAnimation(animIndexStandUp, animLengthStanding, animSpeedStanding);
else
if (direction == 180)
SetAnimation(animIndexStandLeft, animLengthStanding, animSpeedStanding);
else
if (direction == 270)
SetAnimation(animIndexStandDown, animLengthStanding, animSpeedStanding);
}
// ... Other Code
Based upon the character’s current direction, we have effectively set the appropriate standing animation. But up until this point, we haven’t written any code to change the character’s direction or set a walking animation.
Just below the code we wrote, we will modify the existing code within the keyboard_key() check statements to include an updated direction. We will also set the appropriate walking animation when our player is able to move.
Go ahead and modify our existing code to include keeping track of our current direction, as well as setting the appropriate animations. Note that this code will also set an appropriate standing animation if the player is blocked and unable to move. This allows the player to allows face the direction they intend to.
if (isMoving == false)
{
// Perform 4 direction keyboard and grid checks
// for setting appropriate movement and animation
if (keyboard_check(vk_right))
{
direction = 0; // Keep track of new direction
if (obj_grid.cells[(x div 32) + 1, y div 32] == 0)
{
isMoving = true; // Lets start moving
moveTimer = gridSize; // Ready moveTimer for countdown
speedX = moveSpeed; // Set horizontal speed
speedY = 0; // Set vertical speed
SetAnimation(animIndexWalkRight, animLengthWalking, animSpeedWalking);
}
else
{ // Set standing anim for new direction
SetAnimation(animIndexStandRight, animLengthStanding, animSpeedStanding);
}
}
else
if (keyboard_check(vk_up))
{
direction = 90;
if (obj_grid.cells[x div 32, (y div 32) - 1] == 0)
{
isMoving = true;
moveTimer = gridSize;
speedX = 0;
speedY = -moveSpeed;
SetAnimation(animIndexWalkUp, animLengthWalking, animSpeedWalking);
}
else
{
SetAnimation(animIndexStandUp, animLengthStanding, animSpeedStanding);
}
}
else
if (keyboard_check(vk_left))
{
direction = 180;
if (obj_grid.cells[(x div 32) -1, y div 32] == 0)
{
isMoving = true;
moveTimer = gridSize;
speedX = -moveSpeed;
speedY = 0;
SetAnimation(animIndexWalkLeft, animLengthWalking, animSpeedWalking);
}
else
{
SetAnimation(animIndexStandLeft, animLengthStanding, animSpeedStanding);
}
}
else
if (keyboard_check(vk_down))
{
direction = 270;
if (obj_grid.cells[x div 32, (y div 32) + 1] == 0)
{
isMoving = true;
moveTimer = gridSize;
speedX = 0;
speedY = moveSpeed;
SetAnimation(animIndexWalkDown, animLengthWalking, animSpeedWalking);
}
else
{
SetAnimation(animIndexStandDown, animLengthStanding, animSpeedStanding);
}
}
// ... OTHER CODE
}
With that code in place, we now have a functioning animation system where the character will animate according to our set parameters determined by the sprite strip.
A benefit to this animation system is that sprite strips, which share the same animation parameters, can be swapped at any time with ease! Simply change the character’s sprite_index and the change will be immediately reflected, no matter what state the character is in!
If you want to have your standing animations the same as your walking animations (think Dragon Warrior/Quest), then simply change the standing properties to be the same as the walking animation properties, and you’re good to go!
If you have any questions or suggestions, I would love to hear from you!
And if you’re on Twitter, find me at @Nehemius