Feb 25, 2012
Posted on Feb 25, 2012 in Hints and Tips | 10 comments
Premium members: here’s this week’s tutorial. Here, you’ll learn how to interact with the Rotten Tomatoes API for looking up information about movies, as we put together an efficient library that is easy to use and can quickly be expanded.
Premium Preview
To use the demo below, immediately click the try button to use the default API key provided, or type in your own API key if the default key returns an error.
Type in a keyword and click Go to search; results are displayed within a draggable window. Click a movie poster to maximize its parent window.
For a larger view, click here.
In this tutorial, I’m not going to explain how to build the UI above (although all the code for the UI is provided); I’m going to explain how to use the Rotten Tomatoes API to obtain movie data that you can use in any UI or Flash app.
Read the Full Tutorial
Premium members can access the full tutorial right away!
If you’re not yet a Premium member, you can still read the first few steps of the tutorial.
Tuts+ Premium Membership
We run a Premium membership system which periodically gives members access to extra tutorials, like this one, from across the whole Tuts+ network. If you’re a Premium member, you can log in and download the tutorial. If you’re not a member, you can of course join today!
Also, don’t forget to follow @envatoactive on twitter, circle us on Google+, like us on Facebook, and grab the Activetuts+ RSS Feed to stay up to date with the latest tutorials and articles.



