Akihabara Tutorial, Part 2: Moving a Sprite
This is the second 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 teach you how to render a sprite to the screen and make it move around. This tutorial covers sprite rendering, input, and basic game object creation and manipulation. We are building off of Part 1 and are assuming you’ve followed that tutorial and you’re editing what you created in part 1.
The Final Product
To see the end result of this lesson, go here. Press the “Z” key to get past the title screen and then use the arrow keys to move the circle around.
The General Idea
Now that we’re starting to write actual game code, we need to step back and think about what a video game is in the abstract sense.
Games consist of objects interacting with each other: in a game like Space Invaders, objects would include the player’s ship, the enemies, the cover shields, and the bullets. We then set up rules about how objects behave. An enemy object would contain code that says “Move me back and forth, then down when I hit the edge of the screen. I fire a bullet in a downward direction at random intervals.”
The objects are the core component of the game, but a bucket of objects by itself isn’t a game. We need to place these objects in a world and give an overall structure: “Place 4 rows of 10 enemies each positioned above the player.”; “The player object can die three times before we go to the game over state.”
Akihabara is an object-based game engine. In this part of the tutorial we’re going to get our first taste of creating a player object, defining its behaviors, and placing it in the world. For this tutorial, there won’t be any other objects for it to interact with or any overall structure to the game — we’ll cover those parts of the game we’re building in future tutorials.
The Player Object
Our player object will contain a few definitions. We’re going to define what the object looks like by pointing it to a sprite (a 2D graphic, more on this in a second), and we’ll set its controls and tell it how to move.
Our Sprite
A sprite is a fancy word for an image, or a piece of an image, that we can control with our code. It’s a graphic that is assigned to a game object and becomes the visual representation for that object.
The graphic we’re going to use for our sprite is this blue circle, player_sprite.png. It’s a PNG file: Akihabara respects transparency in PNGs so it will render any transparent portions of a PNG sprite correctly so you can see through to the background. So even though the image itself is a 16×16 pixel square, it will appear in our game as a circle. Download it and place it in the same directory as index.html, with your other PNG files from part 1.
In order for our game to use the sprite, we need to load it along with all of our other graphics. Open the Part 1 code and add the following code inside loadResources immediately after the line where we load the logo.png file.
[js]
gbox.addImage(‘logo’, ‘logo.png’);
// ** Part 2 Code Below **
// Adding our spritesheet here, which gives us our circular
protagonist
gbox.addImage(‘player_sprite’,
‘player_sprite.png’);
// Sprites sheets are cut here, setting the tile size, the
number of sprites per row and the gap of the frames set.
gbox.addTiles({
id: ‘player_tiles’, // set a unique ID for future
reference
image: ‘player_sprite’, // Use the
‘sprites’ image, as loaded above
tileh: 16,
tilew: 16,
tilerow: 1,
gapx: 0,
gapy: 0
});
// Sprites sheets are cut here, setting the tile size, the
number of sprites per row and the gap of the frames
set. gbox.addTiles({ id: ‘player_tiles’,
// set a unique ID for future reference image:
‘player_sprite’, // Use the ‘sprites’
image, as loaded above tileh: 16, tilew: 16,
tilerow: 1, gapx: 0, gapy: 0 });[/js]
The first thing we do is call gbox.addImage, which we learned about in Part 1. This just loads the PNG file.
Next we call gbox.addTiles. Most 2D game engines support something called a sprite sheet, which is a big image that contains a series of smaller images, each of the same size, laid out in an organized grid. The sprite sheet is then cut up into a tile map, which is done by identifying the size of the grid and numbering each cell, or tile, in the grid. The game engine can then refer to each tile by its number — a 2D animation would be defined as a series of numbers identifying different cells to be shown one after another.
The gbox.addTiles function takes an image and divides it up just like that. You tell it the height and width of each individual tile along with how many tiles it should expect per row. Our circle is 16×16 pixels so we set tileh and tilew (height and width) to 16. In this case we’re only dealing with a single cell, so we tell it to look for 1 tile per row. The gapx and gapy variables define how much padding (aka “whitespace” that is ignored) goes between each cell, which in this case we leave at 0.
The playerTiles ID that we’ve defined will be accessed later when we define the player object itself.
Changing our resolution
Akihabara’s default settings display the game in a 640×480 canvas, but the game itself is rendering a 320×240 view at 2X zoom. This gives us the chunky pixel look of an old NES game, but for this game we want to run in native resolution. What we’re going to do is switch from 320×240 and 2X zoom to 640×480 and 1x zoom.
In order to do this we need to send some override variables to the help.akihabaraInit function, which accepts certain override variables contained within an object that is passed to it in its first parameter. So we replace our old help.akihabaraInit call at the top of loadResources with the following:
[js]function loadResources() {
// We’re passing some overrides to help.akihabaraInit to
set our title, resolution, and zoom factor
help.akihabaraInit({
title: ‘8by5’,
width: 640,
height: 480,
zoom: 1
});[/js]
If you run the program right now, you’ll see that the resolution has changed: the logo now looks half the size it used to be.
The Structure of Our Player Object
The code for defining an object can get pretty long-winded, so what we’re going to do here is first go over the structure used for defining and object, then discuss the specific implementation. What follows is the overall outline of our object, contained in the addPlayer function. Please read over the code along with the comments, they’re pretty self-explanatory.
[js]
function main() {
// …lots of part 1 code in here…
}
// Our wrapper function for adding a player object —
this keeps our main game code nice and clean
function addPlayer() {
// gbox.addObject creates a new object in your game, with
variables and functions. In this case we’re creating the
player.
gbox.addObject({
// id refers to the specific object, group is the group
it’s in for rendering purposes, tileset is where the
graphics come from
id: ‘player_id’,
group: ‘player’,
tileset: ‘player_tiles’,
// the initialize function contains code that is run when the
object is first created. In the case of the player object this
only happens once, at the beginning of the game, or possibly
after a player dies and respawns.
initialize: function() {
// …
},
// the first function is like a step function. it runs every
frame and does calculations. it’s called first because
it happens before the rendering, so we calculate new positions
and actions and THEN render the object
first: function() {
// …
},
// the blit function is what happens during the game’s
draw cycle. everything related to rendering and drawing goes
here
blit: function() {
// …
},
}); // end gbox.addObject for player
} // end addPlayer()[/js]
Right after the main function we create a function called addPlayer which acts as a wrapper so we can keep our main game code clean. The function that does the heavy lifting inside addPlayer is called gbox.addObject.
The first thing we do is define some basic identification variables. First we give the player object an id so we can refer to it from other functions. Then we set a group ID, which is used for rendering order. This lets us say things like, “Be sure to render everything in the player group on top of everything in the background group” so we don’t get our player disappearing behind the background. Then we set the object’s tileset to ‘playerTiles’, which is the ID we set for our graphics tilemap up above.
The rest of the object is divided into three functions: initialize, first, and blit.
The initialize function contains all the code that is run when an object is created and never again. This typically contains things like maximum health values, initial velocities, and anything else that could be considered “setup” for the object.
The first function is the code that is run during each game step, before graphics are rendered. A game step is a small unit of time in which calculations are made to update an object’s behavior. This is the function where we put all of the behavior of an object, things like checking for player input, checking to see if an object is colliding with another object, updating our position based on our current speed, updating the artificial intelligence, etc. Much of what we think of when we think “game programming” happens in this function.
The blit function contains all the rendering code for the object. If it has to do with showing graphics on the screen, it goes here. Like the first function, this is run each step, and it’s run after the first function. This is because we want to do things like update our position first, and then draw the sprite on the screen at its most up-to-date location.
The next three sections will discuss what we’re putting in each of these three functions.
The initialize Function
In this case our initialize function is pretty empty:
[js]
initialize: function() {
// Toys are helper functions that are specific to certain
genres.
// We’re using the "topview" toys because
we’re creating a game with a top view and Akihabara
provides convenient helper functions for that.
// Here we’re just telling it to initialize the object,
in this case our player.
toys.topview.initialize(this, {
});
},[/js]
We’re just telling the game to initialize the player object as a toys.topview type of object, which gives it access to all the helper functions inside toys.topview. This will come in handy within first and blit below.
The first Function
Inside the first function we tell the object that once per game step, it should check to see if the arrow keys are pressed, change the object’s acceleration values based on those keys, tell the physics engine that this is an object that accepts acceleration, and then applies those forces to the object by actually updating the object’s position.
[js] first: function() {
// Toys.topview.controlKeys sets the main key controls. In
this case we want to use the arrow keys which
// are mapped to their english names. Inside this function it
applies acceleration values to each of these directions
toys.topview.controlKeys(this, { left: ‘left’,
right: ‘right’, up: ‘up’, down:
‘down’ });
// This adds some friction to our accelerations so we stop
when we’re not accelerating, otherwise our game would
control like Asteroids
toys.topview.handleAccellerations(this);
// This tells the physics engine to apply those forces
toys.topview.applyForces(this);
},
[/js]
The toys.topview.controlKeys function is a helper function where you map acceleration in each of the four directions to control keys. In this case we want to map the arrow keys so the function ends up looking kind of silly: yes, left is left and right is right. But sometimes that’s how game programming is.
When we call toys.topview.handleAccellerations (yes there is a spelling error in that function name) we are telling the game engine to slow down our velocity to 0 when we’re not accelerating in a given direction. If we didn’t include this function, our player object would kind of skate around like it was on ice. We’re essentially applying some friction here.
The toys.topview.applyForces function provides the code that looks at our last location location and our current velocity and acceleration and recalculates our position based on those values. This is where actual movement happens.
The blit Function
What we do in the blit function is clear the screen then draw our new position for the player object.
[js]
blit: function() {
// Clear the screen.
gbox.blitFade(gbox.getBufferContext(),{});
// Render the current sprite.. don’t worry too much
about what’s going on here. We’re pretty much
doing
// the default drawing function, sending along the tileset,
the frame info, coordinates, whether the
// spries is flipped, camera info, and the alpha transparency
value
gbox.blitTile(gbox.getBufferContext(), {
tileset: this.tileset,
tile: this.frame,
dx: this.x,
dy: this.y,
fliph: this.fliph,
flipv: this.flipv,
camera: this.camera,
alpha: 1.0
});
},[/js]
The gbox.blitFade function clears the screen — you pass it gbox.getBufferContext which returns the current screen buffer info so it knows what exactly it’s clearing.
The gbox.blitTile function passes along information about the rendering of the tile for this object. As explained in part 1, “this” just means we’re talking about the object we’re writing the code inside of, so we end up passing the current tileset, the current x/y coordinates, information about whether this tile is flipped vertically or horizontally (by default it’s not), information about our camera, and the alpha transparency value of 1 (meaning completely opaque). Since we’re sending almost entirely this.* data, we’re really just passing on the defaults here, which is good enough for now.
A Few Tweaks to Our main Function
Now we need to make a few small tweaks to our main function and then we’re good to go!
The first thing we need to do is define our rendering layer for the player object. We assigned the player object to the ‘player’ group back when we defined the object, so here’s where we use it. We’re going to go the first line of the main function where we call gbox.setGroups and add a ‘player’ group to the list of groups inside the array.
[js]
function main() {
// ** For Part 2 we’re adding ‘player’ to
this next line **
gbox.setGroups([‘player’, ‘game’]);
[/js]
The gbox.setGroups function tells the game what order to render things in. Things are rendered in the left-to-right order that they’re listed in setGroups. By adding the ‘player’ group at the front, the player object will be rendered first, but then anything in the ‘game’ group will be rendered on top of it. This is good because later on the ‘game’ group is going to contain messages like “Game Over” that we will want to appear on top of the player’s sprite.
Now we want to get rid of that difficulty selection screen and the “Let’s begin!” message. To do that we simply override those functions to do nothing. After the line where we define maingame, we put in those overrides:
[js]
maingame = gamecycle.createMaingame(‘game’,
‘game’);
// ** Part 2 code below **
// Disable the default difficulty-choice menu; we don’t
need it for our tutorial
maingame.gameMenu = function() { return true; };
// Disable the default "Let’s begin" screen;
we don’t need it for our tutorial
maingame.gameIntroAnimation = function() { return true;
};[/js]
At the end of our main function, right before we call gbox.go to run the game, we need actually initialize our game by placing our player object in the game world.
[js]
// maingame.initializeGame is where all the game’s
objects and behaviors are defined. This is where your game
code lives!
maingame.initializeGame = function() {
addPlayer();
};
gbox.go();
}[/js]
The maingame.initializeGame function is all the code we run to set up our game. To go back to the earlier analogy we used, this is where you’d set up the player and all the enemies for a game of Space Invaders. All that we do inside this function is call our addPlayer function, which initializes the player object. Because we did not define any coordinates for the player object it will default to (0,0) and spawn at the top left side of the screen.
Hey, You’re Moving!
You can now save your HTML file and load it in a compatible web browser; you should see something like this. You’ll see the title screen from part 1. Press Z on your keyboard to get past the title screen and the blue circle will appear on the screen. It can be controlled with the arrow keys on your keyboard.
[aki_tut_toc full_url=”“]
{ 6 comments… read them below or add one }
Absolutely awesome docs you are putting together for Akihabara. Please keep up the great work!
Pretty good stuff you got here mate =).
I’ve been playing with Akihabara a little bit these days, and I’ve found it very enjoyable to work with – the big real pain is indeed the lack of documentation, but I see it is on its way now – can’t wait to see the next examples/tutorials.
Cheers,
macskeptic
I really enjoyed the first tutorials and am looking forward to the next one!
These are a god send! Thanks! So excited for the next one. Step by step getting a handle on this thing!
Good tutorials, enjoying coding my way following your tuts, will read on since your samples are really interesting :D
If I could recommend any edits, or for those reading this much after the fact.
It was not very clear to me (complete newb, ok, but still) where that last block of init first blit code actually went.
I went and looked at the source on the example at the end, but it was confusing to me until then.
If you get stuck here as I did, check out the source at the end…basically they are replacing some of the first tut with the second…
{ 3 trackbacks }