Jan 22, 2012
Posted on Jan 22, 2012 in Hints and Tips | 10 comments
As HTML games begin to gradually increase in popularity, vendors are starting to introduce some exciting new APIs to make gaming that little bit sweeter for both us developers and our end players. One of these is the GamepadAPI, which allows you to connect your good old console gamepad into your computer and use it for browser based games, plug and play style. Let’s dive in!
Introduction: What Is the Gamepad API?
In a nutshell, the Gamepad API allows you to interact with your browser using a video game console controller, AKA a gamepad. This doesn’t require a special driver or plugin to work, it’s as simple as plug and play!
Being a console gamer rather than a desktop gamer myself, I much prefer to interact with games using a gamepad, and with the upcoming rise of HTML and JavaScript based games, this is going to become a really useful tool in making games more easily accessible for your users.
The Gamepad API is not readily available for public release, but we can start using it for ourselves with preview versions of Firefox. So before we get stuck in, we need a few things.
What You’ll Need
As I mentioned, the Gamepad API isn’t available for public release just yet so you will need to first get yourself a Nightly build of Firefox and make sure you have the Firebug add-on installed (for debugging purposes only).
Also, you can’t forget a gamepad! I’m going to be using a PlayStation 3 controller for this tutorial but an Xbox controller will do just fine.
Once you have installed Nightly and added on Firebug you are ready to go!
(NB. Recent builds of Chromium have Gamepad API support as well, but this tutorial has not been tested against them.)
Step 1: Connecting a Gamepad to Your Browser
Let’s start with a basic HTML file (index.html), sourcing “gamepad.js” (a blank JavaScript file).
index.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Introduction to the Gamepad API</title>
</head>
<body>
<h1>Gamepad API</h1>
<script src="gamepad.js"></script>
</body>
</html>
The connection of a gamepad is detected with a simple JavaScript event listener, the event fired is called “MozGamepadConnected”. So the first thing we need to do is add an event listener to the window to detect that event.
I’m also adding a callback function that will log the details of the event to Firebug’s console. This is the information we are most interested in and what will actually let us know that we have connected a gamepad successfully.
function gamepadConnected(evt)
{
console.log(evt);
}
window.addEventListener('MozGamepadConnected', gamepadConnected);
Run your index.html in Nightly and open up Firebug’s console, here we’ll be able to see the logging of the event from our callback function.
Make sure your controller is turned off and not connected wirelessly to a games console. Plug it in to your computer via USB and power on the controller, watching the event log in the console.

Great, we have a gamepad connecting to a browser, no extra plugins or drivers required!
Step 2: Disconnecting a Gamepad
It’s just as important to know whether a gamepad has been disconnected as well, so let’s look at the event, “MozGamepadDisconnected”.
Similarly to step one, add an event listener for a disconnect event and a callback function to log the event details.
function gamepadDisconnected(evt)
{
console.log(evt);
}
window.addEventListener('MozGamepadDisconnected', gamepadDisconnected);
If you’re gamepad is still connected, refresh your page (which you’ll see connected event be logged) and then disconnect your gamepad by ejecting it from the USB port. You should get an event log like this one.

Now we know when a gamepad has been connected and disconnected, it’s probably a good idea to record the state inside a variable and get ready to detect button events!
var gamepadActive = false;
function gamepadConnected(evt)
{
console.log(evt);
gamepadActive = true;
}
function gamepadDisconnected(evt)
{
console.log(evt);
gamepadActive = false;
}
window.addEventListener('MozGamepadConnected', gamepadConnected);
window.addEventListener('MozGamepadDisconnected', gamepadDisconnected);
Step 3: Detecting Button Presses
Button presses, again, use an event listener and callback function with two events, “MozGamepadButtonDown” and “MozGamepadButtonUp”.
I would suggest logging the entire event from the button press yourself to see what is going on, but the key piece of information we need to get from this event is evt.button. This is the numerical id of the button that was pressed.
The callback function this time takes a second parameter, a boolean value to test if the button was pressed or released. We set this ourselves in the callback functions of the event listeners.
function buttonPressed(evt, pressed)
{
console.log(evt.button, pressed);
}
window.addEventListener("MozGamepadButtonDown", function(evt) { buttonPressed(evt, true); } );
window.addEventListener("MozGamepadButtonUp", function(evt) { buttonPressed(evt, false); } );
This should now output the IDs of the buttons that are pressed and whether they were pressed or released (true for button down, false for button up).

Next we’ll create an array with all the PlayStation 3 buttons in. The indices of the array will map to the IDs used on this gamepad, with the values being the name of the button.
var gamepadActive = false,
ps3Buttons = new Array();
ps3Buttons[12] = 'triangle',
ps3Buttons[15] = 'square',
ps3Buttons[14] = 'cross',
ps3Buttons[13] = 'circle',
ps3Buttons[4] = 'up',
ps3Buttons[7] = 'left',
ps3Buttons[6] = 'down',
ps3Buttons[5] = 'right',
ps3Buttons[10] = 'L1',
ps3Buttons[8] = 'L2',
ps3Buttons[11] = 'R1',
ps3Buttons[9] = 'R2',
ps3Buttons[1] = 'L3',
ps3Buttons[2] = 'R3',
ps3Buttons[16] = 'PS',
ps3Buttons[0] = 'select',
ps3Buttons[3] = 'start';
If you’re using a different controller, take the time to figure out which index goes with which button, and store that info in a similar array.
If we now modify the buttonPressed() function ever so slightly, we can easily tell which button on the controller has been pressed.
function buttonPressed(evt, pressed)
{
console.log(ps3Buttons[evt.button] + ' was pressed');
}
Give it a go! Pressing buttons on your controller should now log the name of buttons being pressed. This will be a lot easier to understand than “button 5″ (which, in my case, is on the D-pad).
Step 4: Detecting Axis Events
Detecting axis events is basically keeping track of where the left and right analog sticks on the gamepad are positioned using the “MozGamepadAxisMove” event.
Add the new event handler and callback function.
function moveAnalogSticks(evt) {
console.log(evt.axis, evt.value);
}
window.addEventListener("MozGamepadAxisMove", moveAnalogSticks);
This is what we get – confusing, right?

There is only one event fired by both analog sticks; each event gives us one of four possible axis and a value between -1.0 and +1.0. Axis 0 and 1 belong to left analog stick and axis 2 and 3 belong to the right.

In the diagram above you’ll see axis 0 and 2 correspond to the x axis, and 1 and 3 correspond to the y axis. By using both the x and y axis for each individual analog stick, you can figure out which way the analog stick is facing!
On different gamepads, you may have other axes. For instance, the shoulder triggers on an Xbox controller are also analog.
Step 5: Putting It Into Practice
That covers all of the events that we can currently take from a gamepad, so let’s put what we’ve learnt into practice.
Now, I don’t want to go too heavily into the game development side of things, as we are focusing on what we use to control games themselves. One of the key things to look at, though, is switching control schemes. As not everyone will have a gamepad ready to hand, we need to make sure we provide controls for both the keyboard and gamepad.
Step 6: Setting Up Your Canvas
To get a small demo up and running, create a canvas element in your html file with an id of “game” and set the width to 600 and height to 540. As you may know, the canvas element is commonly used to render HTML games on.
You will also want to copy the “ship.png” and “space.jpg” images from the source download to your working folder as these are what we’ll be rendering to the canvas. Alternatively, find some graphics of your own to have a play with!
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>Introduction to the Gamepad API</title>
</head>
<body>
<h1>Gamepad API</h1>
<canvas id="game" width="600" height="540"></canvas>
<script src="gamepad.js"></script>
</body>
</html>
Step 7: Creating the Game Loop
Now that the canvas element is in our DOM, we want to create a game loop to render our game.
I’m using a shim for “requestAnimationFrame” by Paul Irish that will be the base for our loop. Next, we get the 2D context of the canvas which we’ll use to draw on and create two new image objects, one for the background and one for our spaceship.
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
window.requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(/* function */ callback, /* DOMElement */ element){
window.setTimeout(callback, 1000 / 60);
};
})();
var canvas = document.getElementById('game'),
ctx = canvas.getContext('2d'),
ship = new Image(),
space = new Image();
space.src = "space.jpg";
ship.src = "ship.png";
Next, the player object. It has x and y coordinates which keep track of where it should appear on the canvas; four direction states (up, down, left and right) so we can know which way the ship is moving; a render() function, which first calls updatePosition() and then draws the image of the ship onto the canvas based on the x and y coordinates, and finally the updatePosition() function itself, which tests to see which way the ship is set to move and updates its position accordingly.
var player = {
x: 200,
y: 250,
up: false,
down: false,
left: false,
right: false,
render: function() {
this.updatePosition();
ctx.drawImage(ship,this.x,this.y);
},
updatePosition: function() {
this.up ? this.y-- : false;
this.down ? this.y++ : false;
this.left ? this.x-- : false;
this.right ? this.x++ : false;
}
}
After that we have our “renderGame” function which draws the space background image onto the canvas first, then draws our spaceship on top of that.
And finally, our loop. This function calls itself again and again, each time calling our “renderGame” function.
function renderGame()
{
ctx.drawImage(space,0,0);
player.render();
}
;(function animloop(){
requestAnimFrame(animloop);
renderGame();
})();
Your canvas should now have a nice space looking background with a spaceship sat in the middle of it – not too exciting, I know. So let’s add some controls!
Step 8: Hooking Up the Ship’s Controls
In our player code we named the four buttons which we want to control our ship with. These match up to the names of the buttons inside the ps3Buttons[] array. So, all we have to do is modify our buttonPressed() function ever so slightly and we’ll be moving.
var player = {
...
up: false,
down: false,
left: false,
right: false,
...
}
Now when a gamepad button is pressed or released it will set its state within the player object, so when the “up” button is pressed, player.up = true/false will be set.
function buttonPressed(evt, pressed)
{
console.log(evt.button, pressed);
player[ps3Buttons[evt.button]] = pressed ? true : false;
}
Head back over to your demo and you should be able to move your ship around!
Step 9: Adding a Keyboard Fallback
As not everyone playing your game will have a gamepad, you’ll probably still want to allow them to play the game with a keyboard.
Lets first create a new keys[] array, and map the keyboard’s arrow keys’ keyCode properties to the equivalent buttons on the gamepad. This will allow us to reuse buttonPressed() function that the gamepad utilises.
var gamepadActive = false,
ps3Buttons = new Array(),
keys = new Array();
ps3Buttons[12] = 'triangle',
ps3Buttons[15] = 'square',
ps3Buttons[14] = 'cross',
ps3Buttons[13] = 'circle',
ps3Buttons[4] = 'up',
ps3Buttons[7] = 'left',
ps3Buttons[6] = 'down',
ps3Buttons[5] = 'right',
ps3Buttons[10] = 'L1',
ps3Buttons[8] = 'L2',
ps3Buttons[11] = 'R1',
ps3Buttons[9] = 'R2',
ps3Buttons[1] = 'L3',
ps3Buttons[2] = 'R3',
ps3Buttons[16] = 'PS',
ps3Buttons[0] = 'select',
ps3Buttons[3] = 'start';
keys[38] = 4;
keys[37] = 7;
keys[40] = 6;
keys[39] = 5;
Now we need a “onkeyup” and “onkeydown” event listener for the arrow keys. When a key is pressed or released, we make sure that a gamepad is not in use. Then we prevent the arrow key from doing its usual task (scrolling the browser window up or down in this case) and then call the same buttonPressed() function that the gamepad calls.
To do this, a fake event object is passed with the key’s “keyCode” mapped to an item in the keys[] array, which in turn, passes the corresponding gamepad button ID.
window.onkeydown = function(evt)
{
if (gamepadActive == false)
{
evt.preventDefault();
buttonPressed({ button: keys[evt.keyCode] }, true);
}
}
window.onkeyup = function(evt)
{
if (gamepadActive == false)
{
evt.preventDefault();
buttonPressed({ button: keys[evt.keyCode] }, false);
}
}
This should now let you use the arrow keys for controlling the ship when a gamepad isn’t plugged in, while still letting the gamepad take over when it’s present.
Conclusion
So we’ve covered the basics of connecting a gamepad to your computer, learnt how to hook into the events that the gamepad fires, and then use them in practice. Not forgetting, the crucial fall-back support for the keyboard!
A quick challenge for those of you with a controller other than a PS3 Dual Shock: adjust the button mapping based on whichever controller is plugged in.
Thank you for taking the time to learn about the Gamepad API. If you have any questions, please leave them in the comments.



