Handling Basic Animation with a Divided Timeline

by Michael James Williams on June 3, 2009 · 20 comments

in Avoider Game Extras,Tutorial

This is not a tutorial on learning how to animate — for that, I recommend Richard Williams’s excellent book The Animator’s Survival Kit.

This tutorial is about what to do with those animations. How do you get them inside the game? What code do you need to make a character play one animation when walking left, another when walking right, and yet another when standing still?

There are essentially two ways to handle this. Since the decision for which to use will usually lie in the hands of the game’s artist, I don’t want to say “this way is better than that way, so I’ll only show you how do do it this way”. The “correct” way is really whichever lets the animator do his job fastest, so I’ll explain both methods in separate blog posts.

The first method, which I call the “divided timeline” approach, uses the timeline very heavily, with labels and even code(!) on frames. Let’s see how it’s done.

Snapshot_O09.png
Click to play

I call the second method the “state MovieClips” approach, and I explain that in a later post. Click here to read it.

Rather than create a whole new game to use as a demonstration, I’m going to add animations to the game I made in my avoider game tutorial. If you followed that tutorial, you should be able to apply this directly to the game you created. If not, don’t worry — you can, of course, use this in your own games, but you might like to download the zip file of the game I made, to make it easier to follow.

Animation 101

In case you’ve never used Flash to animate a symbol before, I’ll quickly run through the steps to give the Enemy movie clip a looping animation. If you’re familiar with all this, you can just skim this section.

Open the FLA, and double-click the Enemy symbol in the Library to go into editing mode. Your screen should look something like this, although hopefully less cramped:

screenshot

(This is in Flash CS3, by the way. I hear the animation system got revamped in Flash CS4, so this might not apply — please leave a comment below if that’s the case.)

Flash animation works a bit like a flickbook; basically, it just plays a bunch of images in sequence. Sure, you can do much more complicated things than that, but at its core that’s all it is.

To add a new image to this sequence, right-click the first empty frame on the timeline and select Insert Keyframe. Empty frame? Timeline? Check out the image below to see what I mean:

screenshot

This copies the image from the first frame into the second. Modify this new image in some way. You could stretch it, rotate it, change the colour, redraw it… whatever! Here’s mine, slightly squashed:

screenshot

Repeat this as many times as you like to get the animation you desire. Remember to make the image on the last frame look almost identical to the image on the first frame, or it’ll be “jumpy” when it loops. It might help to know that you can copy a frame through the right-click menu, and paste it anywhere on the timeline in the same way.

Once you’re ready, run the game as usual:

Snapshot_O01.png
Click to play

As you can see, Flash automatically loops the animation.

We can slow down the speed of the animations by clicking Modify > Document and changing the frame rate. In the example above, I had the frame rate set at 24fps (frames per second). Below, I’ve changed it to 12fps:

Snapshot_O03.png
Click to play

The game feels a lot jerkier, because as well as slowing down the animations, lowering the fps also causes the screen to be redrawn (re-rendered, or refreshed) less frequently. However, because all our game logic is controlled by a timer, rather than by the frame rate, the speed at which the enemies and the avatar move does not change.

(Note: it’s possible to affect the speed of the avatar by increasing the frame rate so much that Flash has to work very hard to keep up, and thus slows everything down. Watch out for this.)

So, those are the basics. Check out the great tutorials on Tutorio.us for more.

Dividing the Timeline

You could do the same for the avatar, but I think we can do better. How about having five different animations: one for movement in each direction, and one for when it’s standing still?

First, double-click the Avatar in the Library to get into editing mode again. Just as before, we need to make a looping animation to play when the avatar is standing still. I’ve done the same kind of animation as for the enemies, to keep things simple:

Snapshot_O04.png
Click to play

Next, let’s add an animation to be played while the player is moving right.

Create a blank keyframe just after the “standing still” animation by right-clicking the first empty frame on the timeline and selecting Insert Blank Keyframe.

The “moving right” animation needs to be added to the end of the “standing still” animation, but separated by this new blank keyframe. So, if your “standing still” animation takes four frames, and you want your “moving right” animation to take another four, then the blank keyframe should be on frame 5, and “moving right” should take frames 6, 7, 8 and 9.

My “moving right” animation is identical to my “standing still” animation, except all the frames have been rotated 30 degrees clockwise:

screenshot

And my timeline looks like this:

screenshot

If you run your game now, then, of course, it’ll look a mess, with the avatar switching between standing still and looking like it’s moving to the right, no matter whether or not it actually is moving. We need to tidy this up.

