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
Pingback: [Game Maker] Grid Movement -PART 1- The Basics « 8-Bit Warrior
Pingback: [Game Maker] Grid Movement -PART 2- Collision Detection « 8-Bit Warrior
i have a animated standing animation thats 3 frames long in all 4 directions the same goes for walking how can i use this?
Hey, Daniel.
I should have the tutorial modified today or tomorrow to help you with your question. Thanks for the feedback!
I just wanted to let you know that I have completely updated the tutorial. Let me know if this helps you out :)
thanks :D
hi i was just wondering what your next tutorial is and also if when your tutorials get to the battleing part if the battles will be like final fantasy or pokemon where its a battle scene seperate to the game where the attacks are turnbased 1 on 1 (or more in some cases) or if the battles will be like nethack or pokemon mystery dungeon where many foes can attack in different directions on the map where your walking about and you attack them in directions.
I haven’t planned any battle system tutorials as of yet. But, if I worked up the motivation, eventually, I’d probably do a tutorial for 1 vs 1 turn based combat and later build upon it in another tutorial to include more fighters.
But, I don’t see myself writing that any time soon :(
Again, thanks for the feedback. It is greatly appreciated.
Could you be so kind as to post a mac (.gmk) version of the file?
That would be great.
I have provided a link to a mac .gmk version at the top of the post :)
Thanks a lot!
Great tutorials by the way :D
Your tutorials are admirable, sir. Thank you so much.
I’m actually in the early stages of learning GML, with no previous skills in coding. After two months of constant research and experimentation about animation and movement, your examples and explanations are by far the best I’ve been able to find out there (sorry if my statements aren’t accurate, I’m triying to speak English as well as I could. I’m from Spain, actually not far from where you can find the bad guys of RE4 xD)(fun fact: “thanks” to RE4, spaniards noticed that the rest of the world see’s us like mexican people, with all their topics about lore, accent and such).
Back to the topic, it would be great if you managed to revisit your tutorials about movement in Game Maker, but taking the grid-based part and eight direction model in favor of an 2D sidescroller like SOTN. I’m having trouble with jump and crouch animations and your approach seems to be very adaptable to this concern.
Thank you in advance, I really appreciate your time and efforts.
Sadly, I don’t have much time, right now, to work on more tutorials :(
Hopefully, I will have more time in a couple of months.
Secondly, my experience with 2d sidescrollers is quite limited. I would prefer to finish a 2d platformer before I teach how to make one :)
Greetings! To animate my player I put this in its step/step event:
if(x < xprevious){
sprite_index = sprPlayerMoveLeft;
image_speed = 0.35;
}
three more for the other directions and then this:
if(x == xprevious && y == yprevious){
image_speed = 0;
image_index = 0;
}
seems to be working fine. Any thoughts?
Miss your great tutorials on youtube!
The code you are using should work fine much of the time. However, there are times when you might not want it that way.
For example, what if your character is teleported to a new location? In that case, the character might suddenly animate when you don’t want him to.
It really comes down to the mechanics in your game. If outside forces are affecting the movement of your player, this method might not be what you want. But, if the player is the only one in control of predictable movement at all times, I don’t see any problem with this.
In one of my games, I have grid based movement mixed with floating platforms which move the player around. In that case, your code would cause the character to look like he is walking when he isn’t.
Anyhow! Thanks for sharing. I like to see how others approach these things.
I hope to get back to doing more tutorials on youtube. I might put a small video up this week :)
Thanks for the input, very interesting. At the moment I’m trying to implement pushable blocks in the game that should only be pushed when not next to another block or a wall. So far I have only managed this by moving them the full 32 pixels at a time without grid functionality, but I would like them to move as smoothly as the player.