Keep Your Flash Project’s Memory Usage Stable With Object Pooling
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
factorytag. - Inside that, the XML describes all the interfaces that the class implements with the
implementsInterfacetag. - We do a quick search to see if the
IPoolableinterface 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 anIObject.
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+

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
_lifeTimeto contain the number of miliseconds that the particle will be on the screen. We initialize by default its value to 1000 on the constructor. Theupdate()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:
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.Statsand 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()anddestroy(). 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 therenew()function, and eliminate any external references to the object in thedestroy()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_destroyedtotruein the constructor so that the function can be run.With that, we have just adapted our
Particleclass to behave as anIPoolable. 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
newkeyword 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
_allowInstantiationis 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
_poolsobject 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
ifstatement looks really weird. You may have never seen those functions before, so here’s what it does:factorytag.implementsInterfacetag.IPoolableinterface 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 anIObject.The code after this check just creates an entry within
_poolsif one didn’t already exist. After that, thePoolInfoconstructor calls theinitialize()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 callrenew()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 implementIPoolable, 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 ourifstatement at the beginning of the function.We can now modify our
Mainclass 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
Vectorobject that has fixed length. Due to that, we can’tsplice()it andpush()objects back. The workaround to this is to change thefixedproperty of thoseVectors tofalse, remove the object and add it back at the end, and then change the property back totrue. 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
newkeyword (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 interfaceIPoolablerequires!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!
In today’s (Very) Quick Tip, you’ll learn how to solve the common problem of flickering or tearing. This is a horrible effect in Flash where bitmaps flicker as they are updated, or appear to tear into two images (as in the thumbnail).
What Causes These Issues?
In a nutshell: tearing occurs when Flash draws information from two different frames to the screen at once. In the thumbnail image above, you can see how this might look when panning across an image of a tower; the bottom part of the image is from one frame, while the top half is from the next. When watching this in motion, you would only see it for a fraction of a second at a time, but it would still be noticeable.
This is commonly solved using “V-sync” (vertical synchronization), which stops the video card drawing anything to the screen until the screen’s next refresh cycle. However, Flash has really poor support for V-sync, because the frame rate of Flash Player is different to the desktop’s vertical refresh rate, meaning that objects that have a lot of height will be hit hard by tearing. This is true even if Flash’s frame rate is equal to the desktop vertical refresh rate, as they are still not synchronized.
Now you may be wondering: Why don’t Adobe fix this problem? The reason is that Flash uses a timeline, and changing the frame rate consequently changes the speed of playback. If you made a game or image gallery running at 60 frames per second and the desktop vertical refresh rate was more than 60 frames per second, you would either have slight stuttering (if you left the movie at 60fps), or would have to play the movie back faster to sync with the desktop. For most content, this wouldn’t be recommended at all!
This is a problem game developers have wanted Adobe to fix for a long time but it’s obvious that there are issues with them doing so. So, at the moment, we developers have to come up with creative ways to solve this problem ourselves. There is no easy way to fix it on all computers, but as most monitors have a refresh rate of 59.9 or 60 then you can set the frame rate to 60 to solve it for most users. However, this requires more processing power and could slow your application down.
The best way to solve this at the moment is fairly simple and easy to do. It doesn’t fix the underlying cause, but it does help reduce the amount of tearing as much as possible.
How Can I Reduce Tearing?
Hardware Acceleration Level 1: Direct is the key to helping the tearing problem. This can be set by opening the HTML file where your SWF is embedded and editing the parameters for the Flash object.
The flag you want to set is
wmode: "direct". This line goes in the ‘params’ section of your HTML code. That’s it, that should help dramatically reduce the tearing. If you want to know why, look at Adobe’s page on hardware acceleration. It explains a little about both levels of hardware acceleration. For even more information, check out this in-depth article.Anything Else?
Yes; another thing to mention is that, the more objects you have on the screen, the more obvious the tearing will become. Smaller items are not usually affected by V-sync issues, but items on the screen which are large make it very obvious, so keeping the number of large objects to a minimum is a good idea.
Also, using
bitmapData.lock()andbitmapData.unlock()is recommended and has helped some people with this problem. Locking a BitmapData object stops any bitmaps from being redrawn until it is unlocked, which is a good idea if you need to make multiple changes between frames. To learn more, take a look at this blog post.Conclusion
You can do a few things to help reduce tearing but you cannot eliminate it completely. Reducing the amount of large objects, setting
wmode:"direct"and using bitmap locking are the best ways to help reduce tearing.Premium members: here’s this week’s tutorial. Simple harmonic motion is a type of movement commonly used to describe pendulums and springs. In this tutorial, you’ll learn the concepts behind this type of motion, and understand the many different ways you can apply this in your games: from an animated health warning, to the motion of attacking enemy ships.
Premium Preview
This tutorial focuses mainly on the mathematical formulae behind simple harmonic motion, and on implementing them in ActionScript, and uses a number of different examples to demonstrate how this could be used in games rather than ending up with one main example.
With that said, here’s one of the demos. Click to activate the pendulum, then try to move the green circle through using the arrow keys, without getting hit.
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, which are enough to introduce the main equation and use it to create an oscillating particle..
Tuts+ Premium Membership
We run a Premium membership system which periodically gives members access to extra tutorials, like this one! You’ll also get access to Psd Premium, Vector Premium, Audio Premium, Net Premium, Ae Premium, Cg Premium, Photo Premium, and the new Mobile Premium too. 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.
Inspired by Prof. Wildberger in his lecture series on linear algebra, I intend to implement his mathematical ideas with Flash. We shall not delve into the mathematical manipulation of matrices through linear algebra: just through vectors. This understanding, although diluting the elegance of linear algebra, is enough to launch us into some interesting possibilities of 2×2 matrix manipulation. In particular, we’ll use it to apply various shearing, skewing, flipping, and scaling effects to images at runtime.
Final Result Preview
Let's take a look at the final result we will be working towards. Press the four directional keys – up, down, left, right – to see some effects we can achieve with affine transformations.
If you only use the left and right arrow keys, the fish appears to swim around in a pseudo-3D isometric space.
Step 1: Different Coordinate Spaces
Graphics are drawn onto coordinate spaces. So in order to manipulate them, especially to translate, rotate, scale, reflect and skew graphics, it is vital that we understand coordinate spaces. We generally make use of not just one, but multiple coordinate spaces in a single project – this is true not only for designers using the Flash IDE, but also for programmers writing ActionScript.
In Flash IDE this happens whenever you convert your drawings into MovieClip symbols: each symbol has its own origin.
The image above shows the origin of the stage’ coordinate space (red dot), and that of the symbol’s coordinate space (registration point marked by crosshair). To know which space you are in currently, observe the bar beneath the timeline of Flash IDE as shown by the image below.
(I’m using Flash CS3, so its location may differ for CS4 and CS5.) What I want to emphasize is the existence of different coordinate spaces, and the fact that you’re already familiar with using them.
Step 2: The Rationale
Now there's a good reason for this. We can use one coordinate space as a reference to change the other coordinate space. This may sound alien, so I’ve included the Flash presentation below to facilitate my explanation. Click and drag the red arrows. Play around with it.
In the background is a blue grid, and in the foreground is a red grid. The blue and red arrows are initially aligned along the x- and y-axis of Flash coordinate space, whose center I have shifted to the middle of the stage. The blue grid is a reference grid; the gridlines will not change as you interact with the red arrows. The red grid, on the other hand, can be reoriented and scaled by dragging the red arrows.
Note that the arrows also indicate an important property of these grids. They indicate the notion of a unit of x and a unit of y on their respective grid. There are two red arrows on the red grid. Each of them indicate the length of one unit on the x-axis and the y-axis. They also dictate the orientation of the coordinate space. Let's take the red arrow pointing along the x-axis and extend it to be twice as long as the original arrow (shown in blue). Observe the following images.
We see that the image (the green box) drawn on the red grid is now stretched horizontally, due to the fact that this red grid it is drawn onto is now twice as wide. The point I’m trying to make is rather simple: you can use one coordinate space as a basis to change another coordinate space.
Step 3: Affine Coordinate Space
So what's an “affine coordinate space”? Well, I'm sure you are careful enough to observe that these coordinate spaces are drawn using parallel grids. Let's take the red affine space for example: there's no guarantee that both the x-axis and the y-axis are always perpendicular to each other, but rest assured that however you try to tweak the arrows, you will never arrive at such a case as below.
This coordinate space is not an affine coordinate space.
In fact, x- and y-axes usually refer to the Cartesian coordinate space, as shown below.
Note that the horizontal and vertical grids are perpendicular to each other. Cartesian is a type of affine coordinate space, but we can transform it to other affine spaces as we prefer. The horizontal and vertical grids do not necessarily have to be perpendicular to each other.
Example of an affine coordinate space
Another example of an affine coordinate space
Step 4: Affine Transformations
As you might have guessed, the affine transformations are translation, scaling, reflection, skewing and rotation.
Original affine space
Scaled affine space
Reflected affine space
Skewed affine space
Rotated and scaled affine space
Needless to say, physical properties such as
x, y, scaleX, scaleYandrotationdepend on the space. When we make calls to those properties, we are actually transforming affine coordinates.Step 5: Understanding Matrix
I hope the images shown above are explicit enough to drive home the idea. This is because for a programmer working with FlashDevelop, we will not see those grids that the Flash IDE conveniently displays for designers. All of these have to live in your head.
Apart from imagining these grids, we also need to enlist the help of
Matrixclass. Thus, having a mathematical understanding of matrices is important, so we shall revise the operations of matrix here: addition and multiplication.Step 6: Geometrical Meaning of Matrix Addition
Matrix operations convery meanings geometrically. In other words, you can picture what they mean on a graph. Let's assume that we have four points in our coordinate space and would like to shift them to a set of new locations. This can be done using matrix addition. Check out the image below.
As you can see, we are actually shifting the whole local coordinate space (red grids) where these four points are drawn. The notation for performing these operations is as shown below:
We can also see that this shift can actually be represented using a vector of (tx, ty). Let us differentiate vectors and static points in coordinate spaces by our use of parentheses and square brackets. I've rewritten them in the image below.
Step 7: ActionScript Implementation
Here's a simple implementation of matrix addition. Check out the comments:
public class Addition extends Sprite { public function Addition() { var m:Matrix = new Matrix(); //instantiate matrix m.tx = stage.stageWidth * 0.5; //shift in x m.ty = stage.stageHeight * 0.5; //shift in y var d:DottedBox = new DottedBox(); //create the custom graphic (dotted box is a Sprite) addChild(d); d.transform.matrix = m; //apply the matrix to our graphic } }Step 8: Geometrical Meaning of Matrix Multiplication
Matrix multiplication is somewhat more sophisticated than matrix addition but Prof Wildberger has elegantly broken it down to this simple interpretation. I shall humbly attempt to reiterate his explanation. For those who'd like to dive deeper into the understanding of linear algebra that leads to this, check out the professor's lecture series.
Let's start off by tackling the case of the identity matrix, I.
From the image above we know that multiplying an arbitrary matrix, A, by the identity matrix, I, will always produce A. Here's an analogy: 6 x 1 = 6; the identity matrix is likened to the number 1 in that multiplication.
Alternatively, we can write the result in the following vector format which will greatly simplify our interpretation:
The geometric interpretation of this formula is shown in the image below.
From the Cartesian grid (left grid), we can see the blue point is located at (2, 1). Now if we were to transform this original grid of x and y to a new grid (right grid) according to a set of vectors (below the right grid), the blue point will be relocated to (2, 1) on the new grid – but when we map this back to the original grid, it’s the same point as before.
Because we are transforming the original grid to another grid that shares the same vectors for x and y, we see no difference. In fact, the changes of x and y in this transformation is nil. This is what it meant by identity matrix, from a geometrical point of view.
However, if we try to perform a mapping using other transformations, we shall see some difference. I know this was not the most revealing example to start with, so let's move on to another example.
Step 9: Scaling Along X
Image above demonstrates a scaling of the coordinate space. Check out the vector of x in transformed coordinate space: one unit of the transformed x accounts for two units of the original x. On the transformed coordinate space, the coordinate of the blue point is still (2, 1). However, if you try to map this coordinate from the transformed grid onto the original grid, it is (4, 1).
This whole idea is captured by the image above. How about the formula? The result should be consistent; let's check it out.
I'm sure you recall these formulae. Now, I've added their respective meanings.
Now to check out the numerical result of our scaling example.
They do agree with each other! Now we can happily apply this idea to other transformations. But before that, an ActionScript implementation.
Step 10: ActionScript Implementation
Check out the ActionScript implementation (and the resulting SWF) below. Note that one of the overlapping boxes is being stretched along x by a scale of 2. I have highlighted the important values. These values will be tweaked in the later steps to represent different transformations.
public class Multiplication extends Sprite { public function Multiplication() { var ref:DottedBox = new DottedBox(); //create reference graphic addChild(ref); ref.x = stage.stageWidth * 0.5; ref.y = stage.stageHeight * 0.5; var m:Matrix = new Matrix(); //instantiate matrix m.tx = stage.stageWidth * 0.5; //shift in x m.ty = stage.stageHeight * 0.5; //shift in y m.a = 2; m.c = 0; m.b = 0; m.d = 1; var d:DottedBox = new DottedBox(); //create the custom graphic addChild(d); d.transform.matrix = m //apply the matrix onto our graphic } }Step 11: Scaling X and Y
Here we’ve scaled the grid by a factor of two along both the x- and y-axes. The blue point is at (2, 1) in the original grid before the transformation, and (4, 2) in the original grid after the transformation. (Of course, it’s still at (2, 1) in the new grid after the transformation.)
And to confirm the result numerically…
… they match again! To see this in the ActionScript implementation, just change the value of
m.dfrom 1 to 2.(Note that the direction of stretch from y is downwards, not upwards, because y increments downwards in Flash but upwards in the normal Cartesian coordinate space that I used in the diagram.)
Step 12: Reflection
Here we’ve reflected the grid along the x-axis using these two vectors, so the position of the blue point in the original grid changes from (2, 1) to (-2, 1). The numeric calculation is as follows:
The ActionScript implementation is the same as before, but using these values instead:
m.a = -1, m.b = 0to represent the vector for the x transformation, and:m.c = 0 and m. d = 1to represent the vector for the y transformation.Next, what about reflecting simultaneously on x and y? Check out the image below.
Also, numerically computed in image below.
For the ActionScript implementation… well, I'm sure you know the values to put into the matrix.
m.a = -1, m.b = 0to represent the vector for the x transformation;m.c = 0 and m. d = -1to represent the vector for the y transformation. I've included the final SWF below.Step 13: Skewing and Shearing
Skewing comes with a little fun. For the case of the image below, the transformed grid has had its x-axis reoriented and scaled. Compare the red arrows in both grids below: they are different, but the y-axis remains unchanged.
Skewing
Visually, it seems that distortion happens along the y-direction. This is true because our transformed x-axis now has a y-component in its vector.
Numerically, this is what happens…
In terms of implementation, I've listed the tweaks below.
m.a = 2m.b = 1m.c = 0m.d = 1I'm sure at this point you'd like to try out things yourself, so go ahead and tweak
I have included the Flash output for both cases as below. For readers who'd like some help with these values, check out
Multiplication_final.asin the source download.Step 14: Rotation
I consider rotation a subset of skewing. The only difference is that in rotation, the magnitude of a unit of both x and y-axis is maintained, as is the perpendicularity between the two axes.
ActionScript actually provides a method in the
Matrixclass,rotate(), to do this. But let's go through this anyway.Now we do not want to alter the magnitude of a unit length in x and y from the original grid; just to change the orientation of each. We can make use of trigonometry to arrive at the result shown in the image above. Given an angle of roation, a, we’ll get the desired result by using vectors of (cos a, sin a) for x-axis and (-sin a, cos a) for y-axis. The magnitude for each new axis will still be one unit, but each axis will be at an angle of a, compared to the originals.
For Actionscript implementation, assuming that the angle, a, is 45 degrees (that is, 0.25*Pi radians), just tweak the matrix values to the following:
The full source can be referred to in
Multiplication_final.as.Step 15: Application
Having a vector interpretation of a 2×2 matrix opens up space for us to explore. Its application in manipulating bitmaps (
BitmapData, LineBitmapStyle, LineGradientStyle, etc.) is widespread – but I think I'll save that for another tutorial. For the case of this article, we shall attempt to skew our sprite at run-time so that it looks like it's actually flipping in 3D.View of a pseudo-3D isometric world
From the image above we can see that, in a world with an isometric view, any graphic that's "standing" keeps its y-axis vector unchanged while the x-axis vector is rotates. Note that a unit of length for the x- and y-axis does not change – in other words, no scaling should happen in either axis, just rotation around the x-axis.
Here's an example of this idea in Flash. Click anywhere on the stage and begin dragging around to see the fish skew. Release to stop your interaction.
Here's the important bit of Actionscript. I've highlighted the crucial lines that handle the x-axis rotation. You can also refer to
FakeIso.as.private var f1:Fish, m:Matrix; private var disp:Point; private var axisX:Point, axisY:Point; public function FakeIso() { disp = new Point(stage.stageWidth * 0.5, stage.stageHeight * 0.5); m = new Matrix(); m.tx = disp.x; m.ty = disp.y; //displace to the center of stage f1 = new Fish(); addChild(f1); f1.transform.matrix = m; //apply transformation to onto fish axisX = new Point(1, 0); //vector for x - axis axisY = new Point(0, 1); //vector for y - axis stage.addEventListener(MouseEvent.MOUSE_DOWN, start); //start interaction stage.addEventListener(MouseEvent.MOUSE_UP, end); //end interaction } private function start(e:MouseEvent):void { f1.addEventListener(Event.ENTER_FRAME, update); } private function end(e:MouseEvent):void { f1.removeEventListener(Event.ENTER_FRAME, update); } private function update(e:Event):void { axisX.setTo(mouseX - f1.x, mouseY - f1.y); //determine orientation (but magnitude changed as well) axisX.normalize(1); //fix magnitude of vector with new orientation to 1 unit apply2Matrix(); //apply matrix onto fish } private function apply2Matrix ():void { m.setTo(axisX.x, axisX.y, axisY.x, axisY.y, disp.x, disp.y); f1.transform.matrix = m; }Here, I have used the Point class for storing vectors.
Step 16: Add Keyboard Control
In this step, we shall attempt to add keyboard controls. The fish's location will update according to its velocity,
velo. We’ll define incremental steps for positive (clockwise) rotation and negative (anti-clockwise) rotation as well.Upon a key press,
velowill rotate:private function keyUp(e:KeyboardEvent):void { if (e.keyCode == Keyboard.LEFT) { velo = delta_negative.transformPoint(velo) //rotate velo counter-clockwise } else if (e.keyCode == Keyboard.RIGHT) { velo = delta_positive.transformPoint(velo) //rotate velo clockwise } }Now for each frame, we shall attempt to color the front side of the fish, and skew the fish as well. If the velocity,
velo, has a magnitude of more than 1 and we apply it to the fish's matrix,m, we will get a scaling effect as well – so in order to eliminate this possibility, we shall normalise the velocity and then only apply that to the fish's matrix.private function update(e:Event):void { var front_side:Boolean = velo.x > 0 //checking for the front side of fish if (front_side) { f1.colorBody(0x002233,0.5) } //color the front side of fish else f1.colorBody(0xFFFFFF,0.5) //white applied to back side of fish disp = disp.add(velo); //update current displacement with velocity var velo_norm:Point = velo.clone(); //in case velo > 0, we need to recalculate 1 unit of length for x. velo_norm.normalize(1); //note that x-axis more than 1 will perform scaling. We dont want that for now m.setTo(velo_norm.x, velo_norm.y, axisY.x, axisY.y, disp.x, disp.y); f1.transform.matrix = m; }Step 17: Your Fish
Click the stage, then press the left and right arrow keys to see make the fish change direction.
Step 18: Another Keyboard Control
To spice things up, let us allow the control of the y-axis vector as well.
private function keyUp(e:KeyboardEvent):void { if (e.keyCode == Keyboard.LEFT) { velo = delta_negative.transformPoint(velo) } else if (e.keyCode == Keyboard.RIGHT) { velo = delta_positive.transformPoint(velo) } if (e.keyCode == Keyboard.UP) { axisY = delta_negative.transformPoint(axisY) } else if (e.keyCode == Keyboard.DOWN) { axisY = delta_positive.transformPoint(axisY) } }Also to determine the front side of the fish, we now need to incorporate the y-axis in. Here’s the code for that:
var front_side:Boolean = velo.x * axisY.y > 0 if (front_side) { f1.colorBody(0x002233,0.5) } else f1.colorBody(0xFFFFFF,0.5)Step 19: Your No-So-Regular Fish
Well, for some the result of controlling both axes may prove to be a little confusing, but the point is that you now can skew your fish, translate it, reflect it, and even rotate it! Try out the combos of up + left, up + right, down + left, down + right.
Also, see if you can maintain the “front” side of fish (fish will be grayed). Hint: Tap up continuously, then left, then down, then right. You are making a rotation!
Conclusion
I hope you find matrix math a valuable asset to your projects after reading this article. I'm hoping to write a little more on applications of 2×2 matrix in little Quick Tips branching out of this article, and on
Matrix3dwhich is essential for 3D manipulations. Thanks for the read, terima kasih.In this tutorial you’ll build an extreme particle system whilst learning how to squeeze more efficient goodness out of the Flash Player than you ever thought possible!
December of 2010
Final Result
Here are a couple of examples of what we’ll be working towards:
EPILEPSY WARNING:
Please don’t view this demo if you are likely to suffer from epileptic attacks or loss of consciousness, particularly when looking at some types of strong flashing lights, rapid succession of images, simple geometric shapes, flashes or explosions.
Introduction: What Will You Learn?
Many users, from beginners to advanced, can still be seen using less than efficient Actionscript 3.0. In all likelyhood, this is because the efficient ways are made to sound a bit more difficult and aimed at highly advanced users. This tutorial will show you that these methods can be used by everyone, and they’re more useful than you may think!
The aim of this tutorial is to let you tackle those tasks that require working with a lot of data, very fast, with ease.
Helpful Hint: This tutorial will feature a lot of coding so I recommend using a more user friendly coding interface. I recommend FlashDevelop, it has some of the best code hinting around and best of all, it’s completely free! But I’m sure most of you will just copy and paste if do anything at all
Step 1 Check out That FPS!
At the heart of making all things efficient in the Flash Player is the FPS (Frames Per Second) of your SWF. The proffered target of your SWF can be set in the Flash Professional interface or, a new feature in Actionscript 3.0, you can change the FPS of the stage at runtime.
However, this will only ever get and set the target FPS (what the Flash Player will attempt to play at), which makes it pretty useless for preformance testing. You might think that the lovely folks over at Adobe would made a nice neat way to find you real FPS but, nope. You’ve got to do the math for yourself. Let’s take a look.
FPS can be defined as the time difference between the current frame and the last.
So all we need is some way to track the time difference from this frame to the previous frame of the SWF. This uses the document class feature. If you are unsure how to use this, check out this Quick Tip on how to use a document class.
package { //imports import flash.events.Event; import flash.utils.getTimer; import flash.display.MovieClip; public class FPSCalculator extends MovieClip { //variable to hold the current time private var currentTime:int = 0; public function FPSCalculator() { //add the enter frame listener, this is fired when the SWF updates to a new frame stage.addEventListener(Event.ENTER_FRAME, onFrameLoop); } private function onFrameLoop (evt:Event):void{ //for the sanity of the fellow developers, try to put each task into a seperate function. //this makes it infinitely easier to read for them and yourself on a large project or when you come back to and old one //since the getTimer() function returns the played time in milliseconds and we want FPSecond, we divide it into 1000 var fps:Number = (1000 / timeDifference); trace(fps); } //this is a get function so it can be referenced just like a variable, without the brackets on the end like a normal function private function get timeDifference ():int{ //the getTimer() function returns the total played time of the SWF in milliseconds var totalPlayedTime:int = getTimer(); //The difference in time from the previous frame to this frame will to calculated here var timeDifference:int = (totalPlayedTime - currentTime); //The currentTime is set to the total played time so it is ready for the next frame currentTime = getTimer(); //return the difference in time return timeDifference } } }We will use this function as the benchmark for comparing the efficiency of different methods from here on. As you might have noticed, we use the function to calculate the time difference, not the FPS. This is because tracing the time difference is actually much more useful and easier to read when we get to the speed tests. Calculating the FPS only becomes useful when we are putting everything together at the end.
Tip #1 Arrays vs. Vectors
Have you ever needed to store a whole bunch of numbers, strings or objects in a list? Of course you have! But the question is – have you been doing it right?
If the first thing you think think of when making a list in AS3 is an Array, then this tip is for you. A Vector is exactly the same as an ordinary Array except for one fact, it is a typed Array. This means that you can only populate it with one type of item. For instance, you can put a number and a string in the same Array, but not in a Vector.
Let’s take a look at the only difference between an Array and a Vector, declaring the Vector.
private function Arrayvs.VectorDifferences ():void{ //delare the array and the vector, this is the only difference between the two var myArray:Array = new Array(); var myVector:Vector.<String> = new Vector.<String>; //populate them in the same way myArray.push("this", "is", "an", "Array"); myVector.push("this", "is", "a", "Vector"); //call elements and length in the same way trace( myArray[myArray.length - 1] ); //Array trace( myVector[myVector.length - 1] ); //Vector //The following creates an error - "Access of possibly undefined property x through a reference with static type String." trace( myVector[myVector.length - 1].x ); //The Flash Player casts the movieclip as a string and a string does not have an 'x' value. }As seen above, declaring the vector is the only difference between the two types. To have the Vector hold another object, just replace
Stringwith your object. For holding MovieClips for example:How does this make it more useful? If all the elements in a Vector are the same type then the Flash Player can zip through them much much quicker because it knows what’s coming up and doesn’t have to test the next element every time (this is true even when declaring a variable type, so never leave it out!).
How big is the difference? Surprisingly big actually! Let’s take a look at our first speed test.
Speed Test #1 Array vs. Vector
package { //imports import flash.utils.getTimer; import flash.display.MovieClip; public class Arrayvs.Vector extends MovieClip { private var currentTime:int = 0; //we want to read and write into the array and vector 10,000,000 times. //this will provide a good indication of the speed difference //dont worry, it wont crash you computer but the FLash Player will pause for about 3 to 5 seconds private var n:int = 10000000 //Declare the Array and Vector private var myArray:Array = new Array(); private var myVector:Vector.<int> = new Vector.<int>; public function Arrayvs.Vector() { //time test for writing to the array and vector write(); trace("----"); //time test for reading from the array and vector read(); } private function write ():void{ trace("Writing Times"); timeDifference //for n times, push i into the array for(var i:int = 0; i < n; i++){ myArray.push(i); } //trace the time taken trace("Array: " + timeDifference + "ms"); //for n times push j into the vector for(var j:int = 0; j < n; j++){ myVector.push(j); } //trace the time taken trace("Vector: " + timeDifference + "ms"); } private function read():void{ var num:int = 0; trace("Reading Times"); timeDifference //for n times, set num to the corresponding array value for(var i:int = 0; i < n; i++){ num = myArray[i]; } //trace the time taken trace("Array: "+ timeDifference + "ms"); //for n times, set num to the corresponding vector value for(var j:int = 0; j < n; j++){ num = myVector[j]; } //trace the time taken trace("Vector: " + timeDifference + "ms"); } private function get timeDifference ():int{ var totalPlayedTime:int = getTimer(); var timeDifference:int = (totalPlayedTime - currentTime); currentTime = getTimer(); return timeDifference } private function Arrayvs.VectorDifferences ():void{ //delare the array and the vector, this is the only difference between the two var myArray:Array = new Array(); var myVector:Vector.<String> = new Vector.<String>; //populate them in the same way myArray.push("this", "is", "an", "Array"); myVector.push("this", "is", "a", "Vector"); //call elements and length in the same way trace( myArray[myArray.length - 1] ); //Array trace( myVector[myVector.length - 1] ); //Vector //pushing in a non-string value myVector.push(new MovieClip()); //The following creates an error - "Access of possibly undefined property x through a reference with static type String." //trace( myVector[myVector.length - 1].x ); //The Flash Player casts the movieclip as a string and a string does not have an 'x' value. } } }This outputs the following:
You shouldn’t get exactly the same results as what I have here of course, you will almost never get the same set of values yourself even as this depends on how much effort your CPU can push into this at runtime.
The first pair of values comes from writing into the array and vector respectively. We can see that the Vector shaved off almost 0.6 seconds, quiet a substancial amount if we need to do something similar 24 (standard FPS for flash movies) times a second. After all, 1/24th of a second is just over 0.04 seconds.
An even bigger percentage difference can be found when you are reading from an Array vs. from a Vector, and this is luckily what you will need to do most of the time every frame.
Hopefully, after reading this section you should be comfortable with using Vectors in your projects for that extra kick of efficiency.
Tip #2 Event Listeners
Like all things in Flash, there’s more than one way to solve a problem, Event Listeners are no exception. In this tutorial we will look two methods of attaching the
Event.ENTER_FRAMElistener to your particles.Method #1 One Listener per Particle
The idea behind this approach is that you attach a listener to each of your particles and direct them to a set function. This isn’t ideal for what we have in mind but remember a particle, in terms of programming, doesn’t have to be a single dot. For instance, this method might be preferred when going between Flash based webpages or objects that are treated differently in the listener function. Let’s take a look.
private function createPages():void{ //create 10 webpages for(var i:int = 0; i < 10; i++){ //create a new webpage as a movieclip var webpage:MovieClip = new MovieClip(); //add the listener webpage.addEventListener(Event.ENTER_FRAME, onWebpageLoop); } } private function onWebpageLoop (evt:Event):void{ //all webpages call this function every frame //evt.target is the webpage }Method #2 One Listener to Rule Them All…
The second method is the one that we will be using and the preferred method when dealing with a lot of similar objects. The idea here is to attach a single listener to only one object – usually the stage – which then loops through each of the particles and tells each one what to do on each frame. This method is slightly more complex as we need some way to reference the particles, so we put them into a Vector. Let’s take a look.
private function createPages2():void{ //create 10 webpages for(var i:int = 0; i < 10; i++){ //add a movieclip to the webpagesHolder //reducing the number of variables and steps used increases the speed webpagesHolder.push(new MovieClip()); } //add the listener stage.addEventListener(Event.ENTER_FRAME, onStageLoop); } private function onStageLoop (evt:Event):void{ //called only once when the stage changes frame for(var i:int = 0; i < 10; i++){ //webpageHolder[i] is the webpage } }Speed Test #2 Methods of Using Event Listeners
Unfortunately there is no hard and fast way to accurately check the difference in speed between these two methods because of the inconsistencies of the calling process while using method one (at least not an accurate method that won’t require its own complete tutorial!)
Take my word for it, using method two is far better for use in particle systems because of two major factors:
After reading this section you should now know how to comfortably keep track of and reference many particles. Remember, method one for objects that should treat their listener function differently and method two for many objects that all should be treated in exactly the same or a very similar way in their listener function.
Tip #3 Building Your Particle
The next step towards our complete particle system is building the right particle for ourselves. It might so happen that you’ll need a full MovieClip for each particle, to make use of frames and such, but for us, a MovieClip is a huge overkill. All our particle is is a placeholder for a bunch of values that need to be kept together and relate to each other. This allows us to drastically reduce the size of the class used.
The following is the basic class we can use for our particle.
package { //imports import flash.geom.Vector3D; //notice that the class extends nothing because there is no need public class Particle { //define the Vector3D objects to hold the position and velocity values private var pos:Vector3D = new Vector3D(0, 0, 0); private var vel:Vector3D = new Vector3D(0, 0, 0); public function Particle(stageRect:Rectangle) { } public function update ():void{ //update the position according to the velocity in that direction pos.x += vel.x; pos.y += vel.y; } //the getter methods that will be used to read the position of the particle public function get x ():Number{ return pos.x } public function get y ():Number{ return pos.y } } }Notice that it does not have any base class (i.e. it does not
extendanything) and therefore it is ‘born’ without properties that you might use regularly, for instance the ‘x’ and ‘y’ values. To correct this, we use build our own getter methods to read these values. These values are then passed into a Vector3D object. A Vector3D object is basically a Vector which holds three variables and an optional fourth variable. The difference is that you can reference these values as ‘x’, ‘y’, ‘z’ and ‘w’ respectively, The ‘w’, which is optional, could be used to old a rotation value for example. This makes this type of holder perfect for what we need.(We could even create these properties as public Number variables within the class directly, without using any Vector3D objects at all… but let’s stick with what we’ve got.)
But how exactly does creating our own class help? Let’s make a quick memory test to find out! Remember to save this, your document class and the Particle class in the same destination.
package { //imports import flash.sampler.getSize; import flash.display.MovieClip; public class BuildingYourParticle extends MovieClip { public function BuildingYourParticle() { //simulate 100,000 of the respective object var n:int = 100000 //define the object var p:Particle = new Particle(); var m:MovieClip = new MovieClip(); //use the getSize() method the find the memory used for n of m and p. Convert them to megabyte format var pSizeTotal:Number = (getSize(p) * n) / (1024 * 1024); var mSizeTotal:Number = (getSize(m) * n) / (1024 * 1024); //trace the respective sizes to two decimal places trace("Particle Memory: " + pSizeTotal.toFixed(2) + "mb"); trace("MovieClip Memory: " + mSizeTotal.toFixed(2) + "mb"); } } }This Outputs something like the following:
Speed Test #3 Our Particle vs. Movieclips
As you can see, there is a massive difference between the size of our class and the movieclip. Freeing up all this space allows more space on your RAM and so it allows the whole Flash Player to run quiet a bit faster. How much faster? Let’s take a look at that too! Much of this code is the same as our Array vs. Vector Speed test.
package { //imports import flash.utils.getTimer; import flash.display.MovieClip; public class ParticleSpeedTest extends MovieClip { private var n:int = 100000 private var currentTime:int = 0; //Declare the respective holders private var particleHolder:Vector.<Particle> = new Vector.<Particle>; private var movieclipHolder:Vector.<MovieClip> = new Vector.<MovieClip>; public function ParticleSpeedTest():void { //time test for writing a new particle or movieclip write(); trace("----"); //time test for reading from a particle or movieclip read(); } private function write ():void{ trace("Writing Times"); timeDifference //for n times, push a new particle into the vector for(var i:int = 0; i < n; i++){ particleHolder.push(new Particle()); } //trace the time taken trace("Particle: " + timeDifference + "ms"); //for n times push a new movieclip into the vector for(var j:int = 0; j < n; j++){ movieclipHolder.push(new MovieClip()); } //trace the time taken trace("MovieClip: " + timeDifference + "ms"); } private function read():void{ var num:int = 0; trace("Reading Times"); timeDifference //for n times, set num to the corresponding particle's 'x' value for(var i:int = 0; i < n; i++){ num = particleHolder[i].x; } //trace the time taken trace("Particle: "+ timeDifference + "ms"); //for n times, set num to the corresponding movieclip's 'x' value for(var j:int = 0; j < n; j++){ num = movieclipHolder[j].x; } //trace the time taken trace("MovieClip: " + timeDifference + "ms"); } private function get timeDifference ():int{ var totalPlayedTime:int = getTimer(); var timeDifference:int = (totalPlayedTime - currentTime); currentTime = getTimer(); return timeDifference } } }This should output something similar to the following:
As you can see from these results the real difference is in the writing times; this is because the Flash Player has to draw on more resources (the base classes of the MovieClip and each subsequent object) to complete this. In our main project this isn’t any real issue since we only need to create new Particles at the beginning but we will see an example later on when pushing new Particles in all the time becomes necessary. The difference in reading times is almost neglectable since both classes use their getters for the ‘x’ property in the same way.
After reading this section you should be comfortable with building your base class for your particle’s needs.
Tip #4 Introduction to Bitmaps
Bitmaps, and their partner in crime BitmapData, are usually some of the two most confusing steps for a beginner, mainly because what they are generally used for is higher level stuff. Here I will give a short introduction on some of the basic and most used methods regarding the Bitmap and BitmapData classes.
What are They?
In the quickest explanation possible:
Basically, the Bitmap class displays what the BitmapData class tells it to. They go hand in hand practically always.
Drawing with Bitmaps
The BitmapData class does not have a
graphicsproperty of its own, yet it remains one of the most important classes for Flash graphics! How? It draws the shapes of other classes. Let’s take a look at how to draw a simple circle using Bitmaps and BitmapData.public function SimpleCircle():void { //define the radius of the circle var radius:int = 30; //draw a circle the normal way. Notice that you do not add the shape that is to be drawn to the display list var circleShape:MovieClip = new MovieClip(); circleShape.graphics.beginFill(0x555555, 1); circleShape.graphics.drawCircle(radius, radius, radius); circleShape.graphics.endFill(); //create the bitmap and add it to the display list var bmd:BitmapData = new BitmapData(radius * 2, radius * 2, true); var bm:Bitmap = new Bitmap(bmd); stage.addChild(bm); //draw the shape bmd.draw(circleShape); }This results in a simple grey circle touching the top left corners of the stage when run. The draw() method is simply a snapshot of the movieclip at that time so in theory we could move the circleShape object around an continue to draw it to give the effect of many circles. This is how a lot of drawing within bitmaps is done.
The setPixel() Method
Because at the base of all graphics are raw pixels, this method becomes very important for creating effects using the Bitmap and BitmapData classes. It allows you to change to color of a pixel inside the BitmapData area. Heres how that’s done.
package { //imports import flash.events.Event; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.MovieClip; public class SetPixelMethod extends MovieClip { //define variables private var n:int = 50; private var w:int; private var h:int; private var bm:Bitmap private var bmd:BitmapData; public function SetPixelMethod ():void { w = stage.stageWidth; h = stage.stageHeight; //create the bitmap data the width and height of the stage that is not transparent and grey in color bmd = new BitmapData(w, h, false, 0x222222); bm = new Bitmap(bmd); addChild(bm); addEventListener(Event.ENTER_FRAME, onFrameLoop); } private function onFrameLoop (evt:Event):void { for (var i:int = 0; i < n; i++ ) { //randomly pick the x,y coordinates to set the new pixel color var px:int = Math.random() * bmd.width; var py:int = Math.random() * bmd.height; //give the pixel a random color var pc:uint = Math.random() * 0xffffff; //set the pixel at (px,py) to that color bmd.setPixel(px, py, pc); } } } }You should end up with something that looks like this, with more dots appearing on every frame:
This is the graphics style we will use for our system. Don’t worry if it looks kinda terrible right now, at the end you’ll see how we can make these look much better with a whole bunch of effects.
The lock() and unlock() methods
These methods are some of the least used but most helpful regarding bitmap. In fact I would have never known about there existence if it wasn’t for a great little site called WonderFl where members regularly boast massive particle systems, the truth is that these were the inspiration of this tutorial!
You might be hard pushed to find a similar set of methods to use together, this is how they work:
public function LockUnlockMethods ():void { //Draw a basic circle, same in steps before this var radius:int = 30; var circleShape:MovieClip = new MovieClip(); circleShape.graphics.beginFill(0x555555, 1); circleShape.graphics.drawCircle(radius, radius, radius); circleShape.graphics.endFill(); //create the bitmap/bitmapdata var bmd:BitmapData = new BitmapData(radius * 2, radius * 2, true); var bm:Bitmap = new Bitmap(bmd); stage.addChild(bm); //lock the bitmap bmd.lock(); //draw resources bmd.draw(circleShape); //unlock and update the bitmap bmd.unlock(); }In essence, you wrap the lock() and unlock() methods around the point in which your code is changing the appearance of a Bitmap. While for the situation shown above they aren’t all that useful, in a large scale system with many thousands of changes to the bitmap they speed up the process by a long shot. This is because the Bitmap and BitmapData classes like to have a lot going on at once, the more changes you can cram into a single step the better they become! These methods are great for that as they put on hold all changes made to the locked bitmap until it is unlocked, and this means it isn’t re-rendered during that time, which speeds up the process.
Clearing Your Bitmap
The BitmapData class doesn’t offer a clear cut method to create wipe its data, so here are two common ways to do so. We can reuse all the the code from learning about the setPixel method.
package { //imports import flash.geom.Point; import flash.events.Event; import flash.geom.Rectangle; import flash.display.Bitmap; import flash.display.BitmapData; import flash.display.MovieClip; import flash.filters.BlurFilter; public class ClearBitmap extends MovieClip { //define variables private var n:int = 50; private var w:int; private var h:int; private var bm:Bitmap private var bmd:BitmapData; private var clearRect:Rectangle; public function ClearBitmap ():void { w = stage.stageWidth; h = stage.stageHeight; bmd = new BitmapData(w, h, false, 0x222222); bm = new Bitmap(bmd); addChild(bm); addEventListener(Event.ENTER_FRAME, onFrameLoop); //create the bitmap data the width and height of the stage that is not transparent and grey in color clearRect = new Rectangle(0, 0, w, h); } private function onFrameLoop (evt:Event):void { //use one of these methods to clear your bitmap //bmd.fillRect(clearRect, 0x222222); bmd.applyFilter(bmd, bmd.rect, new Point(0, 0), new BlurFilter(1.1, 1.1, 2)); for (var i:int = 0; i < n; i++ ) { var px:int = Math.random() * bmd.width; var py:int = Math.random() * bmd.height; var pc:uint = Math.random() * 0xffffff; bmd.setPixel(px, py, pc); } } } }If you use the clearRect method, it simply draws a completely new grey rectangle over everything else. This isn’t as careless method as it sounds at first because remember all you are ever doing with a Bitmap is changing the color of a set of pixels; overlapping items makes no difference what so ever.
The second option blurs out the dots by merging them into the background. We will use this later to create more interesting effects. You should note that this method requires a significantly longer compute time and should be avoided if efficiency is your only concern. We will leave this until the last bit of the tutorial where we are not aiming for maximum efficiency.
Speed Test #4 Bitmap Drawing vs. MovieClips Drawing
This is our final speed test and here we will test the speed difference between drawing multiple shapes using the Bitmap classes and the MovieClip class. Here is is:
CAUTION: The regular createMovieClipCircles() method is so inefficient that you should not let it run for more than a few seconds. The Flash Player will continue to slow down until it eventually grinds to a halt.
package { //imports import flash.events.Event; import flash.display.Bitmap; import flash.utils.getTimer; import flash.display.BitmapData; import flash.display.MovieClip; public class Bitmapvs.MovieClip extends MovieClip { //define variables private var w:int; private var h:int; private var r:int = 5; private var n:int = 500; private var currentTime:int = 0; private var bm:Bitmap; private var bmd:BitmapData; private var bmShape:MovieClip = new MovieClip(); public function Bitmapvs.MovieClip ():void { w = stage.stageWidth; h = stage.stageHeight; bmd = new BitmapData(w, h, true, 0); bm = new Bitmap(bmd); addChild(bm); addEventListener(Event.ENTER_FRAME, onFrameLoop); } private function onFrameLoop (evt:Event):void { timeDifference; //use one of these functions at a time //this one is to create points using the movieclip method //createMovieClipCircles(); //this one is to create points using the bitmap method createBitmapCircles(); } private function createMovieClipCircles ():void { //this will create a new movieclip for each circle for (var i:int = 0; i < n; i ++) { var m:MovieClip = new MovieClip(); drawCircle(m); addChild(m); } //trace the fps trace(1000 / timeDifference); } private function createBitmapCircles ():void { //this will draw the same movieclip in different places over and over bmd.lock(); for (var j:int = 0; j < n; j ++) { drawCircle(bmShape); bmd.draw(bmShape); } bmd.unlock(); //trace the fps trace(1000 / timeDifference); } private function drawCircle (m:MovieClip):void { //create the same function to draw circles for both to keep it fair and organised m.graphics.clear(); m.graphics.beginFill(Math.random() * 0xffffff); m.graphics.drawCircle(Math.random() * w, Math.random() * h, r); m.graphics.endFill(); } private function get timeDifference ():int{ var totalPlayedTime:int = getTimer(); var timeDifference:int = (totalPlayedTime - currentTime); currentTime = getTimer(); return timeDifference } } }What you should find after using both methods is that:
The createMovieClipCircles method is so inefficient because it needs to add each circle to the display list which leaves the Flash Player struggling to hold the weight of them all. This is why we must use the Bitmap and BitmapData classes in our particle system.
From reading this section you should now be familiar with many of the methods we can use from the Bitmap and BitmapData classes to build our particle system. I have covered much of what we need to know to build such a system so now I think its time we dive in!
Building the System
Our system won’t be pretty, but dang it will be fast! It will be composed of two classes, the Particle class we made earlier and the controller class that keeps check of everything. Our aim is to build a system that will brush off 100k particles, laugh at 150k particles and take on 200k comfortably. Of course this depends on your system, but mine is about six years old and hasn’t blown up yet so I’m sure most of you will be okay.
First we will start with the basic Particle class, much of the code that you will see will be the same as in the steps previously described.
package { //imports - the less the better import flash.geom.Vector3D; import flash.geom.Rectangle; public class Particle { //define the position and velocity Vector3D objects private var pos:Vector3D = new Vector3D(0,0); //the velocity of the particle is between +3 and -3 for x and y private var vel:Vector3D = new Vector3D(rand(3), rand(3)); //define the bounds and default color of the particle private var bounds:Rectangle; private var color:uint = 0x555555 public function Particle(stageRect:Rectangle) { //the bounding area of the stage is passed into the constructor //we do not need to pass the entire instance of the stage as this will require more memory bounds = stageRect; //spawn the particle at a random point within the bounds pos.x = Math.random() * bounds.width; pos.y = Math.random() * bounds.height; //give a handful a different color so that we can see particles moving more easily if(Math.random() < 0.005) color = 0xFFFFFF } private function rand(n:int):Number{ //this function returns a random number between -n and n return n - (n * 2 * Math.random()) } public function update ():void{ //add the respective velocities to the position pos.x += vel.x; pos.y += vel.y; //check if the particle is outside the bounds of the rectangle checkBounds(); } private function checkBounds():void{ //this function simply checks the x,y position values and if they are //bigger or greater than the bounds reverse the respective velocity (direction) is reversed if(pos.x < 0 || pos.x > bounds.width) vel.x *= -1; if(pos.y < 0 || pos.y > bounds.height) vel.y *= -1; } //the get methods for the color and x,y values of the particle public function get c ():uint{ return color } public function get x ():Number{ return pos.x } public function get y ():Number{ return pos.y } } }In keeping with OOP traditions, our particle is as encapsulated (self-contained) as possible. It defines its own x- and y-positions to keep clutter and unneeded variables from the controller class and only needs the update() method to be called for it to be ready for the next frame.
Next is the Controller class. This class is the brains of the operation doing all the looping and drawing on each frame.
package { //imports import flash.events.Event; import flash.display.Bitmap; import flash.display.BitmapData; import flash.geom.Rectangle; import flash.utils.getTimer; import flash.display.MovieClip; public class Controller extends MovieClip { //define variables private var w:int; private var h:int; private var bm:Bitmap; private var bmd:BitmapData; private var clearRect:Rectangle; private var currentTime:int = 0; private var holder:Vector.<Particle> = new Vector.<Particle>; //most machines should be fine with 150,000 particles. Even my Nexus One can handle it! private var n:int = 150000; public function Controller():void { w = stage.stageWidth; h = stage.stageHeight; //create the blank rectangle we will use to clear the bitmapdata clearRect = new Rectangle(0, 0, w, h); //create the bitmap and bitmapdata bmd = new BitmapData(w, h, false, 0); bm = new Bitmap(bmd); addChild(bm); //populate the holder with n number of particles for(var i:int = 0; i < n; i++ ){ //notice no temporary variable was used to store the particle before pushing it to the Vector //this only uses unneeded memmory holder.push(new Particle(stage.getRect(this))); } //add listener for every frame addEventListener(Event.ENTER_FRAME, onFrameLoop); } private function onFrameLoop (evt:Event):void{ var p:Particle; //lock the bitmap and clear it before drawing bmd.lock(); bmd.fillRect(clearRect,0); //for n times get the respective particle in the holder and set the //corresponding pixel at p.x and p.y to the particles color for(var i:int = 0; i < n; i++ ){ //notice a temporary variable was used here because otherwise the object //would need to be read 3 times from the Vector - much slower p = holder[i]; bmd.setPixel(p.x, p.y, p.c); //update the particle's position p.update(); } //update the bitmap bmd.unlock(); //trace the FPS trace(1000 / timeDifference); } private function get timeDifference ():int { var totalPlayedTime:int = getTimer(); var timeDifference:int = (totalPlayedTime - currentTime); currentTime = getTimer(); return timeDifference } } }Thats it! You have what you saw in the first demo.
EPILEPSY WARNING:
Please don’t view this demo if you are likely to suffer from epileptic attacks or loss of consciousness, particularly when looking at some types of strong flashing lights, rapid succession of images, simple geometric shapes, flashes or explosions.
Unfortunately there is a problem. If you run this code inside the Flash Professional IDE it will never run at 24/24 FPS. This is because when you run it here, the Flash IDE tries to connect with Flash Player to read many different things off it, this is how you get your error reports when something goes funny. However, luckily for you, your clients probably never have to see this side of things and on its own, the Flash Player works beautifully, running easily at 24/24 FPS. Its just slightly more difficult to read the FPS. I recommend making a small dynamic text field and output what we are should be tracing to that, this is outside the scope of this tutorial and is something that is pretty straightforward so I can leave that with you.
So now that you have made your particle system, wouldn’t it be nice to show it off to your friends and clients? Coming from experience all you will get from showing this one is some weird glances with some squeezed praise on the side from all of those but seasoned programmers. Let’s make something pretty.
Over 9000?! Playing it Safe With so Many Particles.
Before moving on any further I recommend tinkering around a bit with the above particle system and see how far you can push it. On my less than average system I can go to about 200,000 at 24/24 FPS and at 250,000 its at about 18/24 FPS, just as a reference. Get a grip for how far you can push your own system and heck, even boast about it in the comments!
Let’s look at some of the things you should avoid when playing around with systems such as this.
Trace statements. One of the most useful things in a Flash Developer’s arsenal is actually a big task for Flash Player. Once per frame is okay, but make sure you don’t shove it into one of your particles when you have 200k of them running. This will simply instantly crash the Flash IDE and you’l spend the next couple of minutes pressing all the exit buttons. A good way to test something in a particle is just to drop the number of them to something between one and ten.
Everything matters when you’re doing something 200,000 times 24 times a second so be sure to keep looking through your code and never make any big changes without putting the number of particles down to a single number.
Making Something Pretty – A Basic Waterfall Effect
This will be a very basic example of building something that looks mildly attractive.
This is the updated Particle class which is used to create the waterfall:
package { import flash.geom.Vector3D; import flash.geom.Rectangle; public class Particle { private var pos:Vector3D = new Vector3D(0,0); private var vel:Vector3D = new Vector3D(rand(3), rand(3)); private var bounds:Rectangle; private var color:uint = 0x00FFFF public function Particle(stageRect:Rectangle) { bounds = stageRect; //spawn the particle from the top left corner pos.x = 0; pos.y = 0; } private function rand(n:int):Number{ //this function returns a random number between 0 and n return Math.random() * n } public function update ():void{ pos.x += vel.x; pos.y += vel.y; //add a small amount to the y velocity to simulate gravity vel.y += 0.1; //check if the particle is outside the bounds of the rectangle checkBounds(); } private function checkBounds():void{ //this time we need to decrease velocities in both directions to make sure they are all eventually removed if(pos.x < 0 || pos.x > bounds.width){ vel.x *= -0.8; vel.y *= 0.8; } if(pos.y < 0 || pos.y > bounds.height){ vel.x *= 0.9; vel.y *= -Math.random() * 0.8; } } //the get methods for the color and x,y values of the particle public function get c ():uint{ return color } public function get x ():Number{ return pos.x } public function get y ():Number{ return pos.y } //returns true if the particle does not have a lot of 'energy' left, false otherwise public function get remove ():Boolean { if(Math.abs(vel.y) + Math.abs(vel.x) < 0.1){ return true; } return false; } } }As you can see there need to be no major changes to the Particle class because it will always stay as a just a placeholder for a group of related numbers and funcions.
Next is the Controller class. Again, there is no need for any major changes. Let’s take a look:
package { //imports import flash.geom.Point; import flash.events.Event; import flash.display.Bitmap; import flash.display.BitmapData; import flash.geom.Rectangle; import flash.utils.getTimer; import flash.display.MovieClip; import flash.filters.BlurFilter; import flash.geom.ColorTransform; public class Controller extends MovieClip { //define variables private var w:int; private var h:int; private var bm:Bitmap; private var bmd:BitmapData; private var clearRect:Rectangle; private var currentTime:int = 0; private var holder:Vector.<Particle> = new Vector.<Particle>; //define the blur and color transformers private var blurFade:BlurFilter = new BlurFilter(4, 4, 1); private var colorFade:ColorTransform = new ColorTransform(0.7,0.7,0.999); //the number of particles pushed into the holder every frame private var n:int = 50; public function Controller():void { w = stage.stageWidth; h = stage.stageHeight; bmd = new BitmapData(w, h, false, 0); bm = new Bitmap(bmd); addChild(bm); addEventListener(Event.ENTER_FRAME, onFrameLoop); } private function onFrameLoop (evt:Event):void{ //push new particles in n times every frame for(var i:int = 0; i < n; i++ ){ holder.push(new Particle(stage.getRect(this))); } bmd.lock() //apply the BlurFilter which blurs the colors together and fades the particles out bmd.applyFilter(bmd, bmd.rect, new Point(0,0), blurFade); //apply the color transformation to give the particle trails a blue tint bmd.colorTransform(bmd.rect, colorFade); for(var j:int = 0; j < holder.length; j++ ){ var p:Particle = holder[j]; //check if the particle has a resonable amount of energy left through its getter method //if not remove it from the holder vector if(p.remove){ holder.splice(j,1); j--; p = null; } else{ bmd.setPixel(p.x, p.y, p.c); p.update(); } } bmd.unlock(); //trace the FPS //trace(1000 / timeDifference); } private function get timeDifference ():int { var totalPlayedTime:int = getTimer(); var timeDifference:int = (totalPlayedTime - currentTime); currentTime = getTimer(); return timeDifference } } }You should end up with something like this. If you’ve just found this, you might want to hit refresh in your browser to see the start of the waterfall to better understand how the particles move.
Needless to say that you can run and run with the basic ideas here and great some amazing effects, a lot of which pop up on WonderFl quite often, or even to create this kind of effect. (shameless self plug
) A very ‘cool’ thing to try out is to have the particles interacting with the mouse in some way, the effect can be ne beautiful when done correctly. The perlinNoise() method of the BitmapData class might also be worth mentioning here as it sometimes used in particle systems to create a flowing effect, which can also be very beautiful.
Summary
I hope after reading this that you can take away a number of things from how to get the most out of Flash Player in your code to an introduction to building particle effects. Most of all, I hope I ignited a little flame of curiosity somewhere and gave you a new set of boundaries for Flash itself. Hopefully, an ‘extreme’ particle system won’t seem too extreme anymore
Up until now, our collision detection methods have been mathematically based. Although this is helpful, there are cases where the mathematical approach is just not worth it, such as with an irregular, organic shape – the computations required are too complex and expensive to justify. Instead, we can check each individual pixel of the shapes. This is also an expensive approach, but it can at least be optimised.
Collision Detection
This is the final piece we will try to create. Drag the hook over the coconut tree, and note what the text at the bottom says.
Step 1: One by One
Assume we have two bitmaps and we would like to check whether they collide, pixel by pixel: what does it mean? Well, let’s suppose both your bitmaps are 3x3px, and all the pixels are filled.
We will be doing literally this:
There are a few observations that I’d like to point out.
Step 2: Extra Considerations
Now, Step 1 can be taken literally if all the pixels are filled. With bitmap graphics, we define an area of rectangular dimension. But not all pixels are filled to form the graphic.
The example below shows the right bitmap occupying only b2, b4, b5, b6 and b8. In this case, we should check each pixel in the left bitmap (a1, a2, a3 … a9) against only the pixels b2, b4, b5, b6, b8 in the right bitmap.
Now ActionScript provides us with another parameter,
alpha, which defines the transparency of the pixel, with 0 being completely transparent and 1 being completely opaque. For b2, b4, b5, b6, b8, we can define a threshold value foralpha, say 0.5.So, assume that b2 and b8 are both pixels with
alpha0.1; because they are less than the threshold value of 0.5, we will not consider them to be filled pixels, and therefore not check them. So in the end, each pixel in the left bitmap (a1, a2, a3 … a9) is checked against b4, b5, b6 in right bitmap only.Step 3: ActionScript Implementation
In ActionScript, we can superimpose vector graphics into
BitmapDatainstances. You can imagine ActionScript taking an X-ray of a vector graphic, and transferring it to aBitmapData, which acts like the photographic film.(Tip: If you are drawing in Flash IDE and then exporting to FlashDevelop as I’m doing, make sure that the dimensions of the
BitmapDataare large enough to contain the drawing.)Here,
CTreeandHookare two MovieClip symbols, drawn in Flash; we “X-ray” them to obtain a BitmapData instance for each:private var coconut:CTree, hk:Hook; private var bdat1:BitmapData, bdat2:BitmapData; private var t1:TextField; public function Matrix_Bitmap() { coconut = new CTree(); addChild(coconut); coconut.x = stage.stageWidth * 0.3; coconut.y = stage.stageHeight * 0.2; bdat1 = new BitmapData(150, 150, true, 0x00000000); bdat1.draw(coconut); hk = new Hook(); addChild(hk); bdat2 = new BitmapData(100, 50, true, 0x00000000); bdat2.draw(hk); hk.addEventListener(MouseEvent.MOUSE_DOWN, start); hk.addEventListener(MouseEvent.MOUSE_UP, end); t1 = new TextField(); addChild(t1); t1.x = stage.stageWidth * 0.2; t1.y = stage.stageHeight * 0.8; t1.width = 300; t1. height = 100; stage.addEventListener(Event.ENTER_FRAME, check); }So after that, we’ll start the checks by using the
hitTest()method of theBitmapDataclass.On each passing frame, we will update location of the top left pixel for each bitmap before putting instances of
BitmapDatathrough these rigouroushitTest()checks. Note as well that the range foralphainput here is 0 ~ 255 – i.e. there is no threshold. More on transparency in the next step.private function check(e:Event):void { var point1:Point = new Point(coconut.x, coconut.y); //top-left pixel of tree var point2:Point = new Point(hk.x, hk.y); //top-left pixel of hook if (bdat1.hitTest(point1, 255, bdat2, point2, 255)) { //check whether any filled pixels overlap t1.text = "At least one pixel has collided" } else { t1.text = "No collision" } }Here’s an example of the output from ActionScript above. Click on the hook and bring it near to the coconut tree and check the response on the text box. Play around with this by bringing the end of the hook near to the edge of the coconut tree’s leaves, to see whether this collision is of pixel-level precision.
Step 4: Transparency Level
If you have an image that is, say, gradually disappearing (becoming transparent), you can tell ActionScript at which level of transparency you consider a pixel fit to perform collision checks.
Take the example below: there are several levels of transparency on the sprite and, as you can see, it is gradually lowered to the right. If we set the transparency level to 0.5, then any pixel with an alpha of 0.5 ~ 1 will be considered opaque and fit for collision detection. Those lower than 0.5 will be considered transparent. Even when these pixels collide with that of another object, they will not register a true collision.
Another detail I mentioned just now is that ActionScript
BitmapData‘s hitTest functionalphaparameter value actually ranges from 0 ~ 255. So what I do is simply multiply my threshold value by 255 to convert the range.private function check(e:Event):void { var point1:Point = new Point(bar1.x, bar1.y); var point2:Point = new Point(bar2.x, bar2.y); var threshold:Number = 255*0.5 if (bdat1.hitTest(point1, threshold, bdat2, point2, threshold)) { t1.text = "At least one pixel has collided" } else { t1.text = "No collision" } }Step 5: Optimisation
I’ve mentioned that pixel-level collision detection is computationally expensive. This means we shoudl only opt for it when it’s strictly necessary. If two objects are very far apart, then there’s no reason to use this approach, and a normal bounding box collision detection (
hitTestObject()) will do.Here’s the idea:
hitTestObject()to see if two objects’s bounding boxes have collided.private function check(e:Event):void { var closeEnough:Boolean = coconut.hitTestObject(hk) if(closeEnough){ var point1:Point = new Point(coconut.x, coconut.y); var point2:Point = new Point(hk.x, hk.y); if (bdat1.hitTest(point1, 255, bdat2, point2, 255)) { t1.text = "At least one pixel has collided" } else { t1.text = "No collision" } } }For a full ActionScript reference, check out
Matrix_Bitmap3.asfrom the source download.Conclusion
Thanks for the read. In the next Quick Tip, we’ll be using matrices to transform
BitmapData.Ever see crazy binary numbers and wonder what they meant? Ever see numbers with letters mixed in and wonder what is going on? You’ll find out all of this and more in this article. Hexadecimal doesn’t have to be scary.
(Thanks to the ReBoot Wiki for the thumbnail image.)
Introduction: What is a Number System?
You probably already know what a number system is – ever hear of binary numbers or hexadecimal numbers? Simply put, a number system is a way to represent numbers. We are used to using the base-10 number system, which is also called decimal. Other common number systems include base-16 (hexadecimal), base-8 (octal), and base-2 (binary).
In this article, I’ll explain what these different systems are, how to work with them, and why knowing about them will help you.
Activity
Before we get started, let’s try a little activity for fun. There are many different ways to represent a color, but one of the most common is the RGB color model. Using this model, every color is made up of a combination of different amounts of red, green, and blue.
You may be wondering how colors relate to number systems. In short, on a computer, any color is stored as a large number: a combination of red, green, and blue. (We’ll go into more detail on this later.) Because it’s just a number, it can be represented in multiple ways using different number systems.
Your job is to guess how much red, green, and blue is in the background color of the activity below. The values for red, green, and blue can range from 0 to 255.
Feel free to use the various hints provided to help you out. If you don’t understand the numerical hints yet, no problem! You can see what your guess looks like using the View Guess button. Right now, it may seem tricky, but hopefully by the end of the article, it will seem easy.
Looking at Base-10
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11… You’ve counted in base-10 all of your life. Quick, what is 7+5? If you answered 12, you are thinking in base-10. Let’s take a closer look at what you’ve been doing all these years without ever thinking about it.
Let’s take a quick look at counting. First, you go through all the digits: 0, 1, 2… Once you hit 9, you have no more digits to represent the next number. So, you change it back to 0, and add 1 to the tens digit, giving you 10. The process repeats over and over, and eventually you get to 99, where you can’t make any larger numbers with two digits, so you add another, giving you 100.
Although that’s all very basic, you shouldn’t overlook what is going on. The right-most digit represents the number of ones, the next digit represents the number of tens, the next the number of hundreds, etc.
Visualizing Base-10
Confused by these descriptions? No problem – below is a demo to help you out. Simply enter a number in the text box and click draw. Try entering a large number, like 2347. You’ll see 2 groups of one thousand, 3 groups of one hundred, 4 groups of ten, and 7 individual blocks.
Base-10 Mathematically
You may have noticed a pattern by now. Let’s look at what is going on mathematically, using 2347 as an example.
1000 = 10*10*10which can also be written as103.100 = 10*10or102.10 = 101.1 = 100. (That may seem strange, but any number to the power of 0 equals 1, by definition.)This is essentially the definition of base-10. To get a value of a number in base-10, we simply follow that pattern. Here are a few more examples:
892 = 8*102+9*101+2*1001147 = 1*103+1*102+4*101+7*10053 = 5*101+3*100Admittedly, this all seems a little silly. We all know what value a base-10 number is because we always use base-10, and it comes naturally to us. As we’ll see soon, though, if we understand the patterns in the background of base-10, we can understand other bases better.
Base-8
On to base-8, also called octal. Base-8 means just what is sounds like: the system is based on the number eight (as opposed to ten). Remember how in base-10 we had ten digits? Now, in base-8, we are limited to only eight digits: 0, 1, 2, 3, 4, 5, 6, and 7. There’s no such thing as 8 or 9.
We count the same way as we normally would, except with only eight digits. Instead of a lengthy explanation, simply try out the demo below by clicking “Count Up 1″ to see how counting in base-8 works.
You should notice a similar pattern to before; after we get to 7, we run out of different digits for any higher number. We need a way to represent eight of something. So we add another digit, change the 7 back to 0, and end up with 10. Our answer of 10 in base-8 now represents what we would normally think of as 8 in base-10.
Talking about numbers written in multiple bases can be confusing. For example, as we have just seen, 10 in base-8 is not the same as 10 in base-10. So, from this point on, I’ll use a standard notation where a subscript denotes the base of numbers if needed. For example, our base-8 version of 10 now looks like 108.
(Editor’s note: I find it a lot easier to understand this if I change the way I read these numbers in my head, too. For example, for 108, I read “octal one-oh” or “one-oh in base-eight”. For 1010 I read “decimal one-oh” or “one-oh in base-ten”.)
Great, so we know 108 represents eight items. (Always feel free to plug a number into the first tool for a visualization.) What’s the next number after 778? If you said 1008, you’re correct. We know from what we’ve learned so far that the first 7 in 778 represents groups of 8, and the second 7 represents induvidual items. If we add these all up, we have
7*8 + 7*1 = 63. So we have a total of 6310. So 778=6310. We all know 6410 comes after 6310.Converting From Base-8 to Base-10
Let’s look at a wordier example now. John offers to give you 478 cookies, and Jane offers to give you 4310 cookies. Whose offer do you take? If you want, go ahead and generate the graphic for 478 graphic with the first tool. Let’s figure out its base-10 value so we can make the best decision!
As we saw when counting, the four in 478 represents the number of groups of eight. This makes sense – we are in base-8. So, in total, we have four groups of eight and seven groups of one. If we add these all up, we get
4*8 + 7*1 = 3910. So, 478 cookies is the exact same as 3910 cookies. Jane’s offer seems like the best one now!The pattern we saw before with base-10 holds true here also. We’ll look at 5238. There are five groups of 82, two groups of 81 and three groups of 80 (remember, 80=1). If we add these all up,
5*82 + 2*81 + 3*80 = 5*64+2*8+3 = 339, we get 33910 which is our final answer. The diagram below shows the same thing visually:Here are a couple more examples:
1118 = 1*82+1*81+1*80 = 64+8+1 = 7310438 = 4*81+3*80 = 32+3 = 351061238 = 6*83+1*82+2*81+3*80 = 3072+64+16+3 = 315510Converting from Base-10 to Base-8
Converting from base-10 to base-8 is a little trickier, but still straightforward. We basically have to reverse the process from above. Let's start with an example: 15010.
We first find the largest power of 8 that is smaller than our number. Here, this is 82 or 64 (83 is 512). We count how many groups of 64 we can take from 150. This is 2, so the first digit in our base-8 number is 2. We have now accounted for 128 out of 150, so we have 22 left over.
The largest power of 8 that is smaller than 22 is 81 (that is, 8). How many groups of 8 can we take from 22? Two groups again, and thus our second digit is 2.
Finally, we are left with 6, and can obviously take 6 groups of one from this, our final digit. We end up with 2268.
In fact, we can make this process a touch clearer with math. Here are the steps:
Our final answer is then all of our non-remainder digits, or 226. Notice that we still start by dividing by the highest power of 8 that is less that our number.
Dealing with any Base
It's important to be able to apply the concepts we've learned about base-8 and base-10 to any base. Just as base-8 had eight digits and base-10 had ten digits, any base has the same number of digits as its base. So base-5 has five digits (0-4), base-7 has seven digits (0-6), etc.
Now let's see how to find the base-10 value of any number in any base. Say we are working in base-b, where b can be any positive integer. We have a number d4d3d2d1d0 where each d is a digit in a number. (The subscripts here don't refer to the base of the number but simply differentiate each digit.) Our base-10 value is simply
d4*b4 + d3*b3 + d2*b2 + d1*b1 + d0*b0.Here's an example: we have the number 32311 in base-4. Notice how our number only has digits from zero to three since base-4 only has four total digits. Our base-10 value is
3*44 + 2*43 + 3*42 + 1*41 + 1*40 = 3*256 + 2*64 + 3*16 + 1*4 + 1*1 = 949. We could, or course, follow this pattern with any amount of digits in our number.Base-16
Base-16 is also called hexadecimal. It's commonly used in computer programming, so it's very important to understand. Let's start with counting in hexadecimal to make sure we can apply what we've learned about other bases so far.
Since we are working with base-16, we have 16 digits. So, we have 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ... and yikes! We've run out of digits, but we still need six more. Perhaps we could use something like a circled 10?
The truth is, we could, but this would be a pain to type. Instead, we simply use letters of the alphabet, starting with A and continuing to F. Here's a table with all the digits of base-16:
Other than these extra digits, hexadecimal is just like any other base. For example, let's convert 3D16 to base-10. Following our previous rules, we have:
3D16 = 3*161 + 13*160 = 48 + 13 = 61. So 3D16 is equal to 6110. Notice how we use D's value of 13 in our calculation.We can convert from base-10 to base-16 similar to the way we did with base-8. Let's convert 69610 to base-16. First, we find the largest power of 16 that is less than 69610. This is 162, or 296. Then:
We have to replace 11 with its digit representation B, and we get 2B816.
Feel free to try some more conversions for practice. You can use the application below to check your answers:
Binary! (Base-2)
On to the famous base-2, also called binary. While everyone knows binary is made up of 0s and 1s, it is important to understand that it is no different mathematically than any other base. There's an old joke that goes like this:
Can you figure out what it means?
Let's try a few conversions with base-2. First, we'll convert 1011002 to base-10. We have:
101100 = 1*25 + 1*23 + 1*22 = 32 + 8 + 4 = 4410.Now let's convert 65 to binary. 26 is the highest power of 2 less than 65, so:
And thus we get our binary number, 1000001.
Understanding binary is super important. I've included a table below to point out digits' values.
For example, the value of 10001 is 17, which is the sum of the values of the two 1 digits (16+1). This is nothing different than we have done before, its just presented in an easy to read way.
Tricks and Tips
Normally, when converting between two bases that aren't base-10, you would do something like this:
However, there's a trick that will let you convert between binary and hexadecimal quickly. First, take any binary number and divide its digits into groups of four. So, say we have the number 10111012. Divided up we have 0101 1101. Notice how we can just add extra zeroes to the front of the first group to make even groups of 4. We now find the value for each group as if it was its own separate number, which gives us 5 and 13. Finally, we simply use the corresponding hexadecimal digits to write out base-16 number, 5D16.
We can go the other direction also, by converting each hexadecimal digit into four binary digits. Try converting B716 to binary. You should get 101101112.
This trick works because 16 is a power of 2. What this means is that we use similar trick for base-8, which is also a power of 2:
Of course, you can reverse the process to go from base-8 to binary also.
Conclusion
Let's go all the way back and revisit the color guessing game.
In Flash, colors are stored as a single number. When converted to hexadecimal, the first two digits represent the amount of red, the next two the amount of green, and the final two the amount of blue. So, if our color is 17FF1816 we can easily tell that our red component is 1716 or 2310. Our green component is FF16, or 25510. Finally our blue component is 1816 or 2410. If we are given the base-10 version of our color, 157263210, we need to convert it to hexadecimal before we can tell anything about it.
Try the game again, and see how much better you can do!
Understanding different number systems is extremely useful in many computer-related fields. Binary and hexadecimal are very common, and I encourage you to become very familiar with them. Thanks for reading - I hope you've learned a lot from this article! Feel free to grab the source code from any of the demos. Also, if you have any questions, please ask them below.
It’s time for another Premium tutorial! This week, James Tyner will walk you through the process of building an HTML5 MP3 player, step by step, with the SoundManager 2 library, jQuery, and a little help from Flash (for extra audio functionality).
Premium Preview
Click for a demo.
You’ll use jQuery, jQuery UI, and jScroller to manage the UI, with graphics already provided for you, and learn how to use SoundManager 2, a cross-browser JavaScript audio library that even works on iOS (if you are willing to lose the extra features, such as ID3 functionality).
Everything is explained step by step as you build the player. Check out the demo to see the end result.
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, which are enough to help you code the basic play and stop buttons..
Tuts+ Premium Membership
We run a Premium membership system which periodically gives members access to extra tutorials, like this one! You’ll also get access to Psd Premium, Vector Premium, Audio Premium, Net Premium, Ae Premium, Cg Premium, Photo Premium, and the new Mobile Premium too. 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.
Having one object orbit another is a movement mechanic that’s been used since the early gaming era, and it remains handy to this very day! In this Quick Tip we will explore the mathematical function for orbiting, see how to modify it, and look at practical uses in actual game design.
Final Result Preview
Here’s what we will be working towards:
Step 1: The Orbiting Equation
To create an orbit we must define the following:
It is also helpful to note that Flash’s coordinate system is like a regular cartesian plane, except that the y-axis is flipped, so the value increases as we move downwards. The top-left corner of the stage has coordinates
(0,0)In this image, 0, 90, 180, and 270 refer to angles, measured in degrees.
Another thing that we need to understand is how to convert degrees to radians, which can easily be accomplished using the following formula:
Radians = Degrees * (PI / 180)Here’s the actual orbiting function: it requires two lines, one to position the orbiter on the x-axis and the other to position it on the y-axis:
Orbiter X-Coord = Origin X-Coord + Radius * cos(Radians)
Orbiter Y-Coord = Origin Y-Coord + Radius * sin(Radians)
(In a normal Cartesian plane,
sinis used for the x-coord andcosis used for the y-coord, but since our angles are increasing clockwise – due to the reversed y-axis – their places are swapped.)Step 2: Writing the Equation in Code
We can now turn the logic into actual code that we can use. First, declare all of the variables:
Next rewrite the equation for use in AS3 and put it into an
ENTER_FRAMEevent handler function:If you test now, nothing will happen; this is because the variable angle is neither increasing nor decreasing. Therefore, we must increase or decrease the value:
Now what if we want our orbiter to continuously face a direction? Well I have written an equation to do just that!
Depending on which way you have drawn your orbiter movieclip you may have to subtract a certain angle (outside the brackets) to get it to face the correct way.
Step 3: Transforming the Equation
Now this may sound crazy, but some of us might want to have our object orbit in an ellipse. This is easily doable; all we have to do is multiply in a specific place in the equation. Multiplying the
cosorsinfunctions by a postive whole number will cause the circle to stretch. Multiplying it by a decimal between 0 – 1 will cause it to compress. And multiplying it by a negative will cause it to flip along that axis:We can also shift the orbit in any direction we want by adding or subtracting from the equation on either axis:
If you want to learn more about
cos,sin, andatan2, take a look at Trigonometry for Flash Developers.Step 4: Practical Uses for the Equation
Now this is all fine and dandy, but what can it actually be used for? A wide variety of things actually!
If you have ever played Mario Kart you would have gotten the “three shells” powerup; those shells are orbiting using this very technique. Another example is the widely over-used circle pong game, where the paddle orbits along a ring on the outside. A third example is from top down zombie shooter games: a lot of them include a powerup where a grouping of barrels orbits around your player and crushes any zombies if they are hit trying to attack you.
As you can see the use for this technique can be used in anything from industry standard games to casual games.
Conclusion
Thank you for taking the time to learn this Quick Tip! If you have any questions leave a comment below.
Construct 2 is an HTML5 game making tool that doesn’t require any programming knowledge. You just drag and drop items around, add behaviors to them, and make them come alive with “events”.
In this review I will see what Construct 2 is capable of, from my perspective as a Flash game developer. Read the review to see whether or not this tool will serve the purpose of getting my games on more platforms!
First Impressions
Downloading and installing Construct 2 was very easy. It comes as a single .exe installer for Windows (no Mac version at the moment) and the installation steps are very simple.
When you first open the app, it shows you a nice “Hello!” popup asking if you want to read the tutorials, browse examples or buy a license. I chose not to do any of the above, because I wanted to see how intuitive Construct 2 would be for me.
If you ever want to read the manual, follow the tutorials or browse the forums, Construct 2 always provides links in the start page or through the “Home” menu.
Construct 2 has an interface very similar to Microsoft’s Office products. This makes it easy for people who are used to the Office products – but not for me, a fan of the old drop-down menus.
I started a new project by clicking the “Create new project” text in the start page, and after choosing whether I wanted to keep the project in a single file or in a folder, I was led straight to a blank screen, ready to work.
At that stage I didn’t know much about the tool, so I started by changing the Project Settings on the “Properties” tab on the left of the screen. After doing that, I started dragging a few images from my Windows folders to Construct 2, and it automatically recognized them and imported them into the project. Within minutes I managed to set up a very simple level for a platformer game, but at that moment the objects were only images in the screen.
Whenever I clicked an image in the screen (which is called an Object inside Construct 2), the “Properties” tab changed with the options I could change for that object. That’s how I found the “Behaviors” option and clicked it. After that a popup appeared so I could see the current behaviors on my object: none. I clicked the green plus image and it gave me a big popup to choose which behavior I wanted to add:
I could see the “Platform”, “Jump-thru” and “Solid” behaviors, so that was enough for me to start adding behaviors to my objects. Once I finished adding them, I clicked the green arrow in the top of the screen, “Run layout”. Within minutes I already had a game with simple platformer mechanics in it! Impressive.
Now I wanted to add an enemy to my platformer game, so I dragged in its image and tried to add a proper behavior to it. There wasn’t any behavior that would be obvious for an enemy, so I was a bit lost. I right-clicked the object and found the “Edit Event Sheet” option. So I clicked it and tried adding an event, but nothing I tried would make the enemy work. The events don’t have a good description, which makes them hard to use. I could do nothing but try to get help online (even the manual is online).
After a couple hours of reading, I wanted to start a new project. Turns out that everything I did with the enemy image was “wrong”. There were much simpler solutions to what I wanted to do and I learned so many other things that I just wanted to start a new project and apply everything I learned. And so I did.
My first experience with Construct 2 taught me that the tool is really great – it really helps you to make games easily – but some things are very complex at the moment, if you try to dive right in like I did. There isn’t something that will walk you through the application once you start your first project and many things aren’t descriptive enough. I wish that the initial screen either forced me to go read the tutorials online or provided me with a built-in walkthrough tutorial.
The First Game
Turns out that once you read some of their guides and tutorials, everything is very easy (and if you’re wondering which tutorials I read, they’re linked at the bottom of this review). I found myself creating many layouts and event sheets, and quickly adding objects to the screen as if I was using the good old Flash IDE. However, I realized that Construct 2 doesn’t have quick-align shortcuts as Flash does, and that makes it extremely hard and boring to align objects in the screen the way I want. Even using their built-in “Snap to grid” option didn’t help me much, as my objects often had different sizes and proportions from each other.
Animations are really easy to do. The tool allows me to import either many images which will be transformed into frames, or import a spritesheet that will be cropped to make frames. The only things I missed in it were the ability to add more than one image to the same frame, and an easy to use alignment system.
Within an hour, I already had a very simple memory game in my screen. I only had to add the events that would control the game mechanics. And that was initially a big problem. Coming from a programming background, having to visually create the mechanics with events and a limited set of conditions was very hard. I felt I wasn’t free to just go on and “code” anything I wanted in the game, and soon became upset with the event system. It was only after reading (yet another) tutorial on their site that I changed my mind.
I found myself playing for two hours adding and removing events, changing conditions and actions. As soon as I understood how Construct 2′s event system worked, it was a really fun challenge to “program” the events to do what I wanted, since I had only a set of limited conditions and actions to use. It was both challenging and relaxing to be able to visually organize your game and see it evolving without writing a single line of code!
The events for my memory game
After 3 hours of learning and applying this new knowledge in the tool, I had finished my very first game with Construct 2. My conclusion? Construct 2 is a very powerful tool once you learn how to use it, otherwise you’ll feel like a complete fool in front of it. I wish it was easier to use with more descriptive options, but after three hours I felt as if I was already a pro with the tool, because it was so easy to add, change and remove things!
My Conclusions
Construct 2 is a very interesting tool. For people who are already game developers, I found it can be a fun experience and it can teach you a few things about making things simpler, but it isn’t a tool that I would use in my routine. Due to HTML5′s still experimental nature, you’ll find that some features that your game may require won’t work properly across all devices. One example is audio: this simple memory game that I created uses only two sounds – a background music and a card flip effect – and yet I noticed differences between Firefox, Chrome and Android’s browser (which just doesn’t play audio).
When it comes to using Construct 2 to help me expand my game to another platform, that’s something you may want to think about first. It’s very easy to just import all the images in there and set up everything, but the problem comes with events: you’ll spend a lot of time organizing events to make them work the same way as your game in Flash (if that’s the platform you first built your game in).
However, Construct 2 can have a very interesting use for game developers: rapid prototyping and testing whether an idea is fun or not. Within minutes or hours you can just create a level or a small shooter game using behaviors and let people play it, giving feedback as to whether the prototype is fun or not.
For people who want to get into making games but don’t know or have trouble with programming, Construct 2 is the perfect tool. You can quickly learn the event system and start making a game. Construct 2 can export your game to work within Kongregate and on mobile devices. It’s the perfect opportunity to make games and share with friends!
Here is a quick list of pros and cons, based on my experience:
Pros:
Cons:
For people who are wondering whether or not the “Standard” version of the product is worth it: looking at the comparison table, the only drawbacks of the free version are the limited number of events (you will need many of them for a “proper” game) and the inability to offer your games as commercial products.
The free version’s limit on the number of layers you can have is arguably not a problem: I would easily manage to do everything in three layers; a fourth one would just make things easier. I don’t think you would need more than that, unless you are creating something really big. My opinion: if you’re just looking to make games for fun, the free version is more than enough. If you want to sell your games or get some money with them, the standard version is the way to go.
Extra Resources
Below is a quick list of the tutorials and guides that helped me a lot when learning the tool:
And you can see the game I created within three hours here:
Click to play
The source files are available here.