First, let’s get the “standing still” animation looping correctly. On the timeline, right-click the blank keyframe that separates the two animations select Actions. A panel for entering code will appear. Enter the following:

gotoAndPlay(1);

Close this panel. You’ll notice that the frame you just edited on the timeline will have a little “a” on it. This stands for “actions”, as in ActionScript.

Run the game, and you’ll see the animation just plays the first four frames. As soon as the animation reaches the blank keyframe, the line gotoAndPlay(1) is run, and this send the animation back to the first frame.

Labels

We can make things more intuitive by labelling our frames. Left-click the first frame in the timeline, and enter StandingStill in the box in the Properties panel:

screenshot

In the same way, label the first frame of your “moving right” animation as MovingRight. You’ll see little red flags appear in the timeline to let you know that these frames have labels:

screenshot

Create a new blank keyframe after the “moving right” animation, right-click it, and select “Actions”. We’re going to make this one loop as well.

We could just type:

gotoAndPlay(6);

But what if we decide to add more frames to the “standing still” animation later? It’d screw things up. However, because we labelled the first frame of the “moving right” animation, we can just type:

gotoAndPlay("MovingRight");

Make sure you use speech marks, and that the text matches your label exactly, right down to the capital letters.

Now we need to write some code to tell the game to actually play this animation when the player moves to the right. Open AvoiderGame.as and find this block of code:

?View Code ACTIONSCRIPT3
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
if ( downKeyIsBeingPressed )
{
	avatar.moveABit( 0, 1 );
}
else if ( upKeyIsBeingPressed )
{
	avatar.moveABit( 0, -1 );
}
else if ( leftKeyIsBeingPressed )
{
	avatar.moveABit( -1, 0 );
}
else if ( rightKeyIsBeingPressed )
{
	avatar.moveABit( 1, 0 );
}

You can probably guess what we need to do. It’s a small change:

?View Code ACTIONSCRIPT3
154
155
156
157
158
else if ( rightKeyIsBeingPressed )
{
	avatar.gotoAndPlay("MovingRight");
	avatar.moveABit( 1, 0 );
}

Save and run the game:

Snapshot_O06.png
Click to play

As you can see, the avatar plays the correct animation when the right arrow is pressed… but it doesn’t stop playing it when it’s released. Can you see why?

It’s pretty easy to solve:

?View Code ACTIONSCRIPT3
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
if ( downKeyIsBeingPressed )
{
	avatar.moveABit( 0, 1 );
}
else if ( upKeyIsBeingPressed )
{
	avatar.moveABit( 0, -1 );
}
else if ( leftKeyIsBeingPressed )
{
	avatar.moveABit( -1, 0 );
}
else if ( rightKeyIsBeingPressed )
{
	avatar.gotoAndPlay("MovingRight");
	avatar.moveABit( 1, 0 );
}
else
{
	//player is not pressing any keys at all
	avatar.gotoAndPlay("StandingStill");
}

(Lines 159-162 are new, there.)

Test the game:

Snapshot_O07.png
Click to play

It works, more or less. Except… the animations aren’t actually playing, are they? Only the first frame of each is being shown. Have a think about why this is; in the meantime, let’s get the other three animations in there.

Just as before, here’s the process:

  1. Add new animation frames to Avatar’s timeline.
  2. Give the first frame an appropriate label.
  3. Add a new blank keyframe.
  4. Bring up the Actions panel for that keyframe.
  5. Enter, gotoAndPlay("Label");
  6. Add avatar.gotoAndPlay("Label"); to the correct place in AvoiderGame.as.

All done? Great! Test it out:

Snapshot_O08.png
Click to play

I’ll admit, my animations for moving up and down look pretty weird :S

Playing the Whole Animation

Now we need to sort out that bug where it only plays the first frame of the animation.

Did you figure out why it was happening? It’s because we call gotoAndPlay("MovingRight") (or whichever direction) every tick. If the player holds down the right arrow key for ten frames in a row, then each frame we’re telling Flash to play the animation starting from the frame labelled MovingRight.

To fix this, we need to know which animation is currently playing, so that we can decide not to interfere if it’s the one we want. In other words, we want our code to work like this:

?View Code ACTIONSCRIPT3
else if ( rightKeyIsBeingPressed )
{
	if ( avatar.currentAnimationState != "MovingRight" )
	{
		avatar.gotoAndPlay("MovingRight");
		avatar.currentAnimationState = "MovingRight";
	}
	avatar.moveABit( 1, 0 );
}