View full post on Activetuts+
Nov 17, 2011
Posted on Nov 17, 2011 in Hints and Tips | 10 comments
In the last tutorial, we introduced FlashPunk and its capabilities. Now it’s time to build a game with it! We’ll build a top-down, mouse-controlled shoot-’em-up, with a title screen and a game over screen. Read on to learn more…
Final Result Preview
Let’s take a look at the final result we will be working towards:
Step 1: The Player Ship
As always, first we need a clean project. Grab the latest FlashPunk build from the official site. Create a new AS3 project in FlashDevelop and put FlashPunk’s source in the source folder of the project. The game will have the following dimensions: 400×500 px.
We will begin our game by adding a ship – the player ship – on the screen. For that, we will need a new world, called GameWorld, and an image:
The player ship will be an entity. Create one, embed the image in it and put it on the screen. If you’re feeling lost, below is the code for the player ship (if you’re really feeling lost, I recommend reading the first tutorial again). I think that creating the world won’t be a problem for you.
package
{
import net.flashpunk.Entity;
import net.flashpunk.graphics.Image;
public class PlayerShip extends Entity
{
[Embed(source = '../img/PlayerShipImage.png')]
private const IMAGE:Class;
public function PlayerShip()
{
graphic = new Image(IMAGE);
graphic.x = -27.5;
graphic.y = -30;
x = 200;
y = 400;
}
}
}
Add the player ship into the world and make it the current world when FlashPunk’s Engine starts. You’ll get the following:
Step 2: Movement
With the player ship on the screen, we need to make it move. Just like every shoot-’em-up game, the player ship will be able to move across all the screen. There’s one thing left to decide before coding the movement: we will be using frame-based movement (the reason for this is in the next step). That means changing (if needed) the super() call to FlashPunk’s Engine and NOT using the FP.elapsed property.
The code for the player ship movement is below. The movement is mouse-based:
private var _currentDistanceX:Number;
private var _currentDistanceY:Number;
private const SPEED:int = 3;
override public function update():void
{
calculateDistances();
if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED)
{
x = Input.mouseX;
y = Input.mouseY;
}
else
{
x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED;
y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED;
}
}
private function calculateDistances():void
{
_currentDistanceX = Input.mouseX - x;
_currentDistanceY = Input.mouseY - y;
}
You will need to import net.flashpunk.utils.Input in the player ship class. Also, don’t forget to enable FlashPunk’s console. After compiling the project, you will see the player ship following the mouse:
Step 3: Enemies
Time to add something fun: enemies. Enemies need to spawn randomly (based on waves) and need to have a controlled movement. They also have a different image:
The code for creating the enemy class and adding the image to it shouldn’t be a problem. What we need to focus on is how to make enemies follow a path. The idea is this: we create a wave of enemies and pass them a path to follow, and when to spawn. After that, they will be responsible for showing themselves on the screen and moving along the path.
What is a good representation for a path? A Vector of points seems good enough. Also, we need to define a distance between each point. That way, we can be sure of one important thing: if we define the distance between two points of the path to be the distance that the enemy moves during 1 frame, we won’t need the enemy to process too much information, and we will be able to define after how many frames the enemy will leave the screen by just counting the number of points in the vector. That way, it’s very easy to define when a wave will end.
See it in action: the code below only makes enemies follow a path already given to them, and on the time passed to them (which will be counted in frames). When the enemy is created, a counter that starts on a given number begins decreasing after each elapsed frame, and when it reaches zero, the enemy will put itself on screen and begin following its path.
package
{
import flash.geom.Point;
import net.flashpunk.Entity;
import net.flashpunk.FP;
import net.flashpunk.graphics.Image;
import net.flashpunk.World;
public class Enemy extends Entity
{
[Embed(source = '../img/EnemyImage.png')]
private const IMAGE:Class;
private var _timeToAct:uint;
private var _pathToFollow:Vector.<Point>;
private var _currentPoint:uint;
private var _myWorld:World;
private var _added:Boolean;
public function Enemy(timeToAct:uint, pathToFollow:Vector.<Point>, worldToBeAdded:World)
{
graphic = new Image(IMAGE);
graphic.x = -15;
graphic.y = -8;
_timeToAct = timeToAct;
_pathToFollow = pathToFollow;
_currentPoint = 0;
_myWorld = worldToBeAdded;
_added = false;
}
override public function update():void
{
if (_timeToAct > 0)
{
_timeToAct--;
}
else
{
if (!_added)
{
_myWorld.add(this);
_added = true;
}
x = _pathToFollow[_currentPoint].x;
y = _pathToFollow[_currentPoint].y;
_currentPoint++;
if (_currentPoint == _pathToFollow.length)
{
_myWorld.remove(this);
_added = false;
destroy();
}
}
}
public function destroy():void
{
graphic = null;
}
}
}
From the code above, you can see that we always move a fixed distance from point to point by just positioning the enemy on its current point. It is because of this that we are able to determine when an enemy wave will end. You can also see that the enemy takes care of everything: adding itself in the world, moving through the world and removing itself from the world. With that, it’s very simple to create enemies in the game.
Step 4: Adding Enemies to the Screen
Our base Enemy class is done. Now it’s time to modify GameWorld a bit to add enemies. The first task is to generate paths for the enemies. For the purposes of this tutorial, we will only create a straight line, but feel free to try creating any kind of wave path. This is the function that creates a straight line:
private function generateEnemyPath(distanceBetweenPoints:Number):Vector.<Point>
{
var i:Number;
var vec:Vector.<Point> = new Vector.<Point>();
var xPos:Number = Math.random() * 360 + 20;
for (i = -20; i < 520; i += distanceBetweenPoints)
{
vec.push(new Point(xPos, i));
}
return vec;
}
With that, we can already give to an enemy a path to follow. The next step is to actually create the enemy:
private var _enemy:Enemy;
public function GameWorld()
{
_playerShip = new PlayerShip();
add(_playerShip);
_enemy = new Enemy(0, generateEnemyPath(1), this);
}
override public function update():void
{
super.update();
if (_enemy)
_enemy.update();
}
Compile and run the game. You’ll probably get the following error:
[Fault] exception, information=RangeError: Error #1125: The index 540 is out of range 540.
That happens because even after the enemy deletes itself from the world, we are still calling the update() function of it, because our code didn’t detect when the enemy removed itself. Let’s fix that by overriding the current remove() method:
override public function remove(e:Entity):Entity
{
if (e is Enemy)
{
_enemy = new Enemy(0, generateEnemyPath(1), this);
}
return super.remove(e);
}
Now compile the project and you’ll see this:
This is what that function does: every time the enemy removes itself from the world, we detect that through our overriden function and then just create another enemy to “replace” the old one. That’s it! We now have enemies moving across the screen!
Step 5: Shooting With the Player Ship
A shoot-’em-up game wouldn’t be fun without cool ways of shooting bullets out of your ship, would it? In this step we’ll see a great way of organizing bullet patterns in order to shoot them. If you tried to take a guess, you are probably correct: we’re going to use Vectors of Points. However, this time the points will have dynamic beginnings and ends, because your ship won’t always be at the same place every time you shoot, but don’t worry, it’s not as hard as it sounds!
The strategy here is to generate a bullet pattern around a fixed x- and y-axis, and then sum the player ship’s position to the points from the pattern, thus relocating the axis to a new position, giving the impression that the bullets are coming out of the player ship. The bullet image we are going to use is this:
Everything gets simpler when you look at the code. We are basically doing something very similar to the enemy path:
package
{
import flash.geom.Point;
import net.flashpunk.Entity;
import net.flashpunk.graphics.Image;
public class PlayerBullet extends Entity
{
[Embed(source = '../img/BulletImage.png')]
private const IMAGE:Class;
private var _pathToFollow:Vector.<Point>;
private var _xPos:Number;
private var _yPos:Number;
public function PlayerBullet(pathToFollow:Vector.<Point>, xPos:Number, yPos:Number)
{
graphic = new Image(IMAGE);
graphic.x = graphic.y = -3.5;
_pathToFollow = pathToFollow;
_xPos = xPos;
_yPos = yPos;
}
override public function update():void
{
x = _xPos + _pathToFollow[0].x;
y = _yPos + _pathToFollow[0].y;
_pathToFollow.shift();
if (_pathToFollow.length == 0)
{
world.remove(this);
destroy();
}
}
public function destroy():void
{
_pathToFollow = null;
graphic = null;
}
}
}
Notice that we don’t really create the bullet patterns in here: they’re always passed as parameters, just like the enemies. The only difference is that the bullets are always added right away in the world and we keep the initial position of the bullet.
Let’s try adding a bullet when the player clicks with the mouse. In PlayerShip.as:
override public function update():void
{
calculateDistances();
if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED)
{
x = Input.mouseX;
y = Input.mouseY;
}
else
{
x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED;
y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED;
}
if (Input.mousePressed)
{
world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x, y));
}
}
Now we need to create the bullet path. We are going to create a straight line, just like for the enemy, but you can do any kind of path! In GameWorld.as, let’s create the generateBulletPath() function:
public function generateBulletPath(distanceBetweenPoints:Number):Vector.<Point>
{
var i:Number;
var vec:Vector.<Point> = new Vector.<Point>();
for (i = 0; i > -500; i -= distanceBetweenPoints)
{
vec.push(new Point(0, i));
}
return vec;
}
With that, hit the compile and run button and this is what you get:
Step 6: Collision Detection (Using Masks)
We have now the basics of the game running: a player ship that shoots and enemies that go down the screen. Time to add collision detection!
The first step to add the collision detection is to give each entity a type. I’ll leave that to you: give the “Player” type to PlayerShip, “Enemy” to Enemy and “PlayerBullet” to PlayerBullet.
We will be using pixel-perfect collision in this game, so it might be useful to talk about masks. Masks are elements used by FlashPunk for collision detection. They are basically like hitboxes, but they can have a different form (pixel level). We need to set up masks for the player ship, enemies and bullets. The image used by the mask is the same image of the entity. Look at the code for the PlayerShip, Enemy and PlayerBullet, respectively:
public function PlayerShip()
{
graphic = new Image(IMAGE);
graphic.x = -27.5;
graphic.y = -30;
mask = new Pixelmask(IMAGE, -27.5, -30);
x = 200;
y = 400;
type = "Player";
}
public function Enemy(timeToAct:uint, pathToFollow:Vector.<Point>, worldToBeAdded:World)
{
graphic = new Image(IMAGE);
graphic.x = -15;
graphic.y = -8;
mask = new Pixelmask(IMAGE, -15, -8);
_timeToAct = timeToAct;
_pathToFollow = pathToFollow;
_currentPoint = 0;
_myWorld = worldToBeAdded;
_added = false;
type = "Enemy";
}
public function PlayerBullet(pathToFollow:Vector.<Point>, xPos:Number, yPos:Number)
{
graphic = new Image(IMAGE);
graphic.x = graphic.y = -3.5;
mask = new Pixelmask(IMAGE, -3.5, -3.5);
_pathToFollow = pathToFollow;
_xPos = xPos;
_yPos = yPos;
type = "PlayerBullet";
}
As you can see, this is very simple: we create a new Pixelmask, pass the source to use as a mask (just like with the graphic) and then pass both x and y offsets (in case you want to center the mask somewhere). Now, in GameWorld.as:
private var _bulletList:Vector.<PlayerBullet>;
override public function update():void
{
super.update();
if (_enemy)
_enemy.update();
_bulletList = new Vector.<PlayerBullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
if (bullet.collideWith(_enemy, bullet.x, bullet.y))
{
_enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
}
Notice that we could have simply used _enemy.collide("PlayerBullet", _enemy.x, _enemy.y) to check for collisions, but the method above is better when we have many bullets on the screen and there is a possibility that two bullets hit the same enemy at the same time. We have called the takeDamage() function of the Enemy class, but at the moment there is none. (Create an empty function for now. In the next step we will make the enemy take damage and explode when necessary.) Compile the project and you’ll get this:
Step 7: Enemy Death
We have made bullets hit our enemies. In this step we will play an explosion animation every time an enemy dies and remove it from the game. The explosion animation sprite sheet is below:
The approach we will take to do this is by decreasing the enemy’s health in the takeDamage() function, and if the health gets below zero, we will destroy it and put the animation in the screen. The code for decreasing the health is below:
private var _health:int = 100;
public function takeDamage():void
{
_health -= 50;
if (_health <= 0)
{
addExplosion();
_myWorld.remove(this);
_added = false;
destroy();
}
}
The code is very simple. There’s only one thing unknown about it: the addExplosion() function. This function will create an instance of Explosion and add it to the world. The Explosion class will just play and remove itself from the world after that. It’s a simple class:
package
{
import net.flashpunk.Entity;
import net.flashpunk.graphics.Spritemap;
public class Explosion extends Entity
{
[Embed(source = '../img/ExplosionAnimation.png')]
private const ANIMATION:Class;
public function Explosion(xPos:Number, yPos:Number)
{
graphic = new Spritemap(ANIMATION, 50, 46, onAnimationEnd);
graphic.x = -25;
graphic.y = -23;
x = xPos;
y = yPos;
Spritemap(graphic).add("Explode", [0, 1, 2, 3, 4], 25/60, false);
Spritemap(graphic).play("Explode");
}
private function onAnimationEnd():void
{
world.remove(this);
destroy();
}
public function destroy():void
{
graphic = null;
}
}
}
The trick here is using the callback parameter of the Spritemap class: when the animation ends, that function will be called, and then it removes itself from the world.
Now, back to Enemy.as to finish that function!
private function addExplosion():void
{
world.add(new Explosion(x, y));
}
Easy, isn’t it? Compile the game and destroy some enemies!
Step 8: Score
The next logical step after making enemies die is to add a score in the game! We will do that using FlashPunk’s Text class. Start by creating a GameScore class, which will hold the score of the game. Since Text is a Graphic, we will make GameScore an Entity and add its text as a graphic. Look at the code:
package
{
import net.flashpunk.Entity;
import net.flashpunk.graphics.Text;
public class GameScore extends Entity
{
private var _score:int;
public function GameScore()
{
graphic = new Text("Score: 0");
_score = 0;
}
public function addScore(points:int):void
{
_score += points;
Text(graphic).text = "Score: " + _score.toString();
}
public function destroy():void
{
graphic = null;
}
}
}
As you can see, we will call the addScore() function to add points to the game’s score. First, we need to add it to the world. In GameWorld.as:
private var _score:GameScore;
public function GameWorld()
{
_playerShip = new PlayerShip();
add(_playerShip);
_enemy = new Enemy(0, generateEnemyPath(1), this);
_score = new GameScore();
_score.x = 300;
_score.y = 470;
add(_score);
}
public function get score():GameScore
{
return _score;
}
public function get score():int
{
return _score;
}
If we hit compile, we get just a static score on the bottom of the screen:
We need to add something to the score every time an enemy is killed. In Enemy.as:
public function takeDamage():void
{
_health -= 50;
if (_health <= 0)
{
addExplosion();
GameWorld(world).score.addScore(1);
_myWorld.remove(this);
_added = false;
destroy();
}
}
Hit compile now and the score will always increase when an enemy is killed!
Step 9: Upgrades
Time to add upgrades! We will not have a nice screen to choose upgrades. Instead, we will create upgrades based on the score: each time the score goes up by 5 (up to 45), the player’s speed will increase a bit. When the score reaches 25, the player will be able to shoot two shots on every click. We will make the score 50 be the end of the game.
Let’s begin by coding the player speed upgrade. For that, we will need to add a multiplier to the speed. In PlayerShip.as:
public var speedMultiplier:Number = 1;
override public function update():void
{
calculateDistances();
if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier)
{
x = Input.mouseX;
y = Input.mouseY;
}
else
{
x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
}
if (Input.mousePressed)
{
world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x, y));
}
}
Now it’s all about changing the multiplier in GameWorld.as:
private var _speedUpgradeNumber:int = 0;
override public function update():void
{
super.update();
if (_enemy)
_enemy.update();
_bulletList = new Vector.<PlayerBullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
if (bullet.collideWith(_enemy, bullet.x, bullet.y))
{
_enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
{
_playerShip.speedMultiplier += 0.1;
_speedUpgradeNumber++;
}
}
Done! Now, every 5 enemy deaths the player will receive a 10% increase in moving speed!
For the double bullet upgrade, we will make a boolean in the PlayerShip class indicating whether or not the ship has the upgrade. Then we will check that when shooting. Here is it:
public var hasDoubleShoot:Boolean = false;
override public function update():void
{
calculateDistances();
if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier)
{
x = Input.mouseX;
y = Input.mouseY;
}
else
{
x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
}
if (Input.mousePressed)
{
if (hasDoubleShoot)
{
world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x - 5, y));
world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x + 5, y));
}
else
{
world.add(new PlayerBullet(GameWorld(world).generateBulletPath(3), x, y));
}
}
}
Now, let’s do the same as we did for the speed in GameWorld.as:
override public function update():void
{
super.update();
if (_enemy)
_enemy.update();
_bulletList = new Vector.<PlayerBullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
if (bullet.collideWith(_enemy, bullet.x, bullet.y))
{
_enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
{
_playerShip.speedMultiplier += 0.1;
_speedUpgradeNumber++;
}
if (_score.score >= 25)
{
_playerShip.hasDoubleShoot = true;
}
}
And that’s it! Hit compile and your game will have upgrades!
Step 10: Increasing the Difficulty
If you played the game until getting the double shot upgrade in the last step, you may have noticed that the game is too easy right now. What do you think of increasing its difficulty based on the player’s score?
That’s the idea: the game will now be able to put on the screen more than one enemy. And for each kill the player gets, we decrease the timer of spawning a new enemy. Interesting, isn’t it? But that’s not the only thing. What about increasing the enemies’ healths and decreasing the damage they take from the player? Now we’re getting somewhere!
Let’s jump to the coding: first we will make the health increase and damage decrease every kill. They will be just like the upgrades on the player ships, but this time we will need to change our approach as to where to keep the multipliers. In Enemy.as:
private var _health:int;
public static var healthMultiplier:Number = 1;
public static var damageMultiplier:Number = 1;
public function Enemy(timeToAct:uint, pathToFollow:Vector.<Point>, worldToBeAdded:World)
{
graphic = new Image(IMAGE);
graphic.x = -15;
graphic.y = -8;
mask = new Pixelmask(IMAGE, -15, -8);
_timeToAct = timeToAct;
_pathToFollow = pathToFollow;
_currentPoint = 0;
_myWorld = worldToBeAdded;
_added = false;
type = "Enemy";
health = 100 * Enemy.healthMultiplier;
}
public function takeDamage():void
{
_health -= 50 * Enemy.damageMultiplier;
if (_health <= 0)
{
addExplosion();
GameWorld(world).score.addScore(1);
_myWorld.remove(this);
_added = false;
destroy();
}
}
And now, in GameWorld.as:
private var _enemyUpgradeNumber:int = 0;
override public function update():void
{
super.update();
if (_enemy)
_enemy.update();
_bulletList = new Vector.<PlayerBullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
if (bullet.collideWith(_enemy, bullet.x, bullet.y))
{
_enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
{
_playerShip.speedMultiplier += 0.1;
_speedUpgradeNumber++;
}
if (_score.score >= 25)
{
_playerShip.hasDoubleShoot = true;
}
if (_score.score > _enemyUpgradeNumber)
{
Enemy.damageMultiplier -= 0.015;
Enemy.healthMultiplier += 0.02;
_enemyUpgradeNumber++;
}
}
And now our enemies are getting stronger after each kill! Take that, evil player!
Now we need to modify GameWorld in order to spawn enemies based on time. It’s a simple thing: we will just need a timer and a spawn interval. Here’s all the modified code:
private var _enemyList:Vector.<Enemy>;
private var _enemySpawnInterval:int = 5000;
private var _enemySpawnTimer:int;
public function GameWorld()
{
_playerShip = new PlayerShip();
add(_playerShip);
_enemyList = new Vector.<Enemy>();
_score = new GameScore();
_score.x = 300;
_score.y = 470;
add(_score);
_enemySpawnTimer = 0;
}
override public function update():void
{
super.update();
_enemySpawnTimer--;
if (_enemySpawnTimer <= 0)
{
_enemySpawnTimer = _enemySpawnInterval;
_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));
add(_enemyList[_enemyList.length - 1]);
}
_bulletList = new Vector.<PlayerBullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
for each (var enemy:Enemy in _enemyList)
{
if (bullet.collideWith(enemy, bullet.x, bullet.y))
{
enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
}
if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
{
_playerShip.speedMultiplier += 0.1;
_speedUpgradeNumber++;
}
if (_score.score >= 25)
{
_playerShip.hasDoubleShoot = true;
}
if (_score.score > _enemyUpgradeNumber)
{
Enemy.damageMultiplier -= 0.015;
Enemy.healthMultiplier += 0.02;
_enemyUpgradeNumber++;
}
}
override public function remove(e:Entity):Entity
{
if (e is Enemy)
{
_enemyList.splice(_enemyList.indexOf(e), 1);
}
return super.remove(e);
}
Notice that I gave the enemies a few random frames of “wait time” before appearing. That will make their appearance unpredictable. Now all that’s left is to decrease the spawn interval after every kill:
override public function update():void
{
super.update();
_enemySpawnTimer--;
if (_enemySpawnTimer <= 0)
{
_enemySpawnTimer = _enemySpawnInterval;
_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));
add(_enemyList[_enemyList.length - 1]);
}
_bulletList = new Vector.<PlayerBullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
for each (var enemy:Enemy in _enemyList)
{
if (bullet.collideWith(enemy, bullet.x, bullet.y))
{
enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
}
if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
{
_playerShip.speedMultiplier += 0.1;
_speedUpgradeNumber++;
}
if (_score.score >= 25)
{
_playerShip.hasDoubleShoot = true;
}
if (_score.score > _enemyUpgradeNumber)
{
Enemy.damageMultiplier -= 0.015;
Enemy.healthMultiplier += 0.02;
_enemySpawnInterval -= 3;
_enemyUpgradeNumber++;
}
}
With that, we basically have everything done in the game world!
Step 11: The Main Menu World
I think we have everything finished in the game world. The game’s surprisingly difficult with the tougher enemies! What do you think of making a nice main menu now? I created a nice background for it:
Create the MainMenuWorld class, which extends from net.flashpunk.World, and add the background in it. I’ll leave the code for you. We will need a play button, which I also created:
In order to create the play button, we are going to use the Button class created in the first part of this tutorial series. Here’s the code for the button in MainMenuWorld.as:
[Embed(source = '../img/PlayGameButton.png')]
private const PLAYBUTTON:Class;
private var _playButton:Button;
public function MainMenuWorld()
{
addGraphic(new Image(TITLE));
_playButton = new Button(playTheGame, null, 48, 395);
_playButton.setSpritemap(PLAYBUTTON, 312, 22);
add(_playButton);
}
private function playTheGame():void
{
FP.world = new GameWorld();
destroy();
}
public function destroy():void
{
removeAll();
_playButton = null;
}
Don’t forget to change the Main class as well!
override public function init():void
{
FP.world = new MainMenuWorld();
FP.console.enable();
}
Hit compile and… Yes! Our shiny main menu world works! Now to the game over world!
Step 12: The Game Over World
The game over world is going to be very simple. I have created two images: one for when the player dies and one for when the player wins the game. There will be a Quit button that will return the player to the main menu. It’s basically the same thing as the main menu world. Here are the two images and the button:
I will leave the coding to you. The only thing that will change in this class is that it will need an argument passed to the constructor, telling whether or not the player destroyed the enemies. Here’s the code for the constructor:
public function GameOverWorld(hasLost:Boolean)
{
if (hasLost)
{
addGraphic(new Image(BACKGROUNDLOST));
}
else
{
addGraphic(new Image(BACKGROUNDWON));
}
_quitButton = new Button(quitToMain, null, 166, 395);
_quitButton.setSpritemap(QUITBUTTON, 69, 19);
add(_quitButton);
}
Step 13: The Boss – Movement
Finally, the moment everyone was waiting for. Every shoot-’em-up needs a boss, and this is ours!
What we need now is code it. First, the movements. And then, the bullets. This step is for the movements.
As you may have guessed, our boss won’t go directly down the screen. Instead, it will move randomly around the top of the screen, to give the player a bit of difficulty defeating it. What we will need to do is a movement very similar to the player’s. The only difference is that it will follow a point chosen randomly in the top of the screen, and not the mouse. Here’s the full code for the Boss class!
package
{
import flash.geom.Point;
import net.flashpunk.Entity;
import net.flashpunk.graphics.Image;
import net.flashpunk.masks.Pixelmask;
public class Boss extends Entity
{
[Embed(source = '../img/BossImage.png')]
private const IMAGE:Class;
private var _currentDistanceX:Number;
private var _currentDistanceY:Number;
private var _randomPoint:Point;
private const SPEED:int = 3;
public var speedMultiplier:Number = 1;
public function Boss()
{
graphic = new Image(IMAGE);
graphic.x = -38;
graphic.y = -35;
mask = new Pixelmask(IMAGE, -38, -35);
type = "BossEnemy";
getRandomPoint();
}
private function getRandomPoint():void
{
_randomPoint = new Point();
_randomPoint.x = Math.random() * 400;
_randomPoint.y = 38 + (Math.random() * 100);
}
override public function update():void
{
calculateDistances();
if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier)
{
x = _randomPoint.x;
y = _randomPoint.y;
getRandomPoint();
}
else
{
x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
}
}
private function calculateDistances():void
{
_currentDistanceX = _randomPoint.x - x;
_currentDistanceY = _randomPoint.y - y;
}
}
}
We are basically using the same movement code from PlayerShip. Notice that we have kept the speed multipliers, because there will be a really fun thing in the end!
We need now to come up with a way to test this movement. Running the game and getting 50 kills is too much time to wait until we can see the boss (and end up realizing there’s a bug and we will need to do it all again and again!). Let’s just add the boss on the screen when the game begins (yes, with the other enemies going down the screen!) and check the movement! In GameWorld.as:
private var _boss:Boss;
public function GameWorld()
{
_playerShip = new PlayerShip();
add(_playerShip);
_enemyList = new Vector.<Enemy>();
_score = new GameScore();
_score.x = 300;
_score.y = 470;
add(_score);
_enemySpawnTimer = 0;
_boss = new Boss();
add(_boss);
}
Hit compile and test the game! Our boss is moving nicely, isn’t it? It’s going to be hard to kill it!
Step 14: The Boss – Shooting
Time for the really evil boss bullets! Here is their image:
But there is something really bothering me: they will have exactly the same behavior as the player bullet, but instead they will just follow the same enemy downward path, and will have a different FlashPunk type, but I don’t want to copy and paste the same code in their class. What do you think about using some Object-Oriented Design and make an inheritance? Take all the code (yes, all the code) of PlayerBullet and copy it to a new class called Bullet. Remove the code related to the bullet’s image, and this is what you get:
package
{
import flash.geom.Point;
import net.flashpunk.Entity;
public class Bullet extends Entity
{
private var _pathToFollow:Vector.<Point>;
private var _xPos:Number;
private var _yPos:Number;
public function Bullet(pathToFollow:Vector.<Point>, xPos:Number, yPos:Number)
{
_pathToFollow = pathToFollow;
_xPos = xPos;
_yPos = yPos;
}
override public function update():void
{
x = _xPos + _pathToFollow[0].x;
y = _yPos + _pathToFollow[0].y;
_pathToFollow.shift();
if (_pathToFollow.length == 0)
{
world.remove(this);
destroy();
}
}
public function destroy():void
{
_pathToFollow = null;
graphic = null;
}
}
}
That’s the basic behavior of the bullet. Now, what do we do with the PlayerBullet class? Put only the things related to the bullet image in there, and remove the rest. And also make it inherit from Bullet:
package
{
import flash.geom.Point;
import net.flashpunk.graphics.Image;
import net.flashpunk.masks.Pixelmask;
public class PlayerBullet extends Bullet
{
[Embed(source = '../img/BulletImage.png')]
private const IMAGE:Class;
public function PlayerBullet(pathToFollow:Vector.<Point>, xPos:Number, yPos:Number)
{
super(pathToFollow, xPos, yPos);
graphic = new Image(IMAGE);
graphic.x = graphic.y = -3.5;
mask = new Pixelmask(IMAGE, -3.5, -3.5);
type = "PlayerBullet";
}
}
}
Do you mind making the same thing for the BossBullet class too? The only difference is that it will have a type of “BossBullet”. I’ll leave the code to you. Check the tutorial source if you need help!
We could have done the same for the boss and the enemies, but we would need to change more things, because the movement of the enemies isn’t the same as the movement of the boss. It’s better to leave it that way. And now, for the boss shooting. We will use the same timer strategy that we used for the enemy spawning. Here’s the code:
private var _shootingInterval:int = 75;
private var _shootingTimer:int = 0;
override public function update():void
{
calculateDistances();
if ((_currentDistanceX * _currentDistanceX) + (_currentDistanceY * _currentDistanceY) < SPEED * SPEED * speedMultiplier * speedMultiplier)
{
x = _randomPoint.x;
y = _randomPoint.y;
getRandomPoint();
}
else
{
x += Math.cos(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
y += Math.sin(Math.atan2(_currentDistanceY, _currentDistanceX)) * SPEED * speedMultiplier;
}
_shootingTimer--;
if (_shootingTimer <= 0)
{
_shootingTimer = _shootingInterval;
world.add(new BossBullet(GameWorld(world).generateBossBulletPath(1.5), x - 10, y));
world.add(new BossBullet(GameWorld(world).generateBossBulletPath(1.5), x + 10, y));
world.add(new BossBullet(GameWorld(world).generateBossBulletPath(1.5), x, y + 5));
}
}
Compile and run the code and now you have a boss shooting bullets and flying around! Time to make the last battle happen in the next step
Step 15: Final Touches
You may have noticed that the boss’s bullets don’t hit the player ship, and the player’s bullets don’t hit the boss. That’s because we haven’t coded them to hit their enemies. That’s what we are going to do now. We will also make the boss only appear when the score reaches 50, and check for when the player loses the game.
The first task: to make the boss only appear when the score reaches 50. We will do that by checking for the score in GameWorld.as, just like we did with the enemy and player upgrades.
private var _bossAppeared:Boolean = false;
public function GameWorld()
{
_playerShip = new PlayerShip();
add(_playerShip);
_enemyList = new Vector.<Enemy>();
_score = new GameScore();
_score.x = 300;
_score.y = 470;
add(_score);
_enemySpawnTimer = 0;
_boss = new Boss();
// Not adding the boss in the game this time
}
override public function update():void
{
super.update();
_enemySpawnTimer--;
if (_enemySpawnTimer <= 0 && !_bossAppeared)
{
_enemySpawnTimer = _enemySpawnInterval;
_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));
add(_enemyList[_enemyList.length - 1]);
}
_bulletList = new Vector.<PlayerBullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
for each (var enemy:Enemy in _enemyList)
{
if (bullet.collideWith(enemy, bullet.x, bullet.y))
{
enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
}
if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
{
_playerShip.speedMultiplier += 0.1;
_speedUpgradeNumber++;
}
if (_score.score >= 25)
{
_playerShip.hasDoubleShoot = true;
}
if (_score.score > _enemyUpgradeNumber)
{
Enemy.damageMultiplier -= 0.015;
Enemy.healthMultiplier += 0.02;
_enemySpawnInterval -= 3;
_enemyUpgradeNumber++;
}
if (_score.score == 50 && !_bossAppeared)
{
add(_boss);
_bossAppeared = true;
}
}
First task done. Notice that we also changed the block that spawned new enemies. That way, when the boss appears, no more enemies will spawn.
Second task: make boss bullets hit the player and player bullets hit the boss. This is also done in GameWorld.as. Take a look at the code:
private var _bulletList:Vector.<Bullet>;
override public function update():void
{
super.update();
_enemySpawnTimer--;
if (_enemySpawnTimer <= 0 && !_bossAppeared)
{
_enemySpawnTimer = _enemySpawnInterval;
_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));
add(_enemyList[_enemyList.length - 1]);
}
_bulletList = new Vector.<Bullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
for each (var enemy:Enemy in _enemyList)
{
if (bullet.collideWith(enemy, bullet.x, bullet.y))
{
enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
if (_bossAppeared)
{
if (bullet.collideWith(_boss, bullet.x, bullet.y))
{
_boss.takeDamage();
if (!_boss)
{
endTheGame();
return;
}
remove(bullet);
bullet.destroy();
}
}
}
_bulletList = new Vector.<Bullet>();
getType("BossBullet", _bulletList);
for each (var bossBullet:BossBullet in _bulletList)
{
if (bossBullet.collideWith(_playerShip, bossBullet.x, bossBullet.y))
{
endTheGame();
return;
}
}
if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
{
_playerShip.speedMultiplier += 0.1;
_speedUpgradeNumber++;
}
if (_score.score >= 25)
{
_playerShip.hasDoubleShoot = true;
}
if (_score.score > _enemyUpgradeNumber)
{
Enemy.damageMultiplier -= 0.015;
Enemy.healthMultiplier += 0.02;
_enemySpawnInterval -= 3;
_enemyUpgradeNumber++;
}
if (_score.score == 50 && !_bossAppeared)
{
add(_boss);
_bossAppeared = true;
}
}
In the first part of the code, we check for a collision between the player’s bullets and the boss. If there is a collision, we call the takeDamage() function from the boss, which is below. After checking the player’s bullets, we check for the boss’s bullets, and if we find a collision between any of them and the player, we end the game. This function is also below.
Now, for the takeDamage() function of the boss. We want the boss to have a lot of health, and we will make it fly faster after each hit. In Boss.as:
private var _health:int = 1000;
public function takeDamage():void
{
_health -= 50;
speedMultiplier += 0.05;
if (_health <= 0)
{
world.remove(this);
destroy();
}
}
public function destroy():void
{
graphic = null;
mask = null;
_randomPoint = null;
}
Our boss battle is complete! It will die after 20 hits from the player, getting faster after each hit.
Now, the only thing remaining is to end the game and show the screen when the boss is killed, and also make the player lose before the boss battle if an enemy goes down the screen. For the end of the game, we need to check when the boss is killed and create the endTheGame() function in GameWorld.as. This function will basically remove every bullet from the screen, remove the player and boss and then add the game over screen. In GameWorld.as:
override public function remove(e:Entity):Entity
{
if (e is Enemy)
{
_enemyList.splice(_enemyList.indexOf(e), 1);
}
if (e is Boss)
{
_boss = null;
}
return super.remove(e);
}
public function endTheGame():void
{
removeAll();
while (_bulletList.length > 0)
{
_bulletList[0].destroy();
_bulletList.shift();
}
while (_enemyList.length > 0)
{
_enemyList[0].destroy();
_enemyList.shift();
}
_bulletList = null;
_enemyList = null;
_playerShip = null;
_score = null;
if (_boss)
{
FP.world = new GameOverWorld(true);
}
else
{
FP.world = new GameOverWorld(false);
}
_boss = null;
}
And that’s it! The endTheGame() function is basically the same as a destroy() function. It just cleans every reference in the game world.
The last part: making the player lose the game if an enemy has reached the end of the screen. For this one we’re going to remember that an enemy only reaches the bottom of the screen if it still has health. So, in the remove() function of GameWorld.as:
private var _gameEnded:Boolean = false;
override public function remove(e:Entity):Entity
{
if (e is Enemy)
{
if (Enemy(e).health > 0)
{
endTheGame();
return e;
}
_enemyList.splice(_enemyList.indexOf(e), 1);
}
if (e is Boss)
{
_boss = null;
}
return super.remove(e);
}
override public function update():void
{
super.update();
if (_gameEnded)
{
return;
}
_enemySpawnTimer--;
if (_enemySpawnTimer <= 0 && !_bossAppeared)
{
_enemySpawnTimer = _enemySpawnInterval;
_enemyList.push(new Enemy(uint(Math.random() * 30), generateEnemyPath(2), this));
add(_enemyList[_enemyList.length - 1]);
}
_bulletList = new Vector.<Bullet>();
getType("PlayerBullet", _bulletList);
for each (var bullet:PlayerBullet in _bulletList)
{
for each (var enemy:Enemy in _enemyList)
{
if (bullet.collideWith(enemy, bullet.x, bullet.y))
{
enemy.takeDamage();
remove(bullet);
bullet.destroy();
}
}
if (_bossAppeared)
{
if (bullet.collideWith(_boss, bullet.x, bullet.y))
{
_boss.takeDamage();
if (!_boss)
{
endTheGame();
return;
}
remove(bullet);
bullet.destroy();
}
}
}
_bulletList = new Vector.<Bullet>();
getType("BossBullet", _bulletList);
for each (var bossBullet:BossBullet in _bulletList)
{
if (bossBullet.collideWith(_playerShip, bossBullet.x, bossBullet.y))
{
endTheGame();
return;
}
}
if ((_score.score % 5) == 0 && _score.score > (_speedUpgradeNumber * 5))
{
_playerShip.speedMultiplier += 0.1;
_speedUpgradeNumber++;
}
if (_score.score >= 25)
{
_playerShip.hasDoubleShoot = true;
}
if (_score.score > _enemyUpgradeNumber)
{
Enemy.damageMultiplier -= 0.015;
Enemy.healthMultiplier += 0.02;
_enemySpawnInterval -= 3;
_enemyUpgradeNumber++;
}
if (_score.score == 50 && !_bossAppeared)
{
add(_boss);
_bossAppeared = true;
}
}
public function endTheGame():void
{
removeAll();
while (_bulletList.length > 0)
{
_bulletList[0].destroy();
_bulletList.shift();
}
while (_enemyList.length > 0)
{
_enemyList[0].destroy();
_enemyList.shift();
}
_bulletList = null;
_enemyList = null;
_playerShip = null;
_score = null;
if (_boss)
{
FP.world = new GameOverWorld(true);
}
else
{
FP.world = new GameOverWorld(false);
}
_boss = null;
_gameEnded = true;
}
This code will only end the game when an enemy reaches the end (is destroyed) with a health above 0. If the enemy dies, this function is also called, but then the enemy health will be below (or equal to) 0, skipping the code to end the game. We have also created the _gameEnded boolean because when an enemy reaches the end of the screen and gets removed, the world is still updating its entities. Only when it finished updating them (after the super.update() call in the class) is that we can end the game.
After all these lines and lines of code changed, remove the FlashPunk console, hit compile and test the game. It’s finally done, your very first game entirely done in FlashPunk! Congratulations!
Step 16: Conclusion
Congratulations, you have created your first FlashPunk game! You have used pretty much all of FlashPunk’s features for a very basic game, which means you are ready to create more FlashPunk games and spread the word! What do you think of improving this game? It could have different enemies, enemies that also shoot bullets, levels, more bosses, more upgrades and a lot of other things! Are you up to the challenge?



View full post on Activetuts+
Nov 9, 2011
Posted on Nov 9, 2011 in Hints and Tips | 10 comments
TimelineLite is the ultimate tool for creating elaborate and precise sequences of scripted animation. It is an integral part of the GreenSock Tweening Platform that allows you to make the most of TweenLite and TweenMax. This series of screencasts will walk you step by step through everything you need to know to take your AS3 tweening skills to the next level.
Basic Features of TimelineLite
- Create a sequence of TweenLite/Max tweens
- Play and pause any sequence
- Reverse any sequence
- Adjust the overall speed of the sequence
- Jump-to any part of the sequence
- Add labels for easy navigation
- Scrub through any animation
Along the way we will be diving into TimelineMax which extends the power of TimelinLite with even more features. Everything you learn how to do in TimelineLite will also apply to TimelineMax.
Also, although this guide was produced solely with AS3, TimelineLite and TimelineMax have the exact same features in AS2, and use identical syntax!
Meet TimelineLite
In this first introductory video I’m going to explain exactly what TimelineLite is and what it can do. I’ll walk you through some inspiring examples of TimelineLite that highlight its many features. Along the way I’ll show you a few resources that are going to help you get the most out of your TimelineLite training. Once you see how concise and flexible TimelineLite code can be, you’ll never tween without it.
Sit back and relax as I set the groundwork for all the amazing things we will be covering in this series.
Don’t like ads? Download the screencast, or subscribe to Activetuts+ screencasts via iTunes!
TimelineLite in Action
Resources Mentioned in this Video
In this series of videos I am going to be referring to the TimelineLite documentation many times. I strongly suggest you visit and bookmark the following:
To get the most out of TimelineLite its imperative that you have a basic understanding of TweenLite and TweenMax. For a quick crash course please read GreenSock’s Getting Started Tweening article.
Come back tomorrow for the next video in the series, where we’ll be looking at basic methods and properties of TimelineLite.



View full post on Activetuts+
Oct 20, 2011
Posted on Oct 20, 2011 in Hints and Tips | 10 comments
Designers vs. developers – it is an argument as old as computers. The truth is, though, neither can live without the other. A brilliant UI design is as worthless without functionality as is the best piece of code with an ugly, unusable frontend. In this first post on UI Basics for developers, I am going to try and lay out some simple ground rules that devs can follow to make sure their apps, templates and prototypes are as beautiful as the code itself – and usable to boot.
Think: the first impression is the last impression.
Alignment
Alignment refers to the position or orientation of an element in relation to another element or to itself. When we refer to two elements being aligned to each other, alignment usually refers to which side of both elements is in line. In the context of text, alignment refers to the side to which text is anchored in a straight line.
Form Design
In the image above, the second example of a simple form design shows labels that are right-aligned to each other with input fields that are left-aligned. This ensures that the association between each label and its input field is clear and the user does not get confused if some labels are too small while others are long.
Think: Make sure input fields are not too far away from the longest label. If the variation in width is small, try right-aligning labels and left-aligning input fields.
Text
For text, it is ideal to use left-alignment when desiging for the screen. Since most for-screen type rendering methods are incapable of distributing space appropriately when justifying text to both sides, left alignment keeps text readable and well organized. You can, of course, use center and right alignment where the design demands it, but those are usually reserved for special cases and smaller chunks of text.
Flow
The primary purpose of any user interface is to let the user interface with the application. This, believe it or not, is not going to be possible unless you tell the user what he needs to do and in what order. Since you won’t be there behind every user to help them out with this, the interface needs to provide all the cues. Here are some questions to ask when evaluating whether the intended workflow is appropriate:
- How critical is it that the task be performed in a set order of steps?
- Is it obvious to the user where to start and what to do next?
- Is the intended outcome stated or implied – implicitly, if not explicitly?
Let’s take the example of a search category selection on iStockPhoto. In this case, I can either search everything or select a specific category to limit my searches to that type of information. Since the primary act is to enter a search term and hit Search, those should be fairly obvious. A possible step in between is to select a category, which can be a drop-down list between (you guessed it right) the search field and the Search button.
Another example is the income/expense input dialog in the cashbase app. The fields are arranged according to the typical workflow one will use to log such information: enter the amount (which is the most important element), select a category, add a note if necessary, and click Add. Secondary information that will be used much less frequently – like the date which by default is today, and the option to repeat or cancel – are available, but much more subtle.
Further reading:
Proximity
Related elements in an interface should be grouped together. This might sound like common sense when I mention it, but it is not always well understood. The reason all page navigation links on most websites are laid out in a single horizontal bar, is so that the user can identify the relationship at a glance and make the choice to interact with them without any confusion.
Let’s look at this example from Gmail – an app that many of use on a regular basis. This is the toolbar that appears at the top when you open a mail. Although all those buttons perform some action on the open message, they are further grouped together based on what they do – actions one would use to get rid of the message (archive, spam, delete), to change the importance of the message (when using priority inbox), label-related actions, and finally a drop-down with secondary options.
Another example of good use of proximity is the options bar in Zootool. The toolbar at the bottom is divided into three sets, each corresponding to the three panes in the app: the list packs on the left, the mail window in the center which contains all your bookmarks, and the details pane on the right.
Further reading:
Hierarchy
Not everything in a user interface, or any layout for that matter, carries the same importance as everything else. Hierarchy is the arrangement of elements in a way that denotes what is higher in order, what comes next, and so on.
Let’s look at this example here and try to identify what the order of precedence is. Since everything – titles, labels and paragraph text – looks the same, one has to read through everything to make sense. If the same interface was tweaked just a little bit like below, the overall impact on the readability and in turn the usability of the interface is enormous.
As a general rule, the page heading should be biggest and most visible on the screen. This is followed by section titles, sub-titles and then smaller labels. Paragraph text can be more or less prominent depending on its purpose. It is also not limited to text. Primary action buttons can be differentiated from secondary actions by making them brighter, bigger or fancier. Input fields for mandatory inputs can be made more obvious than the others. I could go on, but I think you get the idea.
Contrast
Another very important consideration when designing interfaces is to ensure clear differentiation between elements. Of course, you want the text to be readable on the background, but contrast goes beyond simply using light text on a dark background or vice versa. Headings and paragraph text should be clearly distinguishable. Panels and navigation bars need to be segregated from each other so the user knows what is what. The list goes on.
Contrast can be established using one or more of the following characteristics:
Color
This should be obvious, but its amazing how often people slip on this point. If your background is light, you obviously want the text to be dark to ensure readability. Although in theory complimentary colors should work well together, it is not always that easy. Try placing bright green text on a red background and you will know what I’m saying.
The possibilities here are limitless, so my first recommendation to anyone looking to select colors is to pick up a popular color palette from sites like Adobe Kuler or ColourLovers. They are contributed, evaluated and voted up by passionate users who usually know their way around color. All the basics of color matching and contrast are usually taken care of, so its just a matter of deciding which color scheme works in your app’s context.
One note of caution though – be very wary of going overboard with color. You don’t want them to overshadow the utility and usability of your app.
Size
Another good way to differentiate between elements – based on hierarchy, categorization, or visual flow – is to use different sizes. This applies to text as much as it does to images, backgrounds and static or interactive elements. You may want to put more emphasis on the primary action button, for example, and keep the secondary buttons comparatively less accessible. Or optional prompts can be smaller and lighter than the primary labels in a form.
The TeuxDeux app does a brilliant job of using color to differentiate between past, present and future days. Since the layout is geared towards a work week, different sizes of text are used to make sure that names of days are easy to identify, while the dates are comparatively more subtle.
Interaction
Since the primary purpose of any user interface is to enable users interact with the app, it is imperative that learners intuitively know what to do. As creators of the interface, it is very easy to forget that you won’t be there for every user to tell them what to do. Neither do users have the patience any more to read manuals and quick start guides before diving into using an app. The interface is required to make it amply clear what parts of it are clickable, touchable, draggable – in short, interactive.
Everyone knows how to flick an electrical switch, right? The thing that makes it obvious to anyone that a switch needs to be pressed at a certain point to change state is called affordance. On the flat surface of a screen – desktop, mobile or otherwise – different techniques can be utilized to enable users intuitively click a button or type inside an input field. When creating text hyperlinks, adding an underline for the link is the most commonly used standard, although there are many other creative ways to do that.
Here are some examples:
Going with the switch example, how do you know if flicking the switch did what it was supposed to do? The light comes on or goes off, or in some cases a light inside the switch helps make it clear whether the switch is on or off.
In an application, such feedback can be very obvious in cases where a button navigates to another page or opens a popup, but what about situations where all it does is process some data in the background – like when saving changes to the user settings? Some sort of a feedback mechanism is critical to let users know their action was successful. This could be as simple as a "your settings were saved" message, a brief notification at the top of the page, or a quick highlight around the area that was updated.
When you add a new task in Remember the Milk, it can either appear in the list on the same page, or simply get added to another list in the background (if, for example, the task has been assigned to a different category). The feedback for the action is therefore provided at two levels:
- a green highlight appears for a couple of seconds behind the task in the list to point to where it has been added, and
- a very prominent message appears on a yellow background at the top of the page letting the user know what exactly happened.
Typography
The text in your app – everything from the logo to the titles, labels and copy – is your primary mode of communication with the users. Since it is how your users access information about the app or through it, how you set the type can mean the difference between success and failure. Of course titles have to be bigger than body text and the fine print has to be, well, fine; but a lot of other decisions also influence how users consume information.
Fonts
Step one: define your fonts. It surprises me how many developers simply never bother to change whatever font their text gets generated in. Default fonts change from OS to OS and browser to browser, which means that unless you explicitly state what font you want to use, your text is going to look different in every OS and browser combination. Besides, Times New Roman – which a lot of browsers still use as the default font – is just not a good font for on-screen reading. My first recommendation is often to use a sans-serif font, although Georgia or the new Cambria font in Windows 7 also look good.

