Trending
Opinion: How will Project 2025 impact game developers?
The Heritage Foundation's manifesto for the possible next administration could do great harm to many, including large portions of the game development community.
Featured Blog | This community-written post highlights the best of what the game industry has to offer. Read more like it on the Game Developer Blogs or learn how to Submit Your Own Blog Post
During the development of Kerfuffle I needed an animation system that would afford me much more control over animation timing, and triggering actions on specific frames. This system can be hugely beneficial to ALL GameMaker developers.
When developing Kerfuffle I needed an animation system that would allow me to hold any individual frame of animation for as long as I wanted in game, without having to manually add or remove frames to the sprite. I also needed to be able to trigger certain actions based on the current animation frame. Using this setup I was able to create hitboxes, play sounds, or change states, all while having full control over everything being drawn on the screen.
These are the important variables associated with the animation system. Refer back to this if you get confused.
frameSpeed
The speed in FPS that the game counts through the frames to be displayed. Default is 1.
frameCounter
Increases every frame by the frameSpeed.
currentFrame
The frame of the sprite currently being drawn on the screen.
frameData
Current list of frame data the game is reading from, based on the animation that needs to play. Idle, run, attack, etc.
frameDuration
Total number of in game frames to display the current sprite frame.
maxFrames
The total number of frames in any given sprite.
animSprite
The actual name of the sprite resource in GameMaker. sprMomo_Idle, for example.
A couple of useful scripts that save us some typing later.
frame_reset();
Resets frameCounter and currentFrame to 0.
frameCounter = 0; currentFrame = 0;
animation_set();
This script accepts two arguments. First, the frameData (which is the relevant list of frame data) and second is the animSprite (the sprite resource you want to draw).
//animation_set ( argument0, argument1 ); frameData = argument0; animSprite = argument1;
Each animation requires a list of frame data. This is a list that contains the amount of in game frames that each frame of animation will be played. Each list of data uses the following naming convention. frameDataIdle, frameDataRun, frameDataDash, and so on. Also, if anyone knows how to use a table in tumblr… please tell me how.
Frame data for Momo’s idle animation
Animation Frame | # Of Frames to be Displayed |
---|---|
00 | 5 |
01 | 9 |
02 | 3 |
03 | 3 |
04 | 3 |
05 | 3 |
06 | 5 |
07 | 9 |
08 | 3 |
09 | 3 |
10 | 3 |
11 | 3 |
Be aware that all lists, and values, start with 0. So even though this animation has 12 frames, the highest number in the list is 11. This includes frames you want to display! If you want it to show up for 5 frames in game, the value in the list should be 4.
**GameMaker Specific Note**
Make sure you manually delete a list when you are no longer using it! Otherwise you can run into memory leaks!
Now that we have a list of frame data, we need to actually animate based on that data. The first thing we need to do is figure out what the maxFrames are.
maxFrames = sprite_get_number( animSprite ) - 1;
Then, if your currentFrame happens to be greater than or equal to max frames, AND frameCounter is greater than or equal to the maximum number of frames the sprite frame should appear on screen, reset to the first frame.
if ( currentFrame >= maxFrames - 1 && frameCounter == frameDuration ) { frame_reset(); }
Now the frameCounter can do its job. It counts up to the number of frames the current frame of the sprite should be displayed, then once it reaches that maximum, ticks the currentFrame up to the next frame of of the sprite, and resets back to 0 to start counting again.
frameCounter += frameSpeed; frameDuration = ds_list_find_value ( frameData, currentFrame ); if ( frameCounter == frameDuration ) { currentFrame ++; frameCounter = 0; }
Side Note:
Using maxFrames is also a good way to end animations, and change to a new animation or state! I use maxFrames to switch from an attack state back to the normal state after the entire attack animation has played all the way through.
**GameMaker Specific Note**
Sprite_get_number is a built in GameMaker function that returns the number of frames in a sprite. This function returns the exact number of frames, and does not count up from 0! So if you have a sprite with 5 frames, this will return 5! This is why when checking against maxFrames, we do so while subtracting 1 from its value.
Everything in Kerfuffle runs on a fairly simple state machine. Depending on the state the character is in, the animation changes.
//store the current animation sprite so we can check it later currentAnim = animSprite; switch ( state ) { case normal: //if the player is pushing left, or right, change to run sprite if ( left || right ) { animation_set ( frameDataRun, runSprite ); //if the player isn’t pushing any buttons, change to idle sprite } else { animation_set ( frameDataIdle, idleSprite ); } break; case dash: //if the player is in the dash state, change to the dash sprite animation_set ( frameDataDash, dashSprite ); break; } //check the current animation against the last animation. //If these animations are NOT the same, reset frameCounter and currentFrame to 0. if(lastAnim != currentAnim) { frame_reset(); lastAnim = currentAnim; }
**GameMaker Specific Note**
Use macros or enums instead of strings where possible. I used to use strings for player states (ie: “normal” instead of just normal) and it’s not the best idea. Strings are slower to process, and if you make a typo, GameMaker will not alert you! Your code will just fail and it is much easier to overlook!
For more info on Macros check out this write up by YellowAfterLife.
https://yal.cc/gamemaker-on-global-variables/
Now that all of this has been setup, we just need to put it to use. Since we are bypassing GameMakers built in functions like image_speed and sprite_index, we need to draw the sprites ourselves. This is really easy though! We just need to use draw_sprite_ext!
//draw event draw_sprite_ext ( animSprite, currentFrame, x, y, 1, 1, 0, c_white, 1 );
For more info on exactly what draw_sprite_ext does check out the GameMaker documentation. There are a lot of great things you can do with this! In my opinion its one of the most important parts of GameMaker that you should learn!
https://docs.yoyogames.com/source/dadiospice/002_reference/drawing/drawing%20sprites%20and%20backgrounds/draw_sprite_ext.html
So thats it! Pretty easy right? If you have any questions, or comments on how to improve this, please let me know. I will respond as soon as I am able. If there are any other write-ups like this that you’d like to see, let me know what they are!
Follow me on Twitter!
Check out my games on Itch.io!
Later, Nerds
Read more about:
Featured BlogsYou May Also Like