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+