If you decide to use fonts other than the safe, universally available ones like Arial/Helvetica, Georgia, Tahoma etc., make sure there is a way to have them render similarly on all platforms. If Flash is your development environment of choice, embed them where necessary. For HTML/JS based apps, use @font-face in CSS or any of the web font services like Typekit or Google WebFonts. Remember though, that these techniques come with a caveat of extra file sizes for the embedded fonts. If speed and responsiveness are paramount for you, sticking to the base fonts is your best bet.
Disclaimer: Yes, I do know that Arial and Helvetica are not exactly similar, but they are similar enough for most users to not notice the difference.
Leading
The amount of space between two lines of text is the leading. You want the leading of your paragraph text (line-height in CSS speak) to be at least 140% of the font size to make sure it is easily readable. Any less and your text is going to be much harder to read and – more imporantly – to scan through.
Localization
If you plan to translate your app into oither languages – and you really should – it is best to test the interface early on with different scripts. At the very least, the amount of space a certain message requires can vary drastically across different scripts. The East Asian scripts use fewer words on an average but need a bigger font size, Indian (Indic) scripts also need to be slightly bigger to be readable and middle-eastern scripts (like Arabic) go from right to left instead of the usual left-to-right.
Wrapping Up
That’s about it for now. I hope these tips covered enough basics for you to start applying them in your projects right away. As with most design-related disciplines, there are no hard and fast rules to follow, and everyone has their own take on how things should work. So if you disagree with any of my suggestions above – or even if you agree with them but have a different perspective – let’s hear about them in the comments.
Next up, we will take all of this wisdom and try applying it to an actual interface. Stay tuned!



View full post on Activetuts+
Sep 15, 2011
Posted on Sep 15, 2011 in Hints and Tips | 10 comments
Learn the basics of how FlashPunk works – an amazing library to save you time and help you create the perfect game!
Final Result Preview
Let’s take a look at the final result we will be working towards:
Use the arrow keys to move your character (the blue guy). The red/brown guy is an NPC; the shaded red area is a danger zone, and the green box is a button. You’ll learn how to create all this in this tutorial.
Step 1: What Is FlashPunk?
FlashPunk is an ActionScript 3 library created for the development of Flash games. Basically, it does all the hard work for you and lets you focus entirely on developing your game, rather than on the engine behind it. The best part about it is that you don’t need Flash Pro to work with it: you can do everything with a free code editor like FlashDevelop. Not to mention it’s way faster when it comes to drawing things on screen, since it uses blitting!
This tutorial will go through all the basics of FlashPunk. After following it, you’ll be ready to make a simple game with this amazing library!
Step 2: Initializing the Engine
Begin by downloading the latest version of FlashPunk from the official site (this tutorial uses the version from August 30, 2011). Put the “net” folder, with all its contents, in your “src” folder.
FlashPunk has a class called Engine. This class is what starts everything in the library. Think of it as a Main class, but with special code to power up all the classes in FlashPunk. In order to use the Engine class, we will modify the Main class a little bit.
package
{
import net.flashpunk.Engine;
[Frame(factoryClass="Preloader")]
public class Main extends Engine
{
public function Main():void
{
}
}
}
Now, our class extends Engine. In Main‘s constructor, we need to make a call to the Engine constructor: this is what sets the important information about the game: width, height, framerate and whether the engine should run at a fixed framerate or not.
public function Main():void
{
super(550, 400, 30, false);
}
There is a function that can (and must be) overridden from the Engine class: the init() function. It will run only once, and will initialize everything to get the game working.
override public function init():void
{
trace("The game has started!");
}
I’m pretty sure everyone wants to put something on the screen and see this engine working! Because of that, the next few steps will cover the very basics of the elements of FlashPunk, adding depth as the tutorial goes on.
Step 3: Worlds and Entities
In FlashPunk, there are elements called Worlds and Entities. These are the main elements of the library, and you’ll work with them from the beginning to the very end of your game.
Worlds are pretty much like what is commonly known as a “screen”. Everything in your game will happen in a world: the main menu is a world that will give you access to the actual game world, where you will fight some enemies and die, which will lead you to the game over world, with your scores and statistics about how well you did. More about worlds will be explained later.
Entities are exactly what they seem to be; they live in a world and do something in it: a button is an entity; your character is an entity; enemies and bullets are entities. They are the things that give life to the game.
Given that, we will create the game world (there’s time to make the main menu world later, let’s jump to some action!) by extending FlashPunk’s World class:
package
{
import net.flashpunk.World;
public class GameWorld extends World
{
public function GameWorld()
{
}
}
}
Now that you have created a world, you need to tell FlashPunk that you want this world to be the active one. Let’s do it in Main.as:
private var _gameWorld:GameWorld;
public function Main():void
{
super(550, 400, 30, false);
_gameWorld = new GameWorld();
}
override public function init():void
{
trace("The game has started!");
FP.world = _gameWorld;
}
And don’t forget to import net.flashpunk.FP!
Step 4: Adding an Entity, and Giving It an Image
Now that we have our world, we can make an entity by extending the Entity class and adding it to our game world:
package
{
import net.flashpunk.Entity;
public class GameEntity extends Entity
{
public function GameEntity()
{
}
}
}
And in GameWorld.as:
private var _gameEntity:GameEntity;
public function GameWorld()
{
_gameEntity = new GameEntity();
add(_gameEntity);
}
Notice that if you compile and run the game, the entity doesn’t appear in the screen. That’s because it has no image yet! Every entity can have a graphic object. This graphic can be a single image, a spritesheet with animations, tiled images — pretty much anything.
We will add this little image to our entity:
An entity’s graphic can be accessed by the graphic property. That’s how we are going to put the image in it! First, embed it; then, just pass it to Image‘s constructor and FlashPunk will take care of transforming that into something visible for you. Compile and run now. Surprise! Our entity is there!
package
{
import net.flashpunk.Entity;
import net.flashpunk.graphics.Image;
public class GameEntity extends Entity
{
[Embed(source = "/../img/EntityImage.png")]
private const IMAGE:Class;
public function GameEntity()
{
graphic = new Image(IMAGE);
}
}
}
This is what you should get:
Step 5: Making the Entity Move
Now that we have our entity on the screen, what about making it move? Each Entity has a function called update(), which you must override to use. This function is called by every world in the beginning of each frame. If you need to make your entity move, that’s the place where you put your code!
override public function update():void
{
x += 10 * FP.elapsed;
y += 5 * FP.elapsed;
}
And don’t forget to import:
import net.flashpunk.FP;
See it in action! (Refresh the page if you can’t see anything here.)
You may have noticed the use of FP.elapsed. FP.elapsed gives the amount of time that elapsed since the last frame (in seconds), making it very easy to create time-based motion. However, for that to work, you must have set the fourth parameter to the Engine‘s constructor to false. Remember that (Step 2)? Setting it to false means that you want FlashPunk to run with a variable timestep, whereas setting it to true makes FlashPunk run on a fixed timestep. Doing the latter, you don’t need to use FP.elapsed. You will know that every time the update() function is called, a frame has passed.
Step 6: Move the Entity as You Wish With Keyboard Input
We’ve got the entity moving on just one direction in the last step. Introducing keyboard input: now you will be able to move the entity to where you want!
FlashPunk has a class called Input which takes care of both keyboard and mouse input. In this tutorial, we will only use keyboard input for movement. It is very easy:
override public function update():void
{
if (Input.check(Key.A) || Input.check(Key.LEFT))
{
x -= 50 * FP.elapsed;
}
else if (Input.check(Key.D) || Input.check(Key.RIGHT))
{
x += 50 * FP.elapsed;
}
if (Input.check(Key.W) || Input.check(Key.UP))
{
y -= 50 * FP.elapsed;
}
else if (Input.check(Key.S) || Input.check(Key.DOWN))
{
y += 50 * FP.elapsed;
}
}
And the import statements:
import net.flashpunk.utils.Input;
import net.flashpunk.utils.Key;
Input.check() returns true if the Key passed as an argument is being pressed at the time the function has been called. There are other very useful functions, like Input.pressed(), which returns true if the key has been pressed at the time the function has been called (i.e. the key was up a frame ago and is now down), or Input.released(), which does exactly the opposite.
Another interesting thing that the Input class allows us to do is to define many keys under a single name. For example, we could define Key.UP, Key.W and Key.I as "UP", and only check for Input.check("UP"). That way, we can improve our function:
public function GameEntity()
{
graphic = new Image(IMAGE);
Input.define("UP", Key.W, Key.UP);
Input.define("DOWN", Key.S, Key.DOWN);
Input.define("LEFT", Key.A, Key.LEFT);
Input.define("RIGHT", Key.D, Key.RIGHT);
}
override public function update():void
{
if (Input.check("LEFT"))
{
x -= 50 * FP.elapsed;
}
else if (Input.check("RIGHT"))
{
x += 50 * FP.elapsed;
}
if (Input.check("UP"))
{
y -= 50 * FP.elapsed;
}
else if (Input.check("DOWN"))
{
y += 50 * FP.elapsed;
}
}
And this is what you should get:
Step 7: More About Entities
Entities can do a lot more than just move around and have images. Let’s take a look at what surprises they can hold!
Entities have a property called type. You can set this property to any string you want. This allows you to organize your entities into groups, which will prove very useful in the next step (about worlds). We can, for example, set our entity’s type to “GameEntity”:
public function GameEntity()
{
graphic = new Image(IMAGE);
Input.define("UP", Key.W, Key.UP);
Input.define("DOWN", Key.S, Key.DOWN);
Input.define("LEFT", Key.A, Key.LEFT);
Input.define("RIGHT", Key.D, Key.RIGHT);
type = "GameEntity";
}
Following on that, we have the useful world property and the added() and removed() functions. The world property allows you to access the world from within the entity’s code once the entity has been added to an world. It is like the stage property in common Flash development; the functions are like the ADDED_TO_STAGE and REMOVED_FROM_STAGE event listeners. Here’s an example of the functions working in GameEntity.as:
override public function added():void
{
trace("The entity has been added to the world!");
trace("Entities in the world: " + world.count);
}
override public function removed():void
{
trace("The entity has been removed from the world!");
}
Step 8: Deeper Look at Worlds
It is time to take a deeper look at worlds and how they work. First of all, FlashPunk can only have one world running at once, but your game can have as many worlds as you wish, as long as only one remains active every time.
Worlds have update() functions just as entities do, but their function is a little different: there is actual code in the World class. That means you’ll have to call super.update() every time you override this function.
Apart from entities, worlds can also have graphics added to them. Graphics are images that don’t need to be updated by you (FlashPunk still creates an entity to add them to the world, so the engine will still send a call to an update() function). You can add them by calling addGraphic().
The most important thing about worlds is that they have several functions to retrieve certain entities: getType(), getClass(), getAll(), getLayer() and getInstance(). That way, you can have the world return an array of all the bullets currently in the game, so that you can perform a check against all of them for collision. Very handy, I must say!
Take a look at the code added to World.as. We will use a second image as well:
[Embed(source = "/../img/EntityImage2.png")]
private const IMAGE:Class;
public function GameWorld()
{
_gameEntity = new GameEntity();
add(_gameEntity);
addGraphic(new Image(IMAGE), 0, 50, 50);
}
override public function update():void
{
super.update();
var entityArray:Array = [];
getType("GameEntity", entityArray);
for each (var entity:Entity in entityArray)
{
entity.x = entity.x > 550 ? 550 : entity.x;
entity.y = entity.y > 400 ? 400 : entity.y;
}
}
And don’t forget to import net.flashpunk.graphics.Image!
In this code, the addGraphic() function call adds another graphic similar to _gameEntity‘s graphic – think of it as a NPC! – to the world in the position (50, 50). Lines 23-31 show an example of retrieving only entities of a particular kind: we call getType() to get only entities of the “GameEntity” type (currently only one entity). After that, we iterate through every entity retrieved and prevent them from getting past the right and bottom borders. (So, the entity can move outside the screen, but not far.) Simple, isn’t it?
Step 9: Animations
Time for something more interesting! FlashPunk supports animations of all kinds. All you have to do is, instead of creating an instance of Image, create an instance of Spritemap. This class receives a spritesheet and allows you to map frames and link to animations.
In our entity’s class, embed this spritemap:
Then, create an instance of Spritemap and pass the spritesheet as a parameter to the constructor. After that, it’s all about calling the add() and play() functions!
[Embed(source = "/../img/EntitySheet.png")]
private const SHEET:Class;
private var _timeInterval:Number;
public function GameEntity()
{
graphic = new Spritemap(SHEET, 40, 20, onAnimationEnd);
Spritemap(graphic).add("Stopped", [0]);
Spritemap(graphic).add("Blinking", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 24);
Input.define("UP", Key.W, Key.UP);
Input.define("DOWN", Key.S, Key.DOWN);
Input.define("LEFT", Key.A, Key.LEFT);
Input.define("RIGHT", Key.D, Key.RIGHT);
type = "GameEntity";
Spritemap(graphic).play("Blinking");
}
private function onAnimationEnd():void
{
Spritemap(graphic).play("Stopped");
_timeInterval = 0;
}
override public function update():void
{
_timeInterval += FP.elapsed;
if (_timeInterval >= 3)
{
Spritemap(graphic).play("Blinking");
}
if (Input.check("LEFT"))
{
x -= 50 * FP.elapsed;
}
else if (Input.check("RIGHT"))
{
x += 50 * FP.elapsed;
}
if (Input.check("UP"))
{
y -= 50 * FP.elapsed;
}
else if (Input.check("DOWN"))
{
y += 50 * FP.elapsed;
}
}
The constructor of Spritemap (line 19) takes four arguments: a source to get a graphic from, the width and height of each frame of the spritesheet and a callback function to call when the animation ends (optional). In GameEntity‘s constructor, we create the Spritemap and define two animations: “Stopped”, which only contains the first frame and runs at 0 fps (stopped!) and “Blinking”, which contains all frames and runs at 24 frames per second.
The rest of the code is there to play the “Blinking” animation every three seconds.
Take a look at our entity blinking:
Step 10: Collision
With everything running well, it’s time to introduce another feature: collision detection. FlashPunk has a great collision detection system: all we need to do is set hitboxes for our entities and ask the world to check for collisions. For that, we will create another entity called Box which will contain the following graphic:
package
{
import net.flashpunk.Entity;
import net.flashpunk.graphics.Image;
public class Box extends Entity
{
[Embed(source = "/../img/BoxImage.png")]
private const IMAGE:Class;
public function Box()
{
graphic = new Image(IMAGE);
setHitbox(60, 60);
}
}
}
And inside GameWorld.as:
private var _box:Box;
public function GameWorld()
{
_gameEntity = new GameEntity();
_box = new Box();
add(_gameEntity);
add(_box);
_box.x = 200;
_box.y = 150;
addGraphic(new Image(IMAGE), 0, 50, 50);
}
The setHitbox() function sets a rectangle that will act as a hit box for the entity. The first two parameters are the width and height of the box. The next two parameters (optional) are the origin coordinates (x and y) of the rectangle. Doing the same for GameEntity:
public function GameEntity()
{
graphic = new Spritemap(SHEET, 40, 20, onAnimationEnd);
Spritemap(graphic).add("Stopped", [0]);
Spritemap(graphic).add("Blinking", [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 24);
Input.define("UP", Key.W, Key.UP);
Input.define("DOWN", Key.S, Key.DOWN);
Input.define("LEFT", Key.A, Key.LEFT);
Input.define("RIGHT", Key.D, Key.RIGHT);
type = "GameEntity";
Spritemap(graphic).play("Blinking");
setHitbox(40, 20);
}
Now that we have both our entity and the box set up with hitboxes, we need to check for collisions in the world class:
override public function update():void
{
super.update();
var entityArray:Array = [];
getType("GameEntity", entityArray);
for each (var entity:Entity in entityArray)
{
entity.x = entity.x > 550 ? 550 : entity.x;
entity.y = entity.y > 400 ? 400 : entity.y;
}
if (_gameEntity.collideWith(_box, _gameEntity.x, _gameEntity.y))
{
trace("Collision!");
}
}
The collideWith() function checks collision with the entity passed as an argument, virtually placing the first entity (in this case, _gameEntity) in the position specified by the second and third arguments.
Once a collision is detected, there must be a response to it. We will only change the position of the moving entity:
override public function update():void
{
super.update();
var entityArray:Array = [];
getType("GameEntity", entityArray);
for each (var entity:Entity in entityArray)
{
entity.x = entity.x > 550 ? 550 : entity.x;
entity.y = entity.y > 400 ? 400 : entity.y;
}
if (_gameEntity.collideWith(_box, _gameEntity.x, _gameEntity.y))
{
_gameEntity.x = _gameEntity.y = 0;
}
}
Take a look at the example. Try to move the entity into the box.
Step 11: Creating a Simple Button – Adding an Image
FlashPunk doesn’t have any buttons by default. Almost all games need buttons, so in this step we will create a Button class. First of all, a button has three states (as you may know from common Flash development): “Up”, “Over” and “Down”. This spritesheet illustrates that:
And now let’s start the class:
package
{
import net.flashpunk.Entity;
import net.flashpunk.graphics.Spritemap;
public class Button extends Entity
{
protected var _map:Spritemap;
public function Button(x:Number = 0, y:Number = 0)
{
super(x, y);
}
public function setSpritemap(asset:*, frameW:uint, frameH:uint):void
{
_map = new Spritemap(asset, frameW, frameH);
_map.add("Up", [0]);
_map.add("Over", [1]);
_map.add("Down", [2]);
graphic = _map;
setHitbox(frameW, frameH);
}
override public function render():void
{
super.render();
}
}
}
The setSpritemap() function sets a spritemap for the button and sets “animations” for the button. Always the image must have first the “Up” frame, then the “Over”, followed by the “Down” frame. There’s also a call to setHitbox(). The hitbox will be used to check whether the mouse is or isn’t over the button’s box.
Step 12: Creating a Simple Button: Up/Over/Down Controls, Callback
Now that we have our Button successfully showing an image, it’s time to create up, over and down controls. We will do it by creating two Boolean attributes: “over” and “clicked”. We will also detect whether the mouse is over the button’s hit box or not. Add these functions in Button.as:
protected var _over:Boolean;
protected var _clicked:Boolean;
override public function update():void
{
if (!world)
{
return;
}
_over = false;
_clicked = false;
if (collidePoint(x - world.camera.x, y - world.camera.y, Input.mouseX, Input.mouseY))
{
if (Input.mouseDown)
{
mouseDown();
}
else
{
mouseOver();
}
}
}
protected function mouseOver():void
{
_over = true;
}
protected function mouseDown():void
{
_clicked = true;
}
override public function render():void
{
if (_clicked)
{
_map.play("Down");
}
else if (_over)
{
_map.play("Over");
}
else
{
_map.play("Up");
}
super.render();
}
And don’t forget to import net.flashpunk.utils.Input.
Following the logic in update(): first of all, both attributes (_clicked and _over) are set to false. After that, we check if the mouse is over the button. If it isn’t, the attributes will remain false and the button will be in the “Up” state. If the mouse is over, we check whether the mouse button is currently down. If that’s true, the button is in the “Down” state and _clicked is set to true; if it’s false, then the button is in the “Over” state and the _over attribute is set to true. These attributes will define which frame the spritemap should go to.
This button will be useless if you can’t detect when the user has effectively clicked it. Let’s change the class a bit in order to support callback functions:
protected var _callback:Function;
protected var _argument:*;
public function Button(callback:Function, argument:*, x:Number = 0, y:Number = 0)
{
super(x, y);
_callback = callback;
_argument = argument;
}
override public function update():void
{
if (!world)
{
return;
}
_over = false;
_clicked = false;
if (collidePoint(x - world.camera.x, y - world.camera.y, Input.mouseX, Input.mouseY))
{
if (Input.mouseReleased)
{
clicked();
}
else if (Input.mouseDown)
{
mouseDown();
}
else
{
mouseOver();
}
}
}
protected function clicked():void
{
if (!_argument)
{
_callback();
}
else
{
_callback(_argument);
}
}
Our button is done! This code will allow you to pass a callback function (and optionally an argument) to your button, so whenever the user clicks the button, the function will be called.
Step 13: Creating a Simple Button: Adding It to the Screen
Many steps and nothing on the screen… Time to put a button in there! It’s as simple as adding this code in GameWorld.as:
[Embed(source = "/../img/ButtonSheet.png")]
private const BUTTONSHEET:Class;
private var _button:Button;
public function GameWorld()
{
_gameEntity = new GameEntity();
_box = new Box();
_button = new Button(onButtonClick, null);
_button.setSpritemap(BUTTONSHEET, 50, 40);
add(_gameEntity);
add(_box);
add(_button);
_box.x = 200;
_box.y = 150;
_button.x = 400;
_button.y = 200;
addGraphic(new Image(IMAGE), 0, 50, 50);
}
private function onButtonClick():void
{
FP.screen.color = Math.random() * 0xFFFFFF;
trace("The button has been clicked!");
}
Now all you have to do is compile the project and the button will be there!
Step 14: The Console
And now the final feature from FlashPunk that will be presented in this tutorial! The Console is FlashPunk’s tool for debugging: it features logs, which are pretty much like traces; shows the time taken to run important engine step; and displays how many entities are on screen and the current FPS. It’s a great tool to use when developing your game. To enable it, just add the following line to Main.as:
override public function init():void
{
trace("The game has started!");
FP.console.enable();
FP.world = _gameWorld;
}
And to log anything in it, use the FP.log() function. For example, let’s change that trace() call:
override public function init():void
{
FP.console.enable();
FP.log("The game has started!");
FP.world = _gameWorld;
}
That’s pretty much it! You’ll see that the “Output” part from the debugging console now shows the log. You can go ahead and change all the trace() calls in our code to calls to FP.log().
Conclusion
And that’s our introduction to FlashPunk, covering the most important aspects of this amazing library: entities, worlds, images and animations; collision, buttons, input and movement. I hope you’ll like this library as much as I do – it really makes work easier!



View full post on Activetuts+
Page 1 of 612345...»Last »