Download as pdf or txt
Download as pdf or txt
You are on page 1of 11

2D GAME AR T DEVELOPMENT

1
Animation

Module 8: Animation

Course Learning Outcomes:


1. Add animation to the game being developed.

Animation
So far, all the objects in the game consist of just one, single image sprite. Using
GameMaker: Studio, you can specify an object to use multiple images which will make up
the animation of that object. Make sure you are comfortable with all aspects of the first 5
tutorials before moving on to this one.

Terminologies:
Variables
These are the important variables associated with the animation system.
Refer back to this if you get confused.

1. frameSpeed - The speed in FPS that the game counts through the frames to
be displayed. Default is 1.
2. frameCounter - Increases every frame by the frameSpeed.
3. currentFrame - The frame of the sprite currently being drawn on the screen.
4. frameData - Current list of frame data the game is reading from, based on
the animation that needs to play. Idle, run, attack, etc.
5. frameDuration - Total number of in game frames to display the current
sprite frame.
6. maxFrames - The total number of frames in any given sprite.
7. animSprite - The actual name of the sprite resource in GameMaker.
sprMomo_Idle, for example.

Module 8
2D GAME AR T DEVELOPMENT
2
Animation

Animation Codings
Helper Scripts
A couple of useful scripts that save us some typing later.
1. frame_reset(); Resets frameCounter and currentFrame to 0.

frameCounter = 0;
currentFrame = 0;

2. 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;

Frame Data
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.

Table 1 : Idle Animation Table

Module 8
2D GAME AR T DEVELOPMENT
3
Animation

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.

Frame Counter
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;
}

Module 8
2D GAME AR T DEVELOPMENT
4
Animation

Switching Sprites
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;
}

Module 8
2D GAME AR T DEVELOPMENT
5
Animation

Tutorial

Figure 1: Example of Animation Frames


This shows each frame of the block exploding. This is the animation we will use for
when the ball hits the block.

Loading Frames
Select "spr_block" from the sprite resource folder, then click "Load sprite" as you
normally would and browse to the "Game Assets" folder for this tutorial (found here).
Instead of choosing one image, select each frame of the animation shown above and then
press open and GameMaker: Studio will automatically deal with the frames.

Collision masks

A collision mask is the part of the image to be treated as "collidable". For example,
you might only want a characters feet to be the collision mask in a platformer. In our game,
we only want the blocks themselves to be collidable, not any blanks areas around them.
Select the block sprite and in the properties window, click "modify mask" to see the
darkened area that is considered to be the collidable area (see the image below). You can
set this manually, select an automatic shape to use or use the whole image – whichever is
appropriate for your game. in this case, you will probably want to set it to an ellipse and
then manually adjust the edges to be the same as the first frame of the "block" sprite.

Figure 2: Mask Properties Window


Module 8
2D GAME AR T DEVELOPMENT
6
Animation

If you play the game now, you'll see and the block animation will play straight away
in the game, since the default animation speed is 1 frame per step. This is obviously not
what we want, so we now need to stop it and only play the animation when we want it to
play.

Playing The Animation

When the ball hits a block, we need the animation to play and then destroy the block
instance. We need to make sure the animation is finished before destroying it, or else the
object will get destroyed in the first few steps of the game.
Add a Create event and drag a code block into the action list. Make a new variable
called "destroy". This will be set to true when the ball collides with the block, but for now,
set it to false. Also in the Create Event, set the built-in variable image_speed to 0. This will
stop the animation when an instance of the object is created (1 is the default speed, setting
it to 0.5 will half the animation speed, 2 will double it etc...).

Figure 3: Create Event Window

Now open the Collision Event with "obj_ball" and inside this, set the variable
"destroy" to true and remove the instance_destroy() function, and you also need to add a
bounce function so that the ball won't just go through the block, but bounce off of it:
destroy = true;
with (other)
{
move_bounce_all(false);
}
The "with" function tells GameMaker: Studio that the next code block should be run
from the instance specified, which (in this case) is the keyword "other". In a collision event,

Module 8
2D GAME AR T DEVELOPMENT
7
Animation

"other" refers to the other instance in the collision, which is in this case the ball object. So
the code is telling the ball object to use the move_bounce_all() function to bounce away
from the collision. Now the block is all set up and ready to be destroyed, we can write the
main code in the Step event.
We only want the block to animate if the destroy variable is true, so add a Step
event and in that an "if" condition that checks if "destroy" is equal to true. If this is true
then we can set the image_speed to 0.5 so it plays the animation. We then need to check if
the animation is finished with another "if" condition, so the final code looks like this:
if (destroy == true)
{
image_speed = 0.5;
if (image_index >= image_number - 1)
{
instance_destroy();
}
}
This is checking if the current animation frame (the image_index) is equal to the
total amount of frames (the image_number). We have to take 1 away from this so the
animation doesn't loop back to the start, as frames are counted from 0 (so a 10 frame
animation will have each frame numbered as 0 to 9). We can now destroy the instance.

Okay, so you have seen how we can animate sprites easily in our game, and previous
tutorials have taught you how to get things moving around the room. But what about
stopping things? What about pausing the game? This is an important question, as your
players will inevitably want to be able to pause the game while they have to do something
else, so we are going to add a pause screen to our game now.
NOTE: The following applies to those users with the Pro version of GameMaker:
Studio. For those with the Standard/Free version there is a different method outlined at the
end of the page (but you should read through the rest of this section as it still contains
relevant information).

The Application Surface


To pause our game, the easiest way is to take a "snapshot" of the room and display
that while we deactivate everything else in the background. The snapshot used will be a
sprite that we create especially for this from a surface. But what's a surface? A surface is
simply an area that you can tell GameMaker: Studio to draw to, and then when you have
finished drawing to it, you can then use it for other things. In fact, it may surprise you to
know that you are already using surfaces! Your whole game is drawn to a surface called the