(!= means “is not equal to”, by the way.)

I’ve used the word state here to denote the type of animation that’s currently playing.

We’ll need to add a new public variable to the Avatar, so open Avatar.as. I’ve copied my entire AS file below, as it’s so short:

?View Code ACTIONSCRIPT3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package 
{
	import flash.display.MovieClip;
	public class Avatar extends MovieClip 
	{
		public var currentAnimationState:String;
 
		public function Avatar() 
		{
			currentAnimationState = "StandingStill";
		}
 
		public function moveABit( xDistance:Number, yDistance:Number ):void
		{
			var baseSpeed:Number = 3;
			x += ( xDistance * baseSpeed );
			y += ( yDistance * baseSpeed );
		}
	}
}

(The new lines are 6 and 10.)

Now all we need to do is work this into AvoiderGame.as, as in the example above:

?View Code ACTIONSCRIPT3
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
if ( downKeyIsBeingPressed )
{
	if ( avatar.currentAnimationState != "MovingDown" )
	{
		avatar.gotoAndPlay("MovingDown");
		avatar.currentAnimationState = "MovingDown";
	}
	avatar.moveABit( 0, 1 );
}
else if ( upKeyIsBeingPressed )
{
	if ( avatar.currentAnimationState != "MovingUp" )
	{
		avatar.gotoAndPlay("MovingUp");
		avatar.currentAnimationState = "MovingUp";
	}
	avatar.moveABit( 0, -1 );
}
else if ( leftKeyIsBeingPressed )
{
	if ( avatar.currentAnimationState != "MovingLeft" )
	{
		avatar.gotoAndPlay("MovingLeft");
		avatar.currentAnimationState = "MovingLeft";
	}
	avatar.moveABit( -1, 0 );
}
else if ( rightKeyIsBeingPressed )
{
	if ( avatar.currentAnimationState != "MovingRight" )
	{
		avatar.gotoAndPlay("MovingRight");
		avatar.currentAnimationState = "MovingRight";
	}
	avatar.moveABit( 1, 0 );
}
else
{
	//player is not pressing any keys at all
	if ( avatar.currentAnimationState != "StandingStill" )
	{
		avatar.gotoAndPlay("StandingStill");
		avatar.currentAnimationState = "StandingStill";
	}
}

Yikes, that’s messy. Does it work?

Snapshot_O09.png
Click to play

Yes!

Wrapping Up

So that’s the “divided timeline” approach. Click here to read the next part of this mini-series, where we’ll look at the other approach: using one movie clip per animation state.

Before then, why not see if you can figure out a way to tidy up that messy code in AvoiderGame.as?

The zip file with all the files I modified is available here.

{ 18 comments… read them below or add one }

Mushyrulez June 3, 2009 at 8:30 pm

Are you by any chance related to Richard Williams? :P

Tim Aste June 3, 2009 at 10:42 pm

Awesome tutorial dude!

Michael Williams June 3, 2009 at 10:55 pm

Thanks Tim!

Haha Mushyrulez, I nearly wrote “(no relation)” after his name :P Nah, not as far as I know at least.

rosedragon June 4, 2009 at 11:59 am

Good job on the tutorial!

I’m often try to use tweening as much as possible though and reduce frame by frame animation :) . For smooth purpose.

Michael Williams June 5, 2009 at 1:58 pm

Cheers, Rosedragon, and good point on the tweens :)

Kevin June 10, 2009 at 12:43 am

Your missing something… Enemy animation change based on which direction he moves!, A little tricky… well until you play around with “current label”. This is a small chunk of my game, to get you started, especially if anyone needs the enemies to switch animations. Although as always, there is a better way to do it.

if (enemy.base.hitTestObject(wall)) {
                        if (enemy.front.hitTestObject(wall)) {
                            enemy.x-= xVel;
                            enemy.y-= yVel;
                            enemy.lockTarget.width = 0;
                        }
                        if (enemy.currentLabel == "walk") {
                            enemy.gotoAndPlay("sit");
                            if (enemy.Left.hitTestObject(wall)) {
                                enemy.rotation += 1.8;
                        } else if (enemy.Right.hitTestObject(wall)) {
                            enemy.rotation -= 1.8;
                        }
                    }
                }

Kevin June 10, 2009 at 12:45 am

yuck, sorry the code is hard to read, intresting that the last of it was put in a scrolling box.. hm… how would I “box” the code next time?