View full post on Activetuts+
Feb 24, 2012
Posted on Feb 24, 2012 in Hints and Tips | 10 comments
Hey Flash Developers, welcome to the second part of my Tower Defense Game tutorial. In the first part, we developed the basic mechanism of creating turrets and making them shoot towards the point of mouse click. But that’s not what turrets are for! In this part we’ll extend the game to include enemies, basic artificial intelligence (AI) in turrets, and some more game elements. Are you ready?
Final Result Preview
This is the game we are going to create in this tutorial:
Click the orange circles to place turrets. The red circles are enemies, and the number on each represents its hit points.
Step 1: Recap
In the previous tutorial we developed a game which had placeholders for the turrets. We could deploy turrets by clicking those placeholders, and the turrets aimed at the mouse pointer and shot bullets towards the point where the user clicked.
We finished with a Main class which had the game loop and game logic. Apart from that we had the Turret class which had nothing much except the update function that made the turret rotate.
Step 2: A Separate Bullet Class
We previously created the bullets in Main class and attached an ENTER_FRAME listener to move it. The bullet did not have enough properties earlier to consider it a making a separate class. But in such a game bullets can have many varieties like speed, damage, and so on, so it is a good idea to pull out the bullet code and encapsulate it in a separate Bullet class. Let’s do it.
Create a new class called Bullet, extending the Sprite class. The basic code for this class should be:
package
{
import flash.display.Sprite;
public class Bullet extends Sprite
{
public function Bullet() {
}
}
}
Next we put the code to draw the bullet graphic, taken from Main, in Bullet. As we did with the Turret class, we create a function called draw in the Bullet class:
private function draw():void {
var g:Graphics = this.graphics;
g.beginFill(0xEEEEEE);
g.drawCircle(0, 0, 5);
g.endFill();
}
And we call this function from the Bullet constructor:
public function Bullet() {
draw();
}
Now we add some properties to the bullet. Add four variables: speed, speed_x, speed_y and damage, before the Bullet constructor:
private var speed:Number;
private var speed_x: Number;
private var speed_y:Number;
public var damage:int;
What are these variables for?
speed: This variable stores the speed of the bullet.
speed_x and speed_y: These store the x and y components of the speed, respectively, so that the calculation of breaking the speed into its components does not have to be done again and again.
damage: This is the amount of damage the bullet can do to an enemy. We keep this variable public as we will require this in our game loop in the Main class.
We initialize these variables in the constructor. Update your Bullet constructor:
public function Bullet(angle:Number) {
speed = 5;
damage = 1;
speed_x = Math.cos(angle * Math.PI / 180) * speed;
speed_y = Math.sin(angle * Math.PI / 180) * speed;
draw();
}
Notice the angle variable we receive in the constructor. This is the direction (in degrees) in which the bullet will move. We just break the speed into its x and y components and cache them for future use.
The last thing that remains in the Bullet class is to have an update function that will be called from the game loop to update (move) the bullet. Add the following function at the end of the Bullet class:
public function update():void {
x += speed_x;
y += speed_y;
}
Bingo! We are done with our Bullet class.
Step 3: Updating the Main Class
We moved a lot of bullet code from Main class to its own Bullet class, so a lot of code remains unused in Main and much needs to be updated.
First, delete the createBullet() and moveBullet() functions. Also remove the bullet_speed variable.
Next, go to the shoot function and update it with the following code:
private function shoot(e:MouseEvent):void {
for each(var turret:Turret in turrets) {
var new_bullet:Bullet = new Bullet(turret.rotation);
new_bullet.x = turret.x + Math.cos(turret.rotation * Math.PI / 180) * 25;
new_bullet.y = turret.y + Math.sin(turret.rotation * Math.PI / 180) * 25;
addChild(new_bullet);
}
}
We no longer use the createBullet function to create bullet rather use the Bullet constructor and pass the turret’s rotation to it which is the direction of the bullet’s movement and so we don’t need to store it in the bullet’s rotation property as we did earlier. Also we don’t attach any listener to the bullet as the bullet will be updated from within the game loop next.
Step 4: Saving the Bullet References
Now that we need to update the bullets from the game loop, we need a reference of them to be stored somewhere. The solution is the same as for the turrets: create a new Array named bullets and push the bullets onto it as they are created.
First declare an array just below the turrets array declaration:
private var ghost_turret:Turret;
private var turrets:Array = [];
private var bullets:Array = [];
Now to populate this array. We do so whenever we create a new bullet – so, in the shoot function. Add the following just before adding the bullet to the stage:
var new_bullet:Bullet = new Bullet(turret.rotation);
new_bullet.x = turret.x + Math.cos(turret.rotation * Math.PI / 180) * 25;
new_bullet.y = turret.y + Math.sin(turret.rotation * Math.PI / 180) * 25;
bullets.push(new_bullet);
addChild(new_bullet);
Step 5: Update the Bullets
Just like how we update the turrets the game loop, we will update the bullets, too. But this time, instead of using a for...each loop, we’ll use a basic for loop. Before this, we must add two variables to the top of the game loop, so that we know which variables are used within the game loop and can set them free for garbage collection.
var turret:Turret;
var bullet:Bullet;
Go ahead and add the following code at the end of game loop:
for (var i:int = bullets.length - 1; i >= 0; i--) {
bullet = bullets[i];
if (!bullet) continue;
bullet.update();
}
Here we traverse over all the bullets on the stage every frame and call their update function which makes them move. Note here that we iterate the bullets array in reverse. Why? We’ll see this ahead.
Now that we have a turret variable declared outside already, we don’t need to declare it again inside the for...each loop of turrets. Modify it to:
for each(turret in turrets) {
turret.update();
}
Finally we add the boundary check condition; this was previously in the bullet’s ENTER_FRAME but now we check it in the game loop:
if (bullet.x < 0 || bullet.x > stage.stageWidth || bullet.y < 0 || bullet.y > stage.stageHeight) {
bullets.splice(i, 1);
bullet.parent.removeChild(bullet);
continue;
}
We check whether the bullet is out of the stage’s boundary, and if so we first remove its reference from the bullets array using the splice function, and then remove the bullet from the stage and continue with the next iteration. This is how your game loop should look:
private function gameLoop(e:Event):void {
var turret:Turret;
var bullet:Bullet;
for each(turret in turrets) {
turret.update();
}
for (var i:int = bullets.length - 1; i >= 0; i--) {
bullet = bullets[i];
if (!bullet) continue;
bullet.update();
}
}
If you now run the game, you should have the same functionality as in Part 1, with code that is much more clean and organized.
Step 6: Presenting the Enemy
Now we add one of the most important elements of the game: the Enemy. First thing is to create a new class named Enemy extending the Sprite class:
package
{
import flash.display.Sprite;
public class Enemy extends Sprite
{
public function Enemy() {
}
}
}
Now we add some properties to the class. Add them before your Enemy constructor:
private var speed_x:Number;
private var speed_y:Number;
We initialize these variables in the Enemy constructor:
public function Enemy()
{
speed_x = -1.5;
speed_y = 0;
}
Next we create the draw and update functions for the Enemy class. These are very similar to the ones from Bullet. Add the following code:
private function draw():void {
var g:Graphics = this.graphics;
g.beginFill(0xff3333);
g.drawCircle(0, 0, 15);
g.endFill();
}
public function update():void {
x += speed_x;
y += speed_y;
}
Step 7: Timing the Game Events
In our game we need to have many events that take place at certain times or repeatedly at certain intervals. Such timing can be achieved using a time counter. The counter is just a variable that gets incremented as the time passes in the game. The important thing here is when and by how much amount to increment the counter. There are two ways in which timing is generally done in games: Time based and Frame based.
The difference is that the unit of step in time based game is based on real time (i.e. number of milliseconds passed), but in a frame based game, the unit of step is based on frame units (i.e. the number of frames passed).
For our game we are going to use a frame based counter. We’ll have a counter which we’ll increment by one in the game loop, which runs each frame, and so will basically give us the number of frames which have passed since the game started. Go ahead and declare a variable after the other variable declarations in the Main class:
private var ghost_turret:Turret;
private var turrets:Array = [];
private var bullets:Array = [];
private var global_time:Number = 0;
We increment this variable in the game loop at the top:
global_time++;
Now based on this counter we can do stuff like creating enemies, which we’ll do next.
Step 8: Let’s Create Some Enemies
What we want to do now is create enemies on the field after every two seconds. But we are dealing with frames here, remember? So after how many frames should we create enemies? Well, our game is running at 30 FPS, thus incrementing the global_time counter 30 times each second. A simple calculation tells us that 3 seconds = 90 frames.
At the end of the game loop add the following if block:
if (global_time % 90 == 0) {
}
What is that condition about? We use the modulo (%) operator, which gives the remainder of a division – so global_time % 90 gives us the remainder when global_time is divided by 90. We check whether the remainder is 0, as this will only be the case when global_time is a multiple of 90 – that is, the condition returns true when global_time equals 0, 90, 180 and so on… This way, we achieve a trigger at every 90 frames or 3 seconds.
Before we create the enemy, declare another array called enemies just below the turrets and bullets array. This will be used to store references to enemies on the stage.
private var ghost_turret:Turret;
private var turrets:Array = [];
private var bullets:Array = [];
private var enemies:Array = [];
private var global_time:Number = 0;
Also declare an enemy variable at the top of the game loop:
global_time++;
var turret:Turret;
var bullet:Bullet;
var enemy:Enemy;
Finally add the following code inside the if block we created earlier:
enemy = new Enemy();
enemy.x = 410;
enemy.y = 30 + Math.random() * 370;
enemies.push(enemy);
addChild(enemy);
Here we create a new enemy, position it randomly at the right of the stage, push it in the enemies array and add it to the stage.
Step 9: Updating the Enemies
Just like we update the bullets in the game loop, we update the enemies. Put the following code below the turret for...each loop:
for (var j:int = enemies.length - 1; j >= 0; j--) {
enemy = enemies[j];
enemy.update();
if (enemy.x < 0) {
enemies.splice(j, 1);
enemy.parent.removeChild(enemy);
continue;
}
}
Just like we did a boundary check for bullets, we check for enemies too. But for enemies we just check whether they went out of the left side of the stage, as they only move right-to-left. You should see enemies coming from the right if you run the game now.
Step 10: Give the Enemies Some Health
Every enemy has some life/health and so will ours. We will also show the remaining health on the enemies. Lets declare some variables in the Enemy class for the health stuff:
private var health_txt:TextField;
private var health:int;
private var speed_x:Number;
private var speed_y:Number;
We initialise the health variable in the constructor next. Add the following to the Enemy constructor:
health = 2;
Now we initialize the health text variable to show on the center of enemy. We do so in the draw function:
health_txt = new TextField();
health_txt.height = 20; health_txt.width = 15;
health_txt.textColor = 0xffffff;
health_txt.x = -5;
health_txt.y = -8;
health_txt.text = health + "";
addChild(health_txt);
All we do is create a new TextField, set its color, position it and set its text to the current value of health Finally we add a function to update the enemy’s health:
public function updateHealth(amount:int):int {
health += amount;
health_txt.text = health + "";
return health;
}
The function accepts an integer to add to the health, updates the health text, and returns the final health. We’ll call this function from our game loop to update each enemy’s health and detect whether it’s still alive.
Step 11: Shooting the Enemies.
First lets modify our shoot function a bit. Replace the existing shoot function with the folowing:
private function shoot(turret:Turret, enemy:Enemy):void {
var angle:Number = Math.atan2(enemy.y - turret.y, enemy.x - turret.x) / Math.PI * 180;
turret.rotation = angle;
var new_bullet:Bullet = new Bullet(angle);
new_bullet.x = turret.x + Math.cos(turret.rotation * Math.PI / 180) * 25;
new_bullet.y = turret.y + Math.sin(turret.rotation * Math.PI / 180) * 25;
bullets.push(new_bullet);
addChild(new_bullet);
}
The shoot function now accept two parameters. The first is a reference to a turret which will do the shooting; the second is a reference to a enemy towards which it will shoot.
The new code here is similar to the one present in the Turret class’s update function, but instead of the mouse’s position we now use the enemy’s cordinates. So now you can remove all the code from the update function of the Turret class.
Now how to make the turrets shoot at enemies? Well the logic is simple for our game. We make all the turrets shoot the first enemy in the enemies array. What? Lets put some code and then try to understand. Add up following lines in the end of the for...each loop used to update the turrets:
for each(turret in turrets) {
turret.update();
for each(enemy in enemies) {
shoot(turret, enemy);
break;
}
}
For every turret we now update it, then iterate the enemies array, shoot the first enemy in the array and break from the loop. So essentially each turret shoots at the earliest created enemy as it is always at the beginning of the array. Try running the game and you should see turrets shooting the enemies.
But wait, what’s that bullet stream flowing? Looks like they are shooting too fast. Lets see why.
Step 12: Turrets Are Shooting Too Fast
As we know, the game loop runs every frame i.e. 30 times a second in our case, so the shooting statement we added in the previous step gets called at the speed of our game loop and hence we see a stream of bullets flowing. Looks like we need a timing mechanism inside the turrets too. Switch over to the Turret class and add the following code:
private var local_time:Number = 0;
private var reload_time:int;
local_time: Our counter is called local_time in contrast to the global_time in the Main class. This is for two reasons: first, because this variable is local to the Turret class; second, because it doesn’t always go forward like our global_time variable – it will reset many times during the course of the game.
reload_time: This is the time required by the turret to reload after shooting a bullets. Basically its the time difference between two bullet shoots by a turret. Remember all time units in our game are in terms of frames.
Increment the local_time variable in the update function and initialize the reload_time in the constructor:
public function update():void {
local_time++;
}
public function Turret() {
reload_time = 30;
draw();
}
Next add the following two functions at the end of the Turret class:
public function isReady():Boolean {
return local_time > reload_time;
}
public function reset():void {
local_time = 0;
}
isReady returns true only when the current local_time is greater than the reload_time, i.e. when the turret has reloaded. And the reset function simply resets the local_time variable, to start it reloading again.
Now back in the Main class, modify the shoot code in the game loop we added in the previous step to the following:
for each(turret in turrets) {
turret.update();
if (!turret.isReady()) continue;
for each(enemy in enemies) {
shoot(turret, enemy);
turret.reset();
break;
}
}
So if now the turret isn’t ready (isReady() returns false), we continue with the next iteration of the turret loop. You will see that the turrets fire at an interval of 30 frames or 1 second now. Cool!
Step 13: Limit the Turret Range
Still something not right. The turrets shoot at enemies irrespective of the distance between them. What’s missing here is the range of a turret. Each turret should have its own range inside which its can shoot an enemy. Add another variable to the Turret class called range and set it to 120 inside the constructor:
private var reload_time:int;
private var local_time:Number = 0;
private var range:int;
public function Turret() {
reload_time = 30;
range = 120;
draw();
}
Also add a function called canShoot at the end of the class:
public function canShoot(enemy:Enemy):Boolean {
var dx:Number = enemy.x - x;
var dy:Number = enemy.y - y;
if (Math.sqrt(dx * dx + dy * dy) <= range) return true;
else return false;
}
Every turret can shoot an enemy only when it meets certain criteria – for example, you could let the turret shoot only red enemies with less than half their life and not more than 30px away. All such logic to determine whether the turret is able to shoot an enemy or not will go in the canShoot function, which returns true or false according to the logic.
Our logic is simple. If the enemy is within the range return true; otherwise return false. So when the distance between the turret and enemy (Math.sqrt(dx * dx + dy * dy)) is less than or equal to range, it returns true. A little more modification in the shoot section of the game loop:
for each(turret in turrets) {
turret.update();
if (!turret.isReady()) continue;
for each(enemy in enemies) {
if (turret.canShoot(enemy)) {
shoot(turret, enemy);
turret.reset();
break;
}
}
}
Now only if the enemy is within the range of the turret, will the turret shoot.
Step 14: Collision Detection
A very important part of every game is the collision detection. In our game collision check is done between bullets and enemies. We will be adding the collision detection code inside the for...each loop which updates the bullets in the game loop.
The logic is simple. For every bullet we traverse the enemies array and check if there’s a collision between them. If so, we remove the bullet, update the enemy health and break out of the loop to check other enemies. Let’s add some code:
for (i = bullets.length - 1; i >= 0; i--) {
bullet = bullets[i];
// if the bullet isn't defined, continue with the next iteration
if (!bullet) continue;
bullet.update();
if (bullet.x < 0 || bullet.x > stage.stageWidth || bullet.y < 0 || bullet.y > stage.stageHeight) {
bullets.splice(i, 1);
bullet.parent.removeChild(bullet);
continue;
}
for (var k:int = enemies.length - 1; k >= 0; k--) {
enemy = enemies[k];
if (bullet.hitTestObject(enemy)) {
bullets.splice(i, 1);
bullet.parent.removeChild(bullet);
if (enemy.updateHealth(-1) == 0) {
enemies.splice(k, 1);
enemy.parent.removeChild(enemy);
}
break;
}
}
}
We use ActionScript’s hitTestObject function to check for collision between the bullet and enemy. If the collsion occurs, the bullet is removed in the same way as when it leaves the stage. The enemy’s health is then updated using the updateHealth method, to which bullet‘s damage property is passed. If the updateHealth function returns an integer less than or equal to 0, this means the enemy is dead and so we remove it in the same way as the bullet.
And our collision detection is done!
Step 15: Why Reverse the “For” Loops?
Remember that we traverse the enemies and bullets in reverse in our game loop. Let’s understand why. Let suppose we used an ascending for loop. We are on index i=3 and we remove a bullet from the array. On removal of the item at position 3, its space is filled by the item then at position 4. So now the item previously at position 4 is at 3. After the iteration i increments by 1 and becomes 4 and so item at position 4 is checked.
Oops, you see what happened just now? We just missed the item now at position 3 which shifted back as the result of splicing. And so we use a reverse for loop which removes this problem. You can see why.
Step 16: Displaying the Turret’s Range
Let’s add some extra stuff to make the game look good. We’ll add functionality to display a turret’s range when the mouse is hovered on it. Switch over to the Turret class and add some variables to it:
private var range:int;
private var reload_time:int;
private var local_time:Number = 0;
private var body:Sprite;
private var range_circle:Sprite;
Next update the draw function to the following:
private function draw():void {
range_circle = new Sprite();
g = range_circle.graphics;
g.beginFill(0x00D700);
g.drawCircle(0, 0, range);
g.endFill();
range_circle.alpha = 0.2;
range_circle.visible = false;
addChild(range_circle);
body = new Sprite();
var g:Graphics = body.graphics;
g.beginFill(0xD7D700);
g.drawCircle(0, 0, 20);
g.beginFill(0x800000);
g.drawRect(0, -5, 25, 10);
g.endFill();
addChild(body);
}
We break the graphics of the turret into two parts: the body and the range graphic. We do this so as to give an ordering to the different parts of the turret. Here we require the range_circle to be behind the turret’s body, and so we add it first to the stage. Finally, we add two mouse listeners to toggle the range graphic:
private function onMouseOver(e:MouseEvent):void {
range_circle.visible = true;
}
private function onMouseOut(e:MouseEvent):void {
range_circle.visible = false;
}
Now attach the listeners to the respective events at the end of the constructor:
body.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver);
body.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
If you run the game and try to deploy a turret, you will see a flickering when hovering on the placeholders. Why is that?
Step 17: Removing the Flicker
Remember we set the mouseEnabled property of the ghost turret to false? We did that because, the ghost turret was capturing mouse events by coming in between the mouse and the placeholder. The same situation has arrived again as the turret itself has two children now – its body and the range sprite – which are capturing the mouse events in between.
The solution is the same. We can set their individual mouseEnabled properties to false. But a better solution is to set the ghost turret’s mouseChildren property to false. What this does is restrict all the children of ghost turret from receiving mouse events. Neat, huh? Go ahead and set it to false in the Main constructor:
ghost_turret = new Turret();
ghost_turret.alpha = 0.5;
ghost_turret.mouseEnabled = false;
ghost_turret.mouseChildren = false;
ghost_turret.visible = false;
addChild(ghost_turret);
Problem solved.
Step 18: What Next?
We could extend this demo to include much more advanced features and turn it into a playable game. Some of which could be:
- Better AI logic for selecting and shooting enemies.
- Different type of turrets, bullets and enemies in the game.
- Complex enemy paths instead of straight lines.
Let’s see what you can come up with from this basic demo. I’ll be glad to hear about you tower defense games, and your comments or suggestions for the series.



View full post on Activetuts+
Feb 23, 2012
Posted on Feb 23, 2012 in Hints and Tips | 10 comments
In the previous tutorial, we went through the basics of pixel-level collision detection. In this tutorial, we shall explore the use of matrices in better defining the area of interest – very useful for graphics that have been rotated, translated, or skewed.
Collision Detection
This is the final piece we will try to progam. Click on the ball and hook to start the interactive demo.
Notice how, despite the coconut tree graphic rotating and being otherwise transformed, we still have pixel-perfect collision detection.
Step 1: The draw Function
Performing pixel-level collision detection requires the graphic to be cast to a BitmapData object. We have looked at this in the previous tutorial by using the analogy of an x-ray. In this tutorial, I shall explain this “x-ray”-ing process.
Suppose we have a piece of a graphic (diagram 1) and wanted to cast it to a BitmapData object; we need to define the dimensions of the BitmapData object first (diagram 2). In this case, it’s quite simple because the graphic’s width and height properties provide this. Then we call the draw() method; pixels that are at least half-occupied by the graphic will be filled up, in theory (diagram 3). This array of pixels will be compared against yet another array of pixels from another graphic to check for a collision between the two (diagram 4).
Step 2: Different Coordinate Spaces
There are different coordinate spaces used in Flash IDE (diagrams 1 and 2 above). I’m sure every reader would have experienced this – see my tutorial on affine spaces for a more detailed look.
In the Flash IDE, we draw an image and turn it into a symbol of type MovieClip. When we double click on the MovieClip, we arrive at a different coordinate space (diagram 3). From here, we can click on the stage label to exit this graphic’s local coordinate space and arrive at the stage’s coordinate space. Then we can start to transform the instance of MovieClip on the stage (diagram 4). In fact we can create multiple instances of the MovieClip, each of them having different transformations.
In the Library, the original graphic remains unchanged despite all the tweaks done upon its copies on the stage. This is rational because whenever we make a new copy of a MovieClip on stage, they are always the same as the original copy in the library. Now the question is, “How does Flash capture all the transformation we’ve done to the copies on the stage?” Well, they each use the MovieClip.transform.matrix property to capture all your transformations (translation, rotation, skew, etc).
Now let’s fall back to where we left off. It is crucial that we understand this because the draw() method of BitmapData does not refer to the graphic instance on the stage when performing an “x-ray”, but rather to the unchanged graphic source in the library.
The BitmapData object’s first pixel aligns with the registration point (the red dot) of the MovieClip on the local coordinate space (refer to diagram 3 in Step 1), then captures the graphic in pixel form with the dimensions we specify.
When it comes to hitTest checks, ActionScript aligns this first pixel (the top-left pixel) of the BitmapData object with the registration point of the graphic instance on the stage. With this, all pixels in the BitmapData object will be mapped onto the coordinate space on the stage and obtain their individual coordinates. Checks can later be performed by comparing these coordinates between two bitmaps to see if any pixels overlap.
Note: This explanation assumes the MovieClip or Sprite instance is added to the stage’s display list. In ActionScript, we can actually add display objects to the document class itself because it extends MovieClip or Sprite.
Step 3: The Problem
So if the graphic of interest is rotated on the stage, how do we perform draw()?
From the above diagram, we can clearly see these problems.
| Diagram |
Problem |
Description |
| 1 |
Dimension of BitmapData object |
Since the object orientation has changed, the required dimension of BitmapData cast can no longer be conveniently taken from the width and height properties of the graphic instance. |
| 2 |
Orientation of graphic source |
The instance of the graphic on the stage is rotated, but the one in the library is not. We need to take a snapshot of the transformed graphic source from the library. |
| 3 |
Coordinate of top left pixel (starting pixel) of BitmapData object |
We can’t align the BitmapData object’s first pixel with the registration point of graphic instance. This will be incorrect. |
Step 4: The Solution
To solve these problems, we will first define a rectangle tightly bounding the rotated graphic instance on the stage. ActionScript provisions for this through the getBounds() function. This will solve our first problem. Observe the image below. Notice that there’s a difference between the graphic instance’s registration point and that of the rectangle.
I have included the Flash presentation below to show the rectangular bounding box (red Box) and the local space bounding box (black box)
Step 5: Transformation
Next, we shall bring a snapshot of the transforrmed graphic source into this rectangle on stage. Observe the image below.
We start out having the registration point of the graphic source aligned with that of the rectangular area (diagram 1). Then, we rotate (diagram 2) and offset it (diagram 3) before taking the “x-ray” capture of the image onto the BitmapData object (diagram 4).
We can do this manually, or choose to make a copy of the graphic instance’s transform.matrix property. When using the second approach, we should be careful not to use the transform.matrix translation property – otherwise, the registration points will not align as you see in diagram 1. In both cases, we’ll need to calculate the x and y distance to offset.
Step 6: ActionScript Implementation
After this lengthy explanation, I hope it’s easier to understand the code. I have highlighted the important lines and added comments:
private var coconut:CTree, hk:Hook;
private var bdat1:BitmapData, bdat2:BitmapData;
private var t1:TextField;
private var angle:Number = 45
private var coconutBox:Rectangle;
public function Matrix_Bitmap4()
{
coconut = new CTree(); addChild(coconut);
coconut.rotation = angle;
coconut.x = stage.stageWidth * 0.3; coconut.y = stage.stageHeight * 0.2;
coconutBox = coconut.getBounds(this); //get rectangular box in step 2
var coconut_newX:Number = coconut.x - coconutBox.x //get offset x in step 3
var coconut_newY:Number = coconut.y - coconutBox.y //get offset y in step 3
var m:Matrix = new Matrix();
m.rotate(angle / 180 * Math.PI); //rotate graphic in step 3
//var m:Matrix = coconut.transform.matrix //recommended if many transformation happened.
//m.tx = 0; m.ty = 0; //For this case, its doing the same job as previous line.
m.translate(coconut_newX, coconut_newY); //implement the offset
bdat1 = new BitmapData(coconutBox.width, coconutBox.width, true, 0x00000000);
bdat1.draw(coconut, m);
Also, not to forget to change the location of the first pixel (top left) in BitmapData object to that of the rectangular box
private function check(e:Event):void
{
var closeEnough:Boolean = coconut.hitTestObject(hk)
if(closeEnough){
//var point1:Point = new Point(coconut.x, coconut.y);
//now that we have a different box with different location for starting pixel,
//we should refer to coconutBox as the starting point
var point1:Point = new Point(coconutBox.x, coconutBox.y);
var point2:Point = new Point(hk.x, hk.y);
if (bdat1.hitTest(point1, 1, bdat2, point2, 1)) {
t1.text = "At least one pixel has collided"
}
else {
t1.text = "No collision"
}
}
}
And here’s an example of the work.
Step 7: Constant Update
If the shape of interest, in this case the coconut tree, is constantly transforming (rotating, scaling, shrinking, skewing, etc) then the BitmapData object has to be updated on each frame and this will take some processing. Also, note that I have opted for the alternative approach mentioned in Step 4. Here’s the script to update the x-ray copy of the graphic for each frame:
private function updateBmp():void {
coconutBox = coconut.getBounds(this); //get rectangular box in step 2
var coconut_newX:Number = coconut.x - coconutBox.x //get offset x in step 3
var coconut_newY:Number = coconut.y - coconutBox.y //get offset y in step 3
//var m:Matrix = new Matrix();
//m.rotate(angle / 180 * Math.PI); //rotate graphic in step 3
var m:Matrix = coconut.transform.matrix //recommended if many transformation happened,
m.tx = 0; m.ty = 0; //for this case, its doing the same job as previous line.
m.translate(coconut_newX, coconut_newY); //implement the offset
bdat1 = new BitmapData(coconutBox.width, coconutBox.width, true, 0x00000000);
b = new Bitmap(bdat1); addChild(b);
b.x = stage.stageWidth * 0.3; b.y = stage.stageHeight * 0.2;
bdat1.draw(coconut, m);
}
The following function is performed every frame:
private function check(e:Event):void
{
coconut.rotation += angle; //dynamic changes at runtime
coconut.scaleX +=0.01
var closeEnough:Boolean = coconut.hitTestObject(hk)
if(closeEnough){
updateBmp();
var point1:Point = new Point(coconutBox.x, coconutBox.y);
var point2:Point = new Point(hk.x, hk.y);
if (bdat1.hitTest(point1, 1, bdat2, point2, 1)) {
t1.text = "At least one pixel has collided"
}
else {
t1.text = "No collision"
}
bdat1.dispose();
}
}
And this is the output. Start dragging the hook to see the animation.
Conclusion
I understand this tutorial may not be too quick to read, but it’s crucial to gain a clear understanding of what’s happening. Hope this has been helpful and if you are interested in manipulating this 2×2 matrix more, visit my article on the subject. Thanks.



View full post on Activetuts+
Feb 22, 2012
Posted on Feb 22, 2012 in Hints and Tips | 10 comments
First impressions are very important on a Flash game portal; if your game doesn’t grab the player in the first few seconds, they’ve got plenty of other games to choose from. As the menu is the first point of interface, anything you can do to make it less dull will help. In this tutorial we will create a menu that incorporates swapping depth, smooth roll over effects, and two different transition designs.
Final Result Preview
These are the two designs we will be working towards:
The first design will have the next screens transitioning in from different directions, depending on which option is clicked.
The second design transitions all screens in from the bottom: a more flexible choice if you have more than four options.
Introduction: What Makes It “Active”?
There are two main things that make this menu “active”. The first is the roll over effects on the buttons: regardless of how much they have scaled when you roll out ,they scale down from that particular size (unlike a tween created on the timeline). The second is that the code of the second style is designed to be flexible and easy to extend for your own needs.
Step 1: Setting Up
The first thing we are going to need to create is a new Flash File (ActionScript 3.0). Set its width to 600px, its height to 300px, and the frames per second to 30. The background color can be left as white.
Now save the file; you can name it whatever you please, but I named mine menuBounce.fla.
In the next section we will create the eight MovieClips used in the menu. For reference, here is a list of all the colors used throughout the tutorial:
- White – #FFFFFF (
0xffffff)
- Gold – #E8A317 (
0xe8a317)
- Light Gold – #FBB917 (
0xfbb917)
- Blue – #1569C7 (
0x1569c7)
- Light Blue – #1389FF (
0x1389ff)
- Green – #347235 (
0x347235)
- Light Green – #3E8F1B (
0x3e8f1b)
- Red – #990000 (
0x990000)
- Light Red – #C10202 (
0xc10202)
- Matte Grey – #222222 (
0x222222)
Step 2: Creating the MovieClips
To begin with we’ll create the “backs” (the movie clips that will stand in for actual screens), but before we begin let’s turn on some very useful Flash features.
Right-click the stage and select Grid > Show Grid. By default it will create a 10px by 10px grid across the stage. Next, right-click the stage again and this time select Snapping > Snap to Grid.
Now we can start drawing! Select the Rectangle Tool and draw a 600x300px light gold rectangle. Then select this fill, right-click and choose Convert to Symbol. Name the MovieClip goldBack, set the type to MovieClip and the registration to top-left.
Next right-click the MovieClip and select Duplicate three times to make three more copies of it. Now recolor them with light blue, light green and light red. Then name them blueBack, greenBack and redBack, respectively.
To finish off the backs we should add some sort of text inside each MovieClip: on goldBack write “PLAY”, on blueBack write “INSTRUCTIONS”, on greenBack write “OPTIONS”, and on redBack write “CREDITS”. Once you have written the text I would recommend breaking it apart until it becomes a fill (this removes the need to embed fonts and makes the transition look smoother). Your backs should look similar to the one below:
Now let’s start on the clickable squares! Select the Rectangle Tool and draw a 100x100px light gold square. Select the fill, right-click and Convert to Symbol. Name the MovieClip goldSquare, set the type to MovieClip and the registration to top-left. Now is the time to write text on the square, except this time instead of breaking the text apart leave it for now. Insert a keyframe and change the fill color to gold. Now break apart the text on both frames until they become fills.
Now right-click the MovieClip and choose Duplicate Symbol three times. Then repeat the same process from before for the other three colors, naming the MovieClips blueSquare, greenSquare and redSquare, respectively. Your squares should look similar to the one below:
Step 3: Positioning the MovieClips
Begin by deleting everything off the stage. Then go to Insert > New Symbol. Name it menuBounceMC, set the type to MovieClip, the registration to the top-left and export it as MenuBounceMC.
Now drag all the backs from the library into it and position them in the following way:
- goldBack: (-600,0)
- blueBack: (0,-300)
- greenBack: (0,300)
- redBack: (600, 0)
If you are going to use the one direction design then position all four of the backs at one of those positions. I used (0, 300).
Now drag all of the squares from the library into the MovieClip and positon them in the following way:
- goldSquare: (120,150)
- blueSquare: (240,150)
- greenSquare: (360,150)
- redSquare: (480, 250)
The last thing we have to do before we begin coding is assign the instance names. Set the instance names for the squares as square0, square1, square2, square3, starting from the left. Next set the instance names for the backs according to the corresponding with the square of the same color. So goldBack would get the instance name back0 because the goldSquare has the instance name square0.
Step 4: Setting Up the Classes
Now that we are finished creating and positioning the MovieClips we can begin to set up the two classes that we will use.
First go to your Flash file’s Properties and set its class to MenuBounce; then, create a new ActionScript 3.0 file and save it as MenuBounce.as.
Now copy the following code into it; I will explain it after:
package{
import flash.display.MovieClip;
import flash.events.Event;
public class MenuBounce extends MovieClip{
public var menuBounceMC:MenuBounceMC = new MenuBounceMC();
public function MenuBounce(){
addChild(menuBounceMC);
}
}
}
This is a basic document class to which we’ve added a little extra code that creates an instance of MenuBounceMC and adds it to the stage.
Now create a new ActionScript 3.0 file and save it as MenuBounceMC.as. Now copy the following code into it so we can set it up.
package{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
public class MenuBounceMC extends MovieClip{
public var activeSquare:MovieClip;
public var activeBack:MovieClip;
public var squaresArray:Array = new Array();
public var backsArray:Array = new Array();
public var speed:Number = 20;
public function MenuBounceMC(){
}
}
}
Each variable has a specific purpose:
activeSquare: Which square is being rolled over
activeBack: Which back has been selected to move
squaresArray: An array containing all of the square MovieClips
backsArray: An array containing all of the back MovieClips
speed: How many pixels the backs are moved by every frame
All of those variables have been set, with the exception of topSquare (which is set in other functions) and the arrays. So we must push all of the MovieClips onto the array. Add the following lines inside the constructor:
squaresArray = [square0, square1, square2, square3];
backsArray = [back0, back1, back2, back3];
However this method can be a little bit tedious if you are going to use a high number of MovieClips in the menu – say 50. An alternative would be to create the MovieClips completely through code and push them when you add them to the menu. But for our purpose of using only eight MovieClips it works fine.
The last set of things we need to add to complete the setup is our event listeners, which will trigger all of the transitions and roll over effects. Add these lines below the push() lines.
addEventListener(MouseEvent.MOUSE_OVER, bounceOver);
addEventListener(MouseEvent.MOUSE_OUT, bounceOut);
addEventListener(MouseEvent.CLICK, bounceClick);
addEventListener(Event.ENTER_FRAME, bounceUpdate);
Step 5: Creating the MouseEvent Handlers
Let’s start off by creating the three easier functions:
public function bounceOver(event:MouseEvent):void {
}
public function bounceOut(event:MouseEvent):void {
}
public function bounceClick(event:MouseEvent):void {
}
Inside the bounceOver() function start by adding an if-statement to make sure that no back is currently “active” – that is, transitioning in, transitioning out, or sitting on top:
if(activeBack == null){
}
The remainder of all the code in the bounceOver() function will be written inside that if-statement. Now we figure out whether the object rolled over (the event.target) is a square, by checking whether it’s in the squaresArray[]:
if(squaresArray.indexOf(event.target) != -1){
}
Assuming it is, we do real meat of the function:
activeSquare = event.target as MovieClip;
activeSquare.gotoAndStop(2);
setChildIndex(activeSquare, numChildren - 1);
First we set the variable activeSquare to point to the square in question. After that, we pause this square’s animation on the second frame, which displays its “rollover” image. Lastly we move the sprite to be on top of everything else, using setChildIndex().
We now move into the bounceOut() function. This time, we start by checking whether the object from which the mouse is being rolled out is the currently active square:
if(event.target == activeSquare){
}
Inside the if-block add the following code; it pauses the square’s animation on the first frame again, and then sets activeSquare back to null so that we can roll over another:
activeSquare.gotoAndStop(1);
activeSquare = null;
Then go to the bounceClick() function. This function will be used to initiate all the transitions. Start off by checking whether there’s already an active back:
if(activeBack == null){
}
This prevents the user from clicking another square during a transition. If there is an active back, then a click should undo this, so that we can click another square:
if(activeBack == null){
}else{
activeBack = null;
}
Assuming there’s no currently active back, once again add an if-block to check whether the object clicked was a square:
if(activeBack == null){
if(squaresArray.indexOf(event.target) != -1){
}
}else{
activeBack = null;
}
If the user did click a square, we must set the corresponding back as the “active” back. Since the index of each item in backsArray[] matches the index of each item in squaresArray, this is simple:
if(activeBack == null){
if(squaresArray.indexOf(event.target) != -1){
activeBack = backsArray[squaresArray.indexOf(event.target)] as MovieClip;
}
}else{
activeBack = null;
}
Now we just need to move the currently active back so that it is on top of everything else:
if(activeBack == null){
if(squaresArray.indexOf(event.target) != -1){
activeBack = backsArray[squaresArray.indexOf(event.target)] as MovieClip;
setChildIndex(activeBack, numChildren - 1);
}
}else{
activeBack = null;
}
Step 6: Creating the Final Event Handler
This is the last function we are going to create. Let’s begin by adding the scaling effect for when a square is rolled over or out:
public function bounceUpdate(event:Event):void {
for each (var square in squaresArray) {
if(square == activeSquare){
if(square.scaleX <= 1.5){
square.scaleX +=0.05;
square.scaleY +=0.05;
}
}else{
if(square.scaleX >= 1){
square.scaleX -=0.05;
square.scaleY -=0.05;
}
}
}
}
Here, we’ve created a for-each loop to cycle through every square in the array and check whether it’s the currently active square. If it is, we scale it up until it is greater or equal to 1.5 times its regular size ; if it’s not, we scale it down until it’s back at its regular size. (Technically, this code could allow it to be very slightly smaller than its regular size, but this is unnoticeable in practice.)
Now this is where some of you will go your seperate ways; if you are creating Design 1 go to Step 7a, and if you are creating Design 2 go to Step 7b.
Step 7a: Finishing Design 1
Congratulations you have chosen design 1! This design is simple and easy to follow – assuming you have exactly four squares and backs. Any more, and it becomes a mess to maintain.
We’re going to use a long series of nested if-else statements – very messy, I know. But let me tell you the reasoning behind this! Each back has a different starting position and transition direction. In a nutshell, you can’t use a single for-loop to move all the MovieClips unless you have one if statement to check which back is moving, another to set the axis of movement (x or y), and a third to set the speed (positive or negative). Okay, we could store all this information in properties of the squares or something like that, but I think this is one approach where “Keep It Simple, Stupid” applies.
if(activeBack == back0){
if(back0.x < 0){
back0.x += speed;
}
}else{
if(back0.x > -600){
back0.x -= speed;
}
}
if(activeBack == back1){
if(back1.y < 0){
back1.y += speed;
}
}else{
if(back1.y > -300){
back1.y -= speed;
}
}
if(activeBack == back2){
if(back2.y > 0){
back2.y -= speed;
}
}else{
if(back2.y < 300){
back2.y += speed;
}
}
if(activeBack == back3){
if(back3.x > 0){
back3.x -= speed;
}
}else{
if(back3.x < 600){
back3.x += speed;
}
}
The code’s easy to understand; it looks at each back and moves it onto the stage or off the stage, in the correct direction, depending on whether or not it’s active.
Step 7b: Finishing Design 2
Congratulations you have chosen Design 2! This design is far more flexibile and makes things a lot easier in terms of adding more backs and using less code. For this design we will use another for-each loop to examine each back in the backsArray:
for each (var back in backsArray){
if(back == activeBack){
if(back.y > 0){
back.y -= speed;
}
}else{
if(back.y < 300){
back.y += speed;
}
}
}
Now this should be pretty easy to understand. It cycles through the backs and checks each to see whether it’s active. If it is, the code moves it upwards onto the stage, and stops moving it once it is completely on (i.e. once it’s at y=0 or higher). If the back isn’t active, the code moves it back down until it reaches its starting position.
Conclusion
Here’s a challenge: given 16 squares (and 16 backs), can you make it so that Squares 1, 5, 9, and 13 make the corresponding backs transition in from the left, Squares 2, 6, 10, and 14 make them transition in from the top, and so on? You’ll need to combine the two approaches, as well as check the position of the active square/back in its array.
Thanks for taking the time to read through this tutorial. I hope you enjoyed the finished product and learned something about making active, flexible menus!



View full post on Activetuts+
Feb 22, 2012
Posted on Feb 22, 2012 in Hints and Tips | 10 comments
Memory usage is an aspect of development that you really have to be careful about, or it might end up slowing down your app, taking up a lot of memory or even crashing everything. This tutorial will help you to avoid those bad potential outcomes!
Final Result Preview
Let’s take a look at the final result we will be working towards:
Click anywhere on the stage to create a firework effect, and keep an eye on the memory profiler in the top-left corner.
Step 1: Introduction
If you have ever profiled your application using any profiling tool or used any code or library that tells you the current memory usage of your application, you may have noticed that many times the memory usage goes up, and then goes down again (if you haven’t, your code is superb!). Well, although these spikes caused by big memory usage look kinda cool, it’s not good news for either your application or (consequently) your users. Keep reading to understand why this happens and how to avoid it.
Step 2: Good and Bad Usage
The image below is a really great example of poor memory management. It’s from a prototype of a game. You must notice two important things: the big spikes on memory usage and the memory usage peak. The peak is almost at 540Mb! That means this prototype alone reached the point of using 540Mb of the user’s computer RAM – and that is something you definitely want to avoid.
This problem begins when you start creating a lot of object instances in your application. Unused instances will keep using your application’s memory until the garbage collector runs, when they get deallocated – causing the big spikes. An even worse situation happens when the instances simply won’t get deallocated, causing your application’s memory usage to keep growing until something crashes or breaks. If you want to know more about the latter problem and how to avoid it, read this Quick Tip about garbage collection.
In this tutorial we will not address any garbage collector issues. We’ll instead work on building structures that efficiently keep objects in the memory, making its usage completely stable and thus keeping the garbage collector from cleaning up memory, making the application faster. Take a look at the memory usage of the same prototype above, but this time optimized with the techniques shown here:
All this improvement can be achieved using object pooling. Read on to understand what it is and how it works.
Step 3: Types of Pools
Object pooling is a technique wherein a pre-defined number of objects are created when the application is initialized, and kept in the memory during the entire application lifetime. The object pool gives objects when the application requests them, and resets the objects back to the initial state when the application is finished using them. There are many types of object pools, but we will only take a look at two of them: the static and the dynamic object pools.
The static object pool creates a defined number of objects and only keeps that amount of objects during the entire application life time. If an object is requested but the pool has already given all its objects, the pool returns null. When using this kind of pool, it is necessary to address issues such as requesting an object and getting nothing back.
The dynamic object pool also creates a defined number of objects on initialization, but when an object is requested and the pool is empty, the pool creates another instance automatically and returns that object, increasing the pool size and adding the new object to it.
In this tutorial we will build a simple application that generates particles when the user clicks on the screen. These particles will have a finite lifetime, and then will be removed from the screen and returned to the pool. In order to do that, we will first create this application without object pooling and check the memory usage, and then implement the object pool and compare the memory usage to before.
Step 4: Initial Application
Open FlashDevelop (see this guide) and create a new AS3 project. We will use a simple small colored square as the particle image, which will be drawn with code and will move according to a random angle. Create a new class called Particle that extends Sprite. I’ll assume that you can handle the creation of a particle, and just highlight the aspects that will keep track of the particle’s lifetime and removal from screen. You can grab the full source code of this tutorial on the top of the page if you’re having trouble creating the particle.
private var _lifeTime:int;
public function update(timePassed:uint):void
{
// Making the particle move
x += Math.cos(_angle) * _speed * timePassed / 1000;
y += Math.sin(_angle) * _speed * timePassed / 1000;
// Small easing to make movement look pretty
_speed -= 120 * timePassed / 1000;
// Taking care of lifetime and removal
_lifeTime -= timePassed;
if (_lifeTime <= 0)
{
parent.removeChild(this);
}
}
The code above is the code responsible for the particle’s removal from the screen. We create a variable called _lifeTime to contain the number of miliseconds that the particle will be on the screen. We initialize by default its value to 1000 on the constructor. The update() function is called every frame and receives the amount of miliseconds that passed between frames, so that it can decrease the particle’s lifetime value. When this value reaches 0 or less, the particle automatically asks its parent to remove it from the screen. The rest of the code takes care of the particle’s movement.
Now we’ll make a bunch of these be created when a mouse click is detected. Go to Main.as:
private var _oldTime:uint;
private var _elapsed:uint;
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.addEventListener(MouseEvent.CLICK, createParticles);
addEventListener(Event.ENTER_FRAME, updateParticles);
_oldTime = getTimer();
}
private function updateParticles(e:Event):void
{
_elapsed = getTimer() - _oldTime;
_oldTime += _elapsed;
for (var i:int = 0; i < numChildren; i++)
{
if (getChildAt(i) is Particle)
{
Particle(getChildAt(i)).update(_elapsed);
}
}
}
private function createParticles(e:MouseEvent):void
{
for (var i:int = 0; i < 10; i++)
{
addChild(new Particle(stage.mouseX, stage.mouseY));
}
}
The code for updating the particles should be familiar to you: it’s the roots of a simple time-based loop, commonly used in games. Don’t forget the import statements:
import flash.events.Event;
import flash.events.MouseEvent;
import flash.utils.getTimer;
You can now test your application and profile it using FlashDevelop’s built-in profiler. Click a bunch of times on the screen. Here’s what my memory usage looked like:
I clicked until the garbage collector started to run. The application created over 2000 particles that were collected. Is it starting to look like the memory usage of that prototype? It looks like it, and this is definitely not good. To make profiling easier, we’ll add the utility that was mentioned in the first step. Here’s the code to add in Main.as:
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.addEventListener(MouseEvent.CLICK, createParticles);
addEventListener(Event.ENTER_FRAME, updateParticles);
addChild(new Stats());
_oldTime = getTimer();
}
Don’t forget to import net.hires.debug.Stats and it’s ready to be used!
Step 5: Defining a Poolable Object
The application we built in Step 4 was pretty simple. It featured only a simple particle effect, but created a lot of trouble in the memory. In this step, we will begin working on an object pool in order to fix that problem.
Our first step towards a good solution is to think about how the objects can be pooled without problems. In an object pool, we need to always make sure that the object created is ready for use and that the object returned is completely “isolated” from the rest of the application (i.e. holds no references to other things). In order to force each pooled object to be able to do that, we are going to create an interface. This interface will define two important functions that the object must have: renew() and destroy(). That way, we can always call those methods without worrying about whether or not the object has them (because it will have). This also means that every object we want to pool will need to implement this interface. So here it is:
package
{
public interface IPoolable
{
function get destroyed():Boolean;
function renew():void;
function destroy():void;
}
}
Since our particles will be poolable, we need to make them implement IPoolable. Basically we move all the code from their constructors to the renew() function, and eliminate any external references to the object in the destroy() function. Here’s what it should look like:
/* INTERFACE IPoolable */
public function get destroyed():Boolean
{
return _destroyed;
}
public function renew():void
{
if (!_destroyed)
{
return;
}
_destroyed = false;
graphics.beginFill(uint(Math.random() * 0xFFFFFF), 0.5 + (Math.random() * 0.5));
graphics.drawRect( -1.5, -1.5, 3, 3);
graphics.endFill();
_angle = Math.random() * Math.PI * 2;
_speed = 150; // Pixels per second
_lifeTime = 1000; // Miliseconds
}
public function destroy():void
{
if (_destroyed)
{
return;
}
_destroyed = true;
graphics.clear();
}
The constructor also shouldn’t require any arguments any more. If you want to pass any information to the object, you’ll have to do it through functions now. Due to the way that the renew() function works now, we also need to set _destroyed to true in the constructor so that the function can be run.
With that, we have just adapted our Particle class to behave as an IPoolable. That way, the object pool will be able to create a pool of particles.
Step 6: Starting the Object Pool
It is time now to create a flexible object pool which can pool any object we want. This pool will act a bit like a factory: instead of using the new keyword to create objects you can use, we will instead call a method in the pool that returns to us an object.
For the purposes of simplicity, the object pool will be a Singleton. That way we can access it anywhere within our code. Start by creating a new class called “ObjectPool” and adding the code to make it a Singleton:
package
{
public class ObjectPool
{
private static var _instance:ObjectPool;
private static var _allowInstantiation:Boolean;
public static function get instance():ObjectPool
{
if (!_instance)
{
_allowInstantiation = true;
_instance = new ObjectPool();
_allowInstantiation = false;
}
return _instance;
}
public function ObjectPool()
{
if (!_allowInstantiation)
{
throw new Error("Trying to instantiate a Singleton!");
}
}
}
}
The variable _allowInstantiation is the core of this Singleton implementation: it’s private, so only the own class can modify, and the only place where it should be modified is before creating the first instance of it.
We must now decide how to hold the pools inside this class. Since it will be global (i.e. can pool any object in your application), we need to first come up with a way to always have an unique name for each pool. How to do that? There are many ways, but the best I’ve found so far is to use the objects’ own class names as the pool name. That way, we could have a “Particle” pool, a “Enemy” pool and so on… but there’s another problem. Class names only have to be unique within their packages, so for instance a class “BaseObject” within the “enemies” package and a class “BaseObject” within the “structures” package would be allowed. That would cause problems in the pool.
The idea of using class names as identifiers for the pools is still great, and this is where flash.utils.getQualifiedClassName() comes to help us. Basically this function generates a string with the full class name, including any packages. So now, we can use each object’s qualified class name as the identifier for their respective pools! This is what we will add in the next step.
Step 7: Creating Pools
Now that we have a way to identify pools, it’s time to add the code that creates them. Our object pool should be flexible enough to support both static and dynamic pools (we talked about these in Step 3, remember?). We also need to be able to store the size of each pool and how many active objects there are in each one. A good solution for that is to create a private class with all this information and store all pools within an Object:
package
{
public class ObjectPool
{
private static var _instance:ObjectPool;
private static var _allowInstantiation:Boolean;
private var _pools:Object;
public static function get instance():ObjectPool
{
if (!_instance)
{
_allowInstantiation = true;
_instance = new ObjectPool();
_allowInstantiation = false;
}
return _instance;
}
public function ObjectPool()
{
if (!_allowInstantiation)
{
throw new Error("Trying to instantiate a Singleton!");
}
_pools = {};
}
}
}
class PoolInfo
{
public var items:Vector.<IPoolable>;
public var itemClass:Class;
public var size:uint;
public var active:uint;
public var isDynamic:Boolean;
public function PoolInfo(itemClass:Class, size:uint, isDynamic:Boolean = true)
{
this.itemClass = itemClass;
items = new Vector.<IPoolable>(size, !isDynamic);
this.size = size;
this.isDynamic = isDynamic;
active = 0;
initialize();
}
private function initialize():void
{
for (var i:int = 0; i < size; i++)
{
items[i] = new itemClass();
}
}
}
The code above creates the private class which will contain all the information about a pool. We also created the _pools object to hold all object pools. Below we will create the function that registers a pool in the class:
public function registerPool(objectClass:Class, size:uint = 1, isDynamic:Boolean = true):void
{
if (!(describeType(objectClass).factory.implementsInterface.(@type == "IPoolable").length() > 0))
{
throw new Error("Can't pool something that doesn't implement IPoolable!");
return;
}
var qualifiedName:String = getQualifiedClassName(objectClass);
if (!_pools[qualifiedName])
{
_pools[qualifiedName] = new PoolInfo(objectClass, size, isDynamic);
}
}
This code looks a bit trickier, but don’t panic. It’s all explained here. The first if statement looks really weird. You may have never seen those functions before, so here’s what it does:
- The describeType() function creates a XML containing all the information about the object we passed it.
- In the case of a class, everything about it is contained within the
factory tag.
- Inside that, the XML describes all the interfaces that the class implements with the
implementsInterface tag.
- We do a quick search to see if the
IPoolable interface is among them. If so, then we know we can add that class to the pool, because we will be able to successfully cast it as an IObject.
The code after this check just creates an entry within _pools if one didn’t already exist. After that, the PoolInfo constructor calls the initialize() function within that class, effectively creating the pool with the size we want. It’s now ready to be used!
Step 8: Getting an Object
In the last step we were able to create the function that registers an object pool, but now we need to get an object in order to use it. It’s very straightforward: we get an object if the pool isn’t empty and return it. If the pool is empty, we check whether it’s dynamic; if so, we increase its size, and then create a new object and return it. If not, we return null. (You can also choose to throw an error, but it’s better to just return null and make your code work around this situation when it happens.)
Here’s the getObj() function:
public function getObj(objectClass:Class):IPoolable
{
var qualifiedName:String = getQualifiedClassName(objectClass);
if (!_pools[qualifiedName])
{
throw new Error("Can't get an object from a pool that hasn't been registered!");
return;
}
var returnObj:IPoolable;
if (PoolInfo(_pools[qualifiedName]).active == PoolInfo(_pools[qualifiedName]).size)
{
if (PoolInfo(_pools[qualifiedName]).isDynamic)
{
returnObj = new objectClass();
PoolInfo(_pools[qualifiedName]).size++;
PoolInfo(_pools[qualifiedName]).items.push(returnObj);
}
else
{
return null;
}
}
else
{
returnObj = PoolInfo(_pools[qualifiedName]).items[PoolInfo(_pools[qualifiedName]).active];
returnObj.renew();
}
PoolInfo(_pools[qualifiedName]).active++;
return returnObj;
}
In the function, first we check that the pool actually exists. Assuming that condition is met, we check whether the pool is empty: if it is but it is dynamic, we create a new object and add into the pool. If the pool isn’t dynamic, we stop the code there and just return null. If the pool still has an object, we get the object closest to the beginning of the pool and call renew() on it. This is important: the reason we call renew() on an object that was already in the pool is to guarantee that this object will be given at a “usable” state.
You are probably wondering: why don’t you also use that cool check with describeType() in this function? Well, the answer is simple: describeType() creates an XML every time we call it, so it’s very important to avoid the creation of objects that use a lot of memory and that we can’t control. Besides, only checking to see whether the pool really exists is enough: if the class passed doesn’t implement IPoolable, that means we wouldn’t even be able to create a pool for it. If there isn’t a pool for it, then we definitely catch this case in our if statement at the beginning of the function.
We can now modify our Main class and use the object pool! Check it out:
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
stage.addEventListener(MouseEvent.CLICK, createParticles);
addEventListener(Event.ENTER_FRAME, updateParticles);
_oldTime = getTimer();
ObjectPool.instance.registerPool(Particle, 200, true);
}
private function createParticles(e:MouseEvent):void
{
var tempParticle:Particle;
for (var i:int = 0; i < 10; i++)
{
tempParticle = ObjectPool.instance.getObj(Particle) as Particle;
tempParticle.x = e.stageX;
tempParticle.y = e.stageY;
addChild(tempParticle);
}
}
Hit compile and profile the memory usage! Here’s what I got:
That’s kinda cool, isn’t it?
Step 9: Returning Objects to the Pool
We have successfully implemented an object pool that gives us objects. That’s amazing! But it isn’t over yet. We’re still only getting objects, but never returning them when we don’t need them any more. Time to add a function to return objects inside ObjectPool.as:
public function returnObj(obj:IPoolable):void
{
var qualifiedName:String = getQualifiedClassName(obj);
if (!_pools[qualifiedName])
{
throw new Error("Can't return an object from a pool that hasn't been registered!");
return;
}
var objIndex:int = PoolInfo(_pools[qualifiedName]).items.indexOf(obj);
if (objIndex >= 0)
{
if (!PoolInfo(_pools[qualifiedName]).isDynamic)
{
PoolInfo(_pools[qualifiedName]).items.fixed = false;
}
PoolInfo(_pools[qualifiedName]).items.splice(objIndex, 1);
obj.destroy();
PoolInfo(_pools[qualifiedName]).items.push(obj);
if (!PoolInfo(_pools[qualifiedName]).isDynamic)
{
PoolInfo(_pools[qualifiedName]).items.fixed = true;
}
PoolInfo(_pools[qualifiedName]).active--;
}
}
Let’s go through the function: the first thing is to check whether there’s a pool of the object that was passed. You’re used to that code – the only difference is that now we’re using an object instead of a class to get the qualified name, but that doesn’t change the output).
Next, we get the index of the item in the pool. If it’s not in the pool, we just ignore it. Once we verify that the object is in the pool, we must break the pool at where the object is currently at and reinsert the object at the end of it. And why? Because we’re counting the used objects from the beginning of the pool, we need to reorganize the pool to make all returned and unused objects to be at the end of it. And that’s what we do in this function.
For static object pools, we create a Vector object that has fixed length. Due to that, we can’t splice() it and push() objects back. The workaround to this is to change the fixed property of those Vectors to false, remove the object and add it back at the end, and then change the property back to true. We also need to decrease the number of active objects. After that, we’re done returning the object.
Now that we have created the code to return an object, we can make our particles return themselves to the pool once they reach the end of their lifetimes. Inside Particle.as:
public function update(timePassed:uint):void
{
// Making the particle move
x += Math.cos(_angle) * _speed * timePassed / 1000;
y += Math.sin(_angle) * _speed * timePassed / 1000;
// Small easing to make movement look pretty
_speed -= 120 * timePassed / 1000;
// Taking care of lifetime and removal
_lifeTime -= timePassed;
if (_lifeTime <= 0)
{
parent.removeChild(this);
ObjectPool.instance.returnObj(this);
}
}
Notice that we added a call to ObjectPool.instance.returnObj() in there. That’s what makes the object return itself to the pool. We can now test and profile our app:
And there we go! Stable memory even when hundreds of clicks were made!
Conclusion
You now know how to create and use an object pool to keep your app’s memory usage stable. The class we built built can be used anywhere and it’s really simple to adapt your code to it: at the beginning of your app, create object pools for every kind of object you want to pool, and whenever there is a new keyword (meaning the creation of an instance), replace it with a call to the function that gets an object for you. Don’t forget to implement the methods that the interface IPoolable requires!
Keeping your memory usage stable is really important. It saves you a lot of trouble later in your project when everything starts to fall apart with unrecycled instances still responding to event listeners, objects filling up the memory you have available to use and with the garbage collector running and slowing everything down. A good recommendation is to always use object pooling from now on, and you’ll notice your life will be much easier.
Also notice that although this tutorial was aimed for Flash, the concepts developed in it are global: you can use it on AIR apps, mobile apps and anywhere it fits. Thanks for reading!



View full post on Activetuts+