Module 8
2D GAME AR T DEVELOPMENT
8
Animation

application_surface and then this surface is drawn to the screen at the start of the Post draw
event.

So, we are going to take advantage of the application surface and use it to create a
pause screen combined with a dynamic sprite. To start with we need to create a new object
which will be our "controller" object for pausing. In general, when we talk about controller
objects, we talk about objects that usually have no sprite attached to them and that sit in
the room doing all the behind the scenes work. Call this new object "obj_pause".

Before we add any code to the object, add a new sprite too and call it "spr_pause".
You can make your own sprite for this or load one in from the Game Assets folder that
comes with this tutorial. We do not need to assign this sprite to the pause object as it needs
nothing for collisions and would make editing the room difficult. However we will draw it
to the screen...

Creating A Sprite
Add a Create Event to out object "obj_pause" and in that put the following code:
sprite = -1;
paused = false;
These variables will be used to control the pausing. Now add a Keyboard Pressed
event for the <BackSpace> key with this code:
paused = !paused;
if paused
{
sprite = sprite_create_from_surface(application_surface, 0, 0, room_width,
room_height, false, false, 0, 0);
instance_deactivate_all(true);
}
else
{
instance_activate_all();
if sprite_exists(sprite)
{
sprite_delete(sprite);
}
}
Here we first toggle the pause variable between true and false, and then we check
the value to decide what to do. If we have paused the game, we create a sprite from the
application surface then use a special function to deactivate all the other instances.
Module 8
2D GAME AR T DEVELOPMENT
9
Animation

NOTE: Deactivation is a very powerful tool that effectively removes all deactivated
instances from the game, giving a boost to the game logic and keeping the instance count
down. You can find out more here.
If we are un-pausing the game, everything is activated and the sprite variable is
checked to see if we have previously made a sprite, and if we have it is removed from
memory. This type of check is very important when dealing with any resource that is
created in-game as it prevents memory leaks which will eventually slow down and kill
your game. So, always clean up after creating any dynamic resource and always check to
make sure that the resource exists before trying to manipulate it in code.

Drawing
Our final task is to draw the pause sprite and draw the custom sprite that we made
as a background. For that you need to add a Draw Event to the object "obj_pause", then
give it the following code:
if paused
{
if sprite_exists(sprite)
{
draw_sprite(sprite, 0, 0, 0);
}
draw_set_alpha(0.25);
draw_rectangle_colour(0, 0, room_width, room_height, c_white, c_white,
c_white, c_white, false);
draw_set_alpha(1);
draw_sprite(spr_pause, 0, room_width / 2, room_height / 2);
}
This code first checks to see if the game has been paused or not, and if it has it then
does a check to see if the dynamic sprite exists or not. If the sprite exists, it is drawn in the
room, then it has a transparent white rectangle drawn over the top, and finally the paused
sprite that we added previously.

Open the room editor for the game room and add an instance of this object into the
room at the top left corner. You can test the game now and you'll see that we have created a
very simple yet effective pause mechanism. In the next tutorial we will talk about how to
add further rooms to the game, and how to use them to display different game states.

Module 8
2D GAME AR T DEVELOPMENT
10
Animation

Standard/Free Pausing
You cannot create dynamic resources using the Standard/Free versions of
GameMaker: Studio and so the method outlined above cannot be used. However, you can
still pause the game by simply ommitting those functions.
So, as mentioned above, we need to create our controller object obj_pause and
create a sprite spr_pause. Next, give the object a Create Event with the following code:
sprite = -1;
paused = false;
len = 0;
pause_list = -1;

The "len" variable will hold the length of the ds_list that we will create in the
variable "pause_list". Together they will permit us to draw the deactivated objects sprites
when the game is paused. With the control variables added you can now add a Keyboard
Pressed event for the <BackSpace> key with this code:
paused = !paused;
if paused
{
len = instance_count;
pause_list = ds_list_create();
ds_list_clear(pause_list);
for (var i = 0; i < len; i++;)
{
ds_list_add(pause_list, instance_id[i]);
}
instance_deactivate_all(true);
}
else
{
ds_list_destroy(pause_list);
instance_activate_all();
}

It is similar to the code shown in the section above, only now we get the instance ID
of all instances in the room and add them into a list. We are going to take advantage of the
fact that even when deactivated, you can still access an instances variables using the
"point" method to reference them from the ID. To see this, add a Draw Event with this code:
if paused
{
for (var i = 0; i < len; i++;)
{
ii = ds_list_find_value(pause_list, i);
if ii.sprite_index != -1
{

Module 8
2D GAME AR T DEVELOPMENT
11
Animation

draw_sprite_ext(ii.sprite_index, ii.image_index, ii.x, ii.y, ii.image_xscale, ii.image_yscale,


ii.image_angle, ii.image_blend, ii.image_alpha);
}
}
draw_set_alpha(0.25);
draw_rectangle_colour(0, 0, room_width, room_height, c_white, c_white, c_white, c_white,
false);
draw_set_alpha(1);
draw_sprite(spr_pause, 0, room_width / 2, room_height / 2);
}

Since we have the instance ID's already in the list, we can simply loop through them
and draw the sprite by getting the correct values directly from the instance. This is not at
all efficient, which is why we recommend the surface approach outlined at the beginning,
but for small games it works fine and provides the exact same effect.

References and Supplementary Materials


1. https://docs.yoyogames.com/source/dadiospice/001_advanced%20use/more%20about
%20sprites/edit%20menus/animation%20menu.html
2. https://www.gamasutra.com/blogs/NathanRanney/20170508/297627/Building_A_Better
_Animation_System_in_GameMaker_Studio.php

Module 8

You might also like