Michael Williams June 10, 2009 at 2:20 pm

Nice one Kevin. Hey, you could use the rotation to affect the animation too, so an enemy walking upwards would only show the back of his head.

Oh, WordPress comments seem to do that with code, it’s really irritating.
To create your own code box you just use “pre” tags: <pre> before the code and </pre> after it.

Grey June 17, 2009 at 10:47 pm

Alright, I messed up again. I’m trying to make the random enemies have a different animation decided randomly. I coded something like this, but I can’t seem to figure out where or how to call this function properly. It may even be in my naming. Any ideas. Here is my snippet of code

var randomAnimate = Math.floor(Math.random()*4);
                    if (randomAnimate == 1)
                    {
                        enemy.gotoAndPlay("ClockwiseCoal");
                    }
                    else 
                    {
                        enemy.gotoAndPlay("CounterClockwiseCoal");
                    }

I plan to have 3 animations, but I haven’t done them because I wanted to get it working first. I tried to call a function when the enemy was created, but I kept getting “TypeError: Error #1009: Cannot access a property or method of a null object reference.
at AvoiderGame/onTick()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()”

Michael Williams June 18, 2009 at 1:23 am

Hey Grey.

Where exactly are you calling it from at the minute? I know you said “when the enemy was created” but if you could provide a snippet of the surrounding code that’d be great.

If it’s somewhere here:

    var newEnemy:Enemy = new Enemy( randomX, -15 );
    army.push( newEnemy );
    addChild( newEnemy );

…then I think it’s just a simple typo — you have written enemy.gotoAndPlay() when it should be newEnemy.gotoAndPlay(). But that’s just a guess ;)

grey June 18, 2009 at 1:53 am

Once again I’ve made a silly little mistake. Thanks for the easy fix. One of these days I’ll make a non-typo mistake. :) thanks again. Good catch.

Michael Williams June 18, 2009 at 1:54 am

No problem :) The silly mistakes are often the hardest to spot, and the most annoying to find.

Joe August 11, 2009 at 5:27 am

What if my Avatar is a character with a walkcycle of several layers and frames packaged into a MovieClip. How can I get him to play only on keyPresses?
I have done it by writing code directly into the fla. file when I gave it an instance name, but I can’t figure out how to do it in classes.

Michael Williams August 11, 2009 at 12:43 pm

Hey Joe,

If you want to avoid writing code directly into the FLA file (i.e. on the timeline) you can use State MovieClips. That’d give you an easy way to bundle up all your layers into a single simple object as well.

Let me know how you get on with that :)

Tessa September 5, 2010 at 10:41 am

Hiya,
Thank you very much for your tutorials, they helped me quite a lot.

I am trying to animate something like the different ‘collectibles’ in the avoider game. To do this, I have the following code:

package  {
    import flash.display.DisplayObject;
    import flash.events.Event;

public class Fish {

public var graphic:DisplayObject;

public function Fish() {
    graphic = new PurpleFish();
    graphic.gotoAndPlay("swimRight");
}

function onTick(){
    graphic.x = graphic.x + 1;
    //graphic.trucje();
}

}

}

Still trying to just get the basic aniimation going, so I haven’t bothered with different types yet. PurpleFish is just a movieclip that’s exported for as but no code added. It has (among others)a frame labelled “swimRight”.
When I try to run the code I get the following error:

1061: Call to a possibly undefined method gotoAndPlay through a reference with static type flash.display:DisplayObject.

Do you have any idea how to solve this? Thanks in advance!

Tessa September 5, 2010 at 11:16 am

Never mind, I fixed it by using a state movieclips approach :

if type == purple and dir == left,
show purplefishleft movieclip

Michael Williams October 5, 2010 at 1:05 am

Awesome, nice one Tessa :D

wlodarczyk czakijew June 21, 2013 at 2:33 pm

One of the primary requirements is, of course, the gloves.

From Big City Tickets, you can purchase sports tickets online for
events of the National Basketball Association, National Football League, National Hockey League, Major League Baseball, NASCAR Auto Racing, Boxing, Tennis,
Golf, Soccer and other sports. Jones would defeat Tarver by a majority
decision, and given that it was the closest that anyone had come to Jones: the result
was publicly disputed.

Leave a Comment

Writing code? Write <pre> at the start and </pre> at the end to keep it looking neat.

Anti-Spam Protection by WP-SpamFree

{ 2 trackbacks }

Previous post:

Next post: