Akihabara Tutorial, Part 6: Animation

by Darius Kazemi on June 23rd, 2010

This is the sixth tutorial in a multi-part tutorial series where we will teach you how to make an 8-way shooter in HTML5 and JavaScript using the Akihabara framework. Akihabara is a set of Javascript libraries that take advantage of some of HTML5’s unique features to facilitate game creation. One of the best things about writing a game in HTML5 is that it will run in any browser that supports HTML5 on any platform. This includes Chrome, Firefox, Safari, and WebKit browsers on iPhone/iPad, WebOS devices, and other mobile platforms.

In this tutorial, we will learn how to make animations for the player object.

The final product

In the end we’re going to have something that looks like this. Use the Z key to advance past the title screen, and use the arrow keys to move around. Notice how there is now a directional indicator on the player object, and that the indicator flashes red and black.

A new sprite sheet

First things first: if we’re going to animate a sprite, we need a new sprite sheet which contains the new images for our animation. Our old sprite sheet for the player object contained just a single frame since we were only ever rendering the blue circle. Download our new sprite sheet and use it to replace your old player_sprite.jpg.  If we look at the sprite sheet itself, we see that it is a 304×16 image, consisting of nineteen 16×16 frames (although one of them is blank).

Sprite frame numbers

Player sprite sheet

Modifying loadResources()

The next step is to tell the loadResources function to load up all 19 frames from our new sprite sheet. We do this by modifying gbox.addTiles:

[js] gbox.addTiles({
id: ‘player_tiles’, // Set a unique ID for future reference
image: ‘player_sprite’, // Use the ‘player_sprite’ image, as loaded above
tileh: 16,
tilew: 16,
tilerow: 19, // Now that we are animating, we need to tell the addTiles function to load 19 tiles per row
gapx: 0,
gapy: 0
});[/js]

The only thing we change is the value of tilerow, setting it to 19 instead of 1. This tells gbox.addTiles to load in 19 tiles of size 16×16 into the ‘player_tiles’ tileset.

Counting frames

Akihabara runs at a set 25 frames per second; if we ran an animation every single frame it would go by in a blur and be too fast to really see.

So what we need to do is tell the sprite to skip frames. For example, if we tell the animation to only advance every third frame, that means that our 25 frames per second animation that you see above on the left becomes the ~8.3 frames per second animation you see above on the right.

In order to do this we need to provide a global variable that counts the total number of frames. Fortunately, we already created a frameCount global variable in Part 4.5, so we’ll be using that. Later on we’ll actually call the frameCount variable to regulate frame skipping.

Defining the animations

Now that we’ve set up our frame count, we need to go ahead and define what our animations are going to be for our player object. We’re going to do this inside the initialize function for the player object, since the animations only need to be defined once, when the object is created. We’ll put it right after we set the player’s starting position, at the end of the initialize function:

[js]
this.x = 20;
this.y = 20;

// Here we define the list of animations. We can name these whatever we want.
// These are referenced with this.animList[id].
// So for example, this.animList[rightDown].frames[1] would return 12.
this.animList = {
still: { speed: 1, frames: [0] },
right: { speed: 3, frames: [1, 11] },
rightDown: { speed: 3, frames: [2, 12] },
down: { speed: 3, frames: [3, 13] },
downLeft: { speed: 3, frames: [4, 14] },
left: { speed: 3, frames: [5, 15] },
leftUp: { speed: 3, frames: [6, 16] },
up: { speed: 3, frames: [7, 17] },
upRight: { speed: 3, frames: [8, 18] }
};

// Set the starting animation for the player object.
this.animIndex = ‘still’;
},[/js]

The first thing we define is this.animList, which is a data structure containing named sets of data. (It’s technically an object; for a little background on what the colon syntax actually means, check out this pithily illuminating explanation.) Each entry in this.animList is a name of an animation state, its speed, and the frames it’s using.

The name of the animation state is whatever you want to call it, but it’s generally a good idea to pick something descriptive. The speed variable tells the animation how many overall game frames to wait before moving on to the next image in the animation sequence. As you’ll see below, it’s a simple modulo operation of frameCount % speed; the end result is that a speed of 1 means the animation will advance every frame, a speed of 2 means every other frame, a speed of 3 means every third frame, and so on.

The frames variable is an array where you pick which images to display in what order for a given animation state. The images are numbered left to right starting with 0, like so:

Sprite frame numbers

Sprite frame numbers

So for our right-facing animation, we’re picking images 1 and 11, which will show the blue circle with a notch facing right, and the notch will switch its color between black and red. It’s set to a speed of 3, which means we’re going to see it update every third frame.

After we define our different animation states, we create a variable called this.animIndex, which contains the current animation. We set the initial animation state to ‘still’.

Now, we animate

For our final step, we need to tell the player object which animations it should play under what circumstances. This goes in the player object’s first function, since it needs to be calculated before rendering happens. We insert our new code right after we call toys.topview.controlKeys:

[js] first: function() {
toys.topview.controlKeys(this, { left: ‘left’, right: ‘right’, up: ‘up’, down: ‘down’ });

// The if statements check for accelerations in the x and y directions and whether they are positive or negative. It then sets the animation index to the keyword corresponding to that direction.
if (this.accx == 0 && this.accy == 0) this.animIndex = ‘still’;
if (this.accx > 0 && this.accy == 0) this.animIndex = ‘right’;
if (this.accx > 0 && this.accy > 0) this.animIndex = ‘rightDown’;
if (this.accx == 0 && this.accy > 0) this.animIndex = ‘down’;
if (this.accx < 0 && this.accy > 0) this.animIndex = ‘downLeft’;
if (this.accx < 0 && this.accy == 0) this.animIndex = ‘left’;
if (this.accx < 0 && this.accy < 0) this.animIndex = ‘leftUp’;
if (this.accx == 0 && this.accy < 0) this.animIndex = ‘up’;
if (this.accx > 0 && this.accy < 0) this.animIndex = "upRight";

// Set the animation.
if (frameCount%this.animList[this.animIndex].speed == 0)
this.frame = help.decideFrame(frameCount, this.animList[this.animIndex]);
[/js]

What we’re doing is checking the values of this.accx and this.accy to determine what direction we’re going in. These variables are built into the default toys.topview object. We created these way back in tutorial 2 when we called toys.topview.initialize. Now you understand physics this method might seem wrong to you: technically what we want to be checking against is velocity, not acceleration. However,  the accx and accy variables in Akihabara aren’t actually acceleration, but they’re not precisely velocity either. They function as a kind of… dampened velocity. We don’t understand it 100% ourselves, but suffice to say that for our purposes, we can treat accx and accy like velocity.

This means that this.accx is positive when we’re moving right and negative when we’re moving left. Similarly, this.accy is positive when we’re moving down and negative when we’re moving up. We’re simply checking to see what combination of directions we’re moving in, and we set this.animIndex accordingly.

Last but not least, we actually set the current image we’re showing. The conditional if statement evaluates a modulo (remainder) operation which is only going to be true every nth frame, where n is our speed variable for the given animation. So again, a speed of 3 means that the if statement will evaluate as true only every 3rd frame. When the conditional does return true, we set this.frame (the object’s current rendered image) by using the help.decideFrame function, which takes the frameCount and the animation state itself as parameters, returning the correct image from within that animation sequence.

We’re zany to the max

So that’s our basic intro to animation, which you can see in action here. The player sprite now has a blinking indicator showing what direction it’s moving in. You can easily extend these principles to add animations to the enemy sprites as well!

[aki_tut_toc full_url=”“]

{ 3 comments… read them below or add one }

Jesper Juul August 19, 2010 at 5:42 AM

Do I understand it correctly that when the game says “Press A”, it means “press the A button on the imaginary controller, which happens to be mapped to the Z button on your keyboard”?

It seems that this could be fixed – it took me a while to realize that the framework wasn’t simply broken.

Reply

Darren Torpey August 19, 2010 at 7:00 AM

It means press the “A” button as mapped in your control scheme. Since it’s a cross-platform engine, it just says “A” since that could be a number of different mappings. (on touch-mobile devices, for example, “A” is a touch-screen button labeled as such)

We do mention needing to hit “Z” on the keyboard at the beginning of each tutorial (including this one), but clearly this issue with the games themselves should be remedied. Showing a full control-scheme display by default could be nice, but at the very least we could have it tell you the key it’s currently mapped to if it’s expecting keyboard input. Though for that matter I think we might change the default behavior to advance when you hit ANY key, since that would be much better in most cases.

Reply

angela August 26, 2010 at 12:46 AM

really clear intro to animList, thanks!

Reply

Leave a Comment

{ 2 trackbacks }