logo
468x60-2-495


  • Home
  • Privacy Policy
  • About
search
top
Feb 18, 2012 Posted on Feb 18, 2012 in Hints and Tips | 10 comments

Simple Harmonic Motion and Its Applications in Games – Tuts+ Premium

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.



View full post on Activetuts+

banner ad

10 Responses to “Simple Harmonic Motion and Its Applications in Games – Tuts+ Premium”

  1. Kah Shiu Chong says:
    February 18, 2012 at 5:10 pm

    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.


  2. Kah Shiu Chong says:
    February 18, 2012 at 5:48 pm

    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.

    Coordinate space for stage.

    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.

    Coordinate space for symbol

    (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.

    Original grids without alteration
    X-axis of red grid altered while blue axis remains unchanged

    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.

    Not affine space
    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.

    Cartesian as a type of affine space

    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 affine space
    Example of an affine coordinate space
    Example of affine 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
    Original affine space
    scaled affine space
    Scaled affine space
    reflected affine space
    Reflected affine space
    skewed affine space
    Skewed affine space
    rotated affine space
    Rotated and scaled affine space

    Needless to say, physical properties such as x, y, scaleX, scaleY and rotation depend 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 Matrix class. Thus, having a mathematical understanding of matrices is important, so we shall revise the operations of matrix here: addition and multiplication.

    Matrix operations

    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.

    Geometrical meaning of matrix addition

    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:

    Notation of matrix addition

    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.

    Notation of matrix addition, differentiated

    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.

    Identity matrix

    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:

    Vector form

    The geometric interpretation of this formula is shown in the image below.

    Interpretation of vector form

    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

    Scaling in x direction

    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.

    Interpretation of matrix

    Now to check out the numerical result of our scaling example.

    • Original coordinate: (2, 1)
    • Vector on transformed x-axis: (2, 0)
    • Vector on transformed y-axis: (0, 1)
    • Expected result: (2*2 + 0*1, 0*2 + 1*1) = (4, 1)
    Scale numerical result

    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

    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…

    Scale x and y numerical result

    … they match again! To see this in the ActionScript implementation, just change the value of m.d from 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

    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:

    reflect x numerical result

    The ActionScript implementation is the same as before, but using these values instead: m.a = -1, m.b = 0 to represent the vector for the x transformation, and: m.c = 0 and m. d = 1 to represent the vector for the y transformation.

    Next, what about reflecting simultaneously on x and y? Check out the image below.

    reflection

    Also, numerically computed in image below.

    reflect x and y numerical result

    For the ActionScript implementation… well, I'm sure you know the values to put into the matrix. m.a = -1, m.b = 0 to represent the vector for the x transformation; m.c = 0 and m. d = -1 to 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
    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…

    shear in y numerical result

    In terms of implementation, I've listed the tweaks below.

    • m.a = 2
    • m.b = 1
    • m.c = 0
    • m.d = 1

    I'm sure at this point you'd like to try out things yourself, so go ahead and tweak

    • the orientation of transformed y-axis while maintaining the x-axis
    • the orientation of both axes altogether

    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.as in 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.

    rotation explained

    ActionScript actually provides a method in the Matrix class, 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:

    
    
    var a:Number = 0.25*Math.PI
    m.a = Math.cos(a); m.c = -1*Math.sin(a);
    m.b = Math.sin(a); m.d = Math.cos(a); 

    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 isometric world
    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.

    
    
    velo = new Point(1, 0); //velo will be used to define x-axis
    axisY = new Point(0, 1);
    delta_positive = new Matrix(); delta_positive.rotate(Math.PI * 0.01); //positive rotation
    delta_negative = new Matrix(); delta_negative.rotate(Math.PI * -0.01); //negative rotation 

    Upon a key press, velo will 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 Matrix3d which is essential for 3D manipulations. Thanks for the read, terima kasih.


  3. Mark Dunne says:
    February 18, 2012 at 6:31 pm

    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:

    demo_link_particles

    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.

    stage.frameRate = 30;
    trace(stage.frameRate); //30
    

    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 String with your object. For holding MovieClips for example:

    var myVector.<MovieClip> = new Vector.<MovieClip>;
    

    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:

    Array: 2073ms
    Vector: 1476ms
    ----
    Reading Times
    Array: 190ms
    Vector: 134ms
    

    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_FRAME listener 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:

    • Huge speed increase
    • Much easier to reference other particles from particles

    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 extend anything) 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:

    Particle Memory: 1.53mb
    MovieClip Memory: 40.05mb
    

    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:

    Writing Times
    Particle: 334ms
    MovieClip: 2096ms
    ----
    Reading Times
    Particle: 16ms
    MovieClip: 22ms
    

    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:

    • The Bitmap class represents display objects that represent bitmap images
    • The BitmapData class Let’s you work with the data (pixels) of a Bitmap object

    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 graphics property 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 grinds to a halt after a few seconds
    • The createBitmapCircles() can keep running all day at 24/24 FPS and not slow down

    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.

    demo_link_particles

    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 :)


  4. Kah Shiu Chong says:
    February 18, 2012 at 7:02 pm

    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.

    Pixel by pixel checking.

    We will be doing literally this:

    1. Check if a1 and b1 share the same location.
    2. Repeat step (1) but now for a1 and b2.
    3. Repeat same between a1 and b3, b4 … b9.
    4. Repeat step (1) to (3) for a2, a3 … a9.

    There are a few observations that I’d like to point out.

    Observation Description
    Top left pixels The top left pixels for both bitmaps are used as the starting pixel for checkings. For example, a1 is the starting pixel checked against all pixels in b, which starts with b1. Both top left pixels.
    Scan-line progression As mentioned in previous point, checking is done in order of a1, a2, a3 … a9. Note the way these pixels are arranged.
    Common coordinate space Assume both graphics are added to the stage’s display list. The location of each pixel in both bitmaps, in the stage’s coordinate space, will be compared to see if any overlappings occur.
    Expensive computation For two 3×3 bitmaps, a maximum of 9×9 repetitions is required. If my bitmap size goes to 100×100, you can see how quickly the total calculation grows. However, if any one check returns a positive result then the remainder of the checks can be aborted, since when one pixel overlaps in both bitmaps, we can say that a collision happens between the bitmaps

    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.

    Not all pixels are filled.

    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 for alpha, say 0.5.

    So, assume that b2 and b8 are both pixels with alpha 0.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 BitmapData instances. You can imagine ActionScript taking an X-ray of a vector graphic, and transferring it to a BitmapData, 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 BitmapData are large enough to contain the drawing.)

    Here, CTree and Hook are 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 the BitmapData class.

    On each passing frame, we will update location of the top left pixel for each bitmap before putting instances of BitmapData through these rigourous hitTest() checks. Note as well that the range for alpha input 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.

    Transparency level.

    Another detail I mentioned just now is that ActionScript BitmapData‘s hitTest function alpha parameter 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:

    1. Use hitTestObject() to see if two objects’s bounding boxes have collided.
    2. If the answer is yes, then these two objects are pretty close. Proceed with pixel-level checking.
    3. If the answer is no, then these two objects are far apart. End collision checks without pixel-level checking.
    
    
    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.as from the source download.


    Conclusion

    Thanks for the read. In the next Quick Tip, we’ll be using matrices to transform BitmapData.


  5. Jason Killian says:
    February 18, 2012 at 7:50 pm

    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.

    • As you saw, there are 2 groups of a thousand. Not coincidentally, 1000 = 10*10*10 which can also be written as 103.
    • There are 3 groups of a hundred. Again, not coincidentally, 100 = 10*10 or 102.
    • There are 4 groups of ten, and, 10 = 101.
    • Finally, there are 7 groups of one, and 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*100
    • 1147 = 1*103+1*102+4*101+7*100
    • 53 = 5*101+3*100

    Admittedly, 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:

    Converting 523 from base-8 to base-10

    Here are a couple more examples:

    • 1118 = 1*82+1*81+1*80 = 64+8+1 = 7310
    • 438 = 4*81+3*80 = 32+3 = 3510
    • 61238 = 6*83+1*82+2*81+3*80 = 3072+64+16+3 = 315510

    Converting 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:

    1. 150/82 = 2 remainder 22
    2. 22/81 = 2 remainder 6
    3. 6/80 = 6

    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:

    Base-16 digits

    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:

    1. 696/162 = 2 remainder 184
    2. 184/161 = 11 remainder 8
    3. 8/161 = 8 remainder 0

    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:

    binary shirt

    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:

    1. 65/26 = 1 remainder 1
    2. 1/25 = 0 remainder 1
    3. 1/24 = 0 remainder 1
    4. 1/23 = 0 remainder 1
    5. 1/22 = 0 remainder 1
    6. 1/21 = 0 remainder 1
    7. 1/20 = 1 remainder 0

    And thus we get our binary number, 1000001.

    Understanding binary is super important. I've included a table below to point out digits' values.

    Powers of Two

    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:

    1. Convert number to base-10
    2. Convert result to desired base

    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:

    Base-8 to Binary

    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.


  6. James Tyner says:
    February 18, 2012 at 8:49 pm

    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

    SoundManager 2 HTML5 MP3 Player tutorial
    Click for a demo.

    In this tutorial I will show you how to create a JavaScript MP3 Player with jQuery and the SoundManager 2 JavaScript library that uses a hidden SWF file to play the sounds. (I could have used HTML5 Audio, but we would have lost the ID3 functionality, and so would have had to hard-code all of our artists and titles.)

    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.


  7. Tyler Seitz says:
    February 18, 2012 at 9:42 pm

    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:

    • Origin – The object or position that the orbit centers on.
    • Orbiter – The object that orbits the origin.
    • Angle – The current angle of the orbiter.
    • Speed – The number of pixels our object orbits per frame.
    • Radius – The orbiter’s distance from the origin.

    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)

    grid
    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, sin is used for the x-coord and cos is 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:

    
    
    public var orbiter:Orbiter = new Orbiter(); // The MovieClip That Orbits
    public var origin:Origin = new Origin(); // The MovieClip That Is Orbited
    public var angle:Number = 0; // The Initial Angle Orbiting Starts From
    public var speed:Number = 3; // Number Of Pixels Orbited Per Frame
    public var radius:Number = 75; // Orbiting Distance From Origin
    

    Next rewrite the equation for use in AS3 and put it into an ENTER_FRAME event handler function:

    
    
    var rad:Number = angle * (Math.PI / 180); // Converting Degrees To Radians
    orbiter.x = origin.x + radius * Math.cos(rad); // Position The Orbiter Along x-axis
    orbiter.y = origin.y + radius * Math.sin(rad); // Position The Orbiter Along y-axis
    

    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:

    
    
    angle += speed; // Object will orbit clockwise
    angle -= speed; // Object will orbit counter-clockwise
    

    Now what if we want our orbiter to continuously face a direction? Well I have written an equation to do just that!

    
    
    orbiter.rotation = (Math.atan2(orbiter.y-origin.y, orbiter.x-origin.x) * 180 / Math.PI);
    

    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 cos or sin functions 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:

    
    
    (2 * Math.cos(rad)); // Stretch the orbit along the x-axis by a factor of 2
    (0.5 * Math.sin(rad)); // Compress the orbit along the y-axis by a factor of 2 (i.e. halve it)
    (-3 * Math.cos(rad)); // Flip the orbit along the x-axis and stretch it by a factor of 3
    

    We can also shift the orbit in any direction we want by adding or subtracting from the equation on either axis:

    
    
    orbiter.x = (origin.x + radius * Math.cos(rad))-50; // Shift the orbit 50 pixels left on the x-axis
    

    If you want to learn more about cos, sin, and atan2, 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.


  8. Daniel Sidhion says:
    February 18, 2012 at 9:45 pm

    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.

    Initial popup

    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:

    Current behaviors in Construct 2

    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!

    Fun with events in Construct 2
    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:

    • You can make certain types of games, like platformers and shooters, within minutes
    • The behavior system is very intuitive and easy to use
    • You can make custom plugins for the tool, extending its abilities
    • Once you learn how to use the event system, you feel like a pro using the tool
    • Allows rapid prototyping

    Cons:

    • Isn’t descriptive enough
    • You WILL have to read many tutorials and guides to properly use the tool
    • Lacks many features for visually positioning and changing elements in the screen, such as quick aligning
    • Exports only as an HTML5 game

    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:

    • Beginner’s guide to Construct 2 – You won’t do a thing within Construct 2 without this
    • Adding sound – a beginner’s guide – For people who want to use sounds in the game
    • Animation Control – Event Based – Really helpful guide for animations and controlling them from a single place in the event sheet
    • Building a platform game – a beginner’s guide – Useful for learning the basics of a platformer game within Construct 2
    • How to series – ‘In Game Shop’ – Perfect for learning how to organize your variables and event sheets
    • About Picking – For understanding how the events pick objects
    • Randomized an array for a deck of cards – For learning to use arrays within Construct 2

    And you can see the game I created within three hours here:

    Construct 2 memory game
    Click to play

    The source files are available here.


  9. Amila Prabhath Senadheera says:
    February 18, 2012 at 9:53 pm

    In this tutorial, I’ll teach you how to create a visual representation of a sound file’s audio spectrum, using Flash’s SoundMixer.computeSpectrum method. We’ll use four classes for this effect: Sound, SoundChannel, SoundMixer, and ByteArray. I’ll explain each classes as we use them.


    Final Result Preview

    Let’s take a look at the final result we will be working towards:


    Click to view the demo

    Step 1: Set Up Your Flash File

    Launch Flash Pro and create a new Flash Document. Set the stage size to 500x300px, the background color to #000000, and the frame rate to 24fps.

    Setup Stage

    In your timeline, select the existing layer and rename it “Buttons”. Then click Window > Common Libraries > Buttons.

    Select your favorite button set, then drag and drop the ‘Play’ and ‘Stop’ buttons to the bottom-right corner of the stage.

    Library-Buttons

    Set the instance names of these buttons to play_btn and stop_btn, respectively.

    Step 2: Create the Document Class

    Create a new AS file, and save it as Main.as. Add this code (read the comments for more details):

    This code should be placed in our new Class:

    
    
    package  {
    	import flash.display.Sprite;
    	import flash.media.Sound; //The Sound class is the first step in working with sound. It is used to load a sound, play a sound, and manage basic sound properties.
    	import flash.net.URLRequest;
    
    	public class Main extends Sprite {
    		private var sound:Sound;
    		public function Main() {
    			sound = new Sound(new URLRequest("sound.mp3")); //assign music to the sound variable.
    			sound.play(); //play assigned sound.
    		}
    	}
    }
    

    You’ll need to put an MP3 file called sound.mp3 in the same directory as your FLA’s output directory. Any MP3 will do; on is included in the tutorial’s source download.


    Step 3: Document Class

    Add the class name to the Class field in the Publish section of the Properties panel to associate the FLA with the Main document class.

    If you’re not familiar with the concept of a document class,check out this Quick Tip before reading further.

    Publish section

    Then press Ctrl+Enter to test your Application.


    Step 4: Handling the Sound Using Buttons

    Let’s add an instance of a new class: SoundChannel. This class is used to keep different sounds in separate audio channels; each channel is created by an instance of SoundChannel, and we use these instances to control the sounds.

    
    
    package  {
    	import flash.display.Sprite;
    	import flash.media.Sound;
    	import flash.media.SoundChannel;
    	import flash.net.URLRequest;
    	import flash.events.MouseEvent;
    	public class Main extends Sprite {
    		private var sound:Sound;
    		private var channel:SoundChannel;
    
    		public function Main() {
    			sound = new Sound(new URLRequest("sound.mp3"));
    			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
    			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
    		}
    
    		private function onPlayHandler(event:MouseEvent):void{
    			channel = sound.play();
    		}
    
    		private function onStopHandler(event:MouseEvent):void{
    			channel.stop();
    		}
    	}
    }
    

    As you can see, when Play is clicked, we don’t just play the MP3, we also assign it to a SoundChannel. We can then control the playback through this SoundChannel instance later – in this case, by making it stop.


    Step 5: Create Simple Animation

    Now let’s create some simple animation for this sound, again using the SoundChannel class.

    
    
    package  {
    	import flash.display.Sprite;
    	import flash.media.Sound;
    	import flash.media.SoundChannel;
    	import flash.net.URLRequest;
    	import flash.events.MouseEvent;
    	import flash.events.Event;
    
    	public class Main extends Sprite {
    
    		private var sound:Sound;
    		private var channel:SoundChannel;
    
    		public function Main() {
    			sound = new Sound(new URLRequest("sound.mp3"));
    			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
    			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
    		}
    
    		private function onPlayHandler(event:MouseEvent):void{
    			channel = sound.play();//assign sound to channel class
    			addEventListener(Event.ENTER_FRAME,animateBars); //render the animation every frame
    		}
    
    		private function onStopHandler(event:MouseEvent):void{
    			channel.stop();
    			graphics.clear();
    			removeEventListener(Event.ENTER_FRAME,animateBars);//stop rendering the animation
    		}
    
    		private function animateBars(event:Event):void{
    
    			graphics.clear();
    
    			graphics.beginFill(0xAB300C,1);
    			//Draw a rectangle whose height corresponds to channel.leftPeak
    			graphics.drawRect(190,300,50,-channel.leftPeak * 160 );
    			graphics.endFill();
    
    			graphics.beginFill(0xAB300C,1);
    			//Draw a rectangle whose height corresponds to channel.rightPeak
    			graphics.drawRect(250,300,50,-channel.rightPeak  * 160 );
    			graphics.endFill();
    		}
    	}
    }
    

    The leftPeak and rightPeak properties of a SoundChannel instance correspond to the current amplitude of the sound, through the left and right channels. Think of it this way: if you have stereo speakers, then leftPeak is the volume of the sound coming out of the left speaker, and rightPeak is the volume of the sound coming out of the right speaker.

    You can press Ctrl+Enter to test your application:

    Sound Bar Animation

    Step 6: What Is SoundMixer?

    The SoundMixer class controls all embedded and streaming sounds in the application, for all SoundChannels at once.

    It has three methods: areSoundsInaccessible(), which determines whether any sounds are inaccessible due to security reasons; stopAll(), which stops playback of all sounds; and computeSpectrum(), which is what we’re interested in for this tutorial. The latter method takes a “snapshot” of the current sound, and pushes it into a ByteArray object.


    Step 7: What Is ByteArray?

    The ByteArray class provides methods and properties to optimize reading, writing, and working with binary data. It stores data as an array of bytes, hence its name. Find out more with this Introduction to ByteArray.


    Step 8: More Complex Animation

    So now let’s create a more complex animation using the SoundMixer.computeSpectrum() method. Again, read the comments in the code to fully understand the behavior:

    
    
    package {
    	import flash.display.Sprite;
    	import flash.media.Sound;
    	import flash.utils.ByteArray;
    	import flash.events.Event;
    	import flash.media.SoundMixer;
    	import flash.filters.GlowFilter;
    	import flash.net.URLRequest;
    	import flash.events.MouseEvent;
    	import flash.media.SoundChannel;
    
    	public class Main extends Sprite{
    		private var sound:Sound;
    		private var channel:SoundChannel;
    		private var byteArr:ByteArray = new ByteArray();
    		private var glow:GlowFilter = new GlowFilter();
    		private var filterArr:Array;
    		private var line:Sprite = new Sprite();
    
    		public function Main(){
    			// create a "glow" effect for the animation we will render
    			glow.color = 0x009900;
    			glow.alpha = 1;
    			glow.blurX = 10;
    			glow.blurY = 10;
    
    			// load your MP3 in to the Sound object
    			sound = new Sound(new URLRequest("sound.mp3"));
    			// apply the glow effect
    			filterArr = new Array(glow);
    			line.filters = filterArr;
    			addChild(line);
    
    			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
    			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
    		}
    
    		private function onPlayHandler(event:MouseEvent):void{
    			channel = sound.play(0,1000);
    			addEventListener(Event.ENTER_FRAME,spectrumHandler);
    		}
    
    		private function onStopHandler(event:MouseEvent):void{
    			channel.stop();
    			line.graphics.clear();
    			removeEventListener(Event.ENTER_FRAME,spectrumHandler);
    		}
    
    		private function spectrumHandler(event:Event):void{
    			line.graphics.clear();
    			line.graphics.lineStyle(1,Math.random() * 0xFFFFFF);
    			line.graphics.moveTo(-1,150);
    			// push the spectrum's bytes into the ByteArray
    			SoundMixer.computeSpectrum(byteArr);
    
    			for (var i:uint=0; i<256; i++){
    				// read bytes and translate to a number between 0 and +300
    				var num:Number = byteArr.readFloat() * 150 + 150;
    				//use this number to draw a line
    				line.graphics.lineTo(i*2,num);
    			}
    		}
    	}
    }
    

    The most important parts of this code are lines 53 and 57. Here, the whole sound wave is translated to a ByteArray, which is then read, byte by byte, and translated into a set of numbers.

    The ByteArray will be 512 floats long; in the for loop, we only read the first 256 floats, which correspond to the entire sound wave of the left channel (the sound coming through the left speaker).

    Press Ctrl+Enter to test your Application.

    Sound Line Animation

    Step 9: Fill in the Gaps

    We can fill in the area underneath the line to give us a different effect:

    Complex Drawing Animation

    All we need to do is draw a box and fill it in, using graphics methods. The code for this is as follows:

    
    
    package {
    	import flash.display.Sprite;
    	import flash.media.Sound;
    	import flash.utils.ByteArray;
    	import flash.events.Event;
    	import flash.media.SoundMixer;
    	import flash.filters.GlowFilter;
    	import flash.net.URLRequest;
    	import flash.events.MouseEvent;
    	import flash.media.SoundChannel;
    
    	public class Main extends Sprite{
    		private var sound:Sound;
    		private var channel:SoundChannel;
    		private var byteArr:ByteArray = new ByteArray();
    		private var glow:GlowFilter = new GlowFilter();
    		private var filterArr:Array;
    		private var line:Sprite = new Sprite();
    
    		public function Main(){
    			glow.color = 0xFF0000;
    			glow.alpha = 1;
    			glow.blurX = 10;
    			glow.blurY = 10;
    
    			sound = new Sound(new URLRequest("sound.mp3"));
    
    			filterArr = new Array(glow);
    			line.filters = filterArr;
    			addChild(line);
    			addChild(play_btn);
    			addChild(stop_btn);
    
    			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
    			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
    		}
    
    		private function onPlayHandler(event:MouseEvent):void{
    			channel = sound.play(0,1000);
    			addEventListener(Event.ENTER_FRAME,spectrumHandler);
    		}
    
    		private function onStopHandler(event:MouseEvent):void{
    			channel.stop();
    			line.graphics.clear();
    			removeEventListener(Event.ENTER_FRAME,spectrumHandler);
    		}
    
    		private function spectrumHandler(event:Event):void{
    			// draw one edge of the box, and specify a fill
    			line.graphics.clear();
    			line.graphics.beginFill(0xFF0000,1);
    			line.graphics.lineStyle(1,0xFF0000);
    			line.graphics.moveTo(-1,150);
    			SoundMixer.computeSpectrum(byteArr);
    
    			for (var i:uint=0; i<256; i++){
    				var num:Number = byteArr.readFloat() * 200 + 150;
    				line.graphics.lineTo(i*2,num);
    			}
    
    			//draw the rest of the box
    			line.graphics.lineTo(512,300);
    			line.graphics.lineTo(0,300);
    			line.graphics.lineTo(-1,150);
    		}
    	}
    }
    

    Step 10: Try Something Different

    We can take this idea further, to add even more interesting and complex effects:

    Complex Drawing Animation

    In this case, we’ll draw two spectra on top of each other, one for the left channel and one for the right. To achieve this, we’ll use two for loops that each read in 256 floats, one after the other.

    
    
    package {
    	import flash.display.Sprite;
    	import flash.media.Sound;
    	import flash.utils.ByteArray;
    	import flash.events.Event;
    	import flash.media.SoundMixer;
    	import flash.filters.GlowFilter;
    	import flash.net.URLRequest;
    	import flash.events.MouseEvent;
    	import flash.media.SoundChannel;
    
    	public class Main extends Sprite{
    		private var sound:Sound;
    		private var channel:SoundChannel;
    		private var byteArr:ByteArray = new ByteArray();
    		private var glow:GlowFilter = new GlowFilter();
    		private var filterArr:Array;
    		private var line:Sprite = new Sprite();
    		private var num:Number;
    		public const GRAFT_HEIGHT:int = 150; //set animation height
    		public const CHANNEL_SIZE:int = 256; //set left/right channel size
    
    		public function Main(){
    			glow.color = 0x009900;
    			glow.alpha = 1;
    			glow.blurX = 10;
    			glow.blurY = 10;
    
    			sound = new Sound(new URLRequest("sound.mp3"));
    
    			filterArr = new Array(glow); //add glow to the animation
    			line.filters = filterArr;
    			addChild(line);
    
    			play_btn.addEventListener(MouseEvent.CLICK,onPlayHandler);
    			stop_btn.addEventListener(MouseEvent.CLICK,onStopHandler);
    		}
    
    		private function onPlayHandler(event:MouseEvent):void{
    			channel = sound.play(0,1000); // play sound 1000 times
    			addEventListener(Event.ENTER_FRAME,spectrumHandler);
    		}
    
    		private function onStopHandler(event:MouseEvent):void{
    			channel.stop();
    			line.graphics.clear();
    			removeEventListener(Event.ENTER_FRAME,spectrumHandler);
    		}
    
    		private function spectrumHandler(event:Event):void{
    			num = 0;
    
    			line.graphics.clear(); // create current graphics
    			line.graphics.lineStyle(0, 0x00FF00);
    			line.graphics.beginFill(0x00FF00,0.5);
    			line.graphics.moveTo(0,GRAFT_HEIGHT);
    
    			SoundMixer.computeSpectrum(byteArr);// add bytes to Sound mixer
    
    			for (var i:int = 0; i < CHANNEL_SIZE; i++) {
                    		num = (byteArr.readFloat() * GRAFT_HEIGHT);
                    		line.graphics.lineTo(i * 2, GRAFT_HEIGHT - num);
                		}
    
    			line.graphics.lineTo(CHANNEL_SIZE * 2, GRAFT_HEIGHT);
    			line.graphics.endFill();
    
    			line.graphics.lineStyle(0, 0xFF0000);
    			line.graphics.beginFill(0xFF0000, 0.5);
    			line.graphics.moveTo(CHANNEL_SIZE * 2,GRAFT_HEIGHT);
    
    			for (i = CHANNEL_SIZE; i > 0; i--) {
    				num = (byteArr.readFloat() * GRAFT_HEIGHT);
    				line.graphics.lineTo(i * 2, GRAFT_HEIGHT - num);
    			}
    
    			line.graphics.lineTo(0, GRAFT_HEIGHT);
    			line.graphics.endFill();
    		}
    	}
    }
    

    Conclusion

    So we have learnt how to use the various Sound classes, and how to create beautiful sound drawing animations using SoundMixer.

    Thank you for taking the time to read this article, because this is my first tutorial. If you have any questions, please leave them in a comment.


  10. Michael James Williams says:
    February 18, 2012 at 10:32 pm

    Creating little browser extensions is a great way to learn JavaScript. You don’t need to worry about cross-browser compatibility, you can make the project as small or large as you like, and you can fix problems in other people’s websites that bug you, specifically. In this post, we’ll create a short script that automatically rearranges Tumblr archive pages to read in chronological order – and we’ll learn about NodeList on the way.


    The Problem

    This week, Ryan North started a new Tumblr, in which he’s going through the novelization of the first Back to the Future movie, one page at a time. This is a thing I wish to read.

    BtotheFClick to read.

    However, Tumblr displays its posts in reverse chronological order – that is, with the most recent posts first. This makes sense for a lot of sites on Tumblr, but in this instance, I really want to read them in the order they were written. The current site layout means that, to do that, I have to scroll down to the top of the first (first written) post, scroll down as I read it, and then scroll up to the top of the second post, and scroll down through that…

    This is a tiny, tiny first world problem – totally trivial and almost embarrassing to mention. But that doesn’t mean I don’t want to fix it.

    By the end of this tutorial, you’ll make this Tumblr – or any Tumblr you choose – display its posts in chronological order on the page, automatically.


    How Can We Do This?

    We don’t have control over the BtotheF site design; it offers no options to us, so we can’t change the order in which the posts are displayed on the page server-side.

    But once the HTML is sent to the browser, it’s ours. We can manipulate it however we want. And, of course, the language with which we can do this is JavaScript.

    I’ll give a quick demo. I’ll be using Chrome, and recommend that you do, too – if you can’t, or don’t want to, then grab a copy of Firebug.

    Browse to http://btothef.tumblr.com/ and open the JavaScript console (Tools > JavaScript Console, in Chrome). Type:

    
    
    alert("Hi");
    

    …and hit Enter.

    JavaScript Console Demo

    Wow! … Okay, fine, that didn’t prove much. Try this:

    
    
    document.body.appendChild(document.createTextNode("Hi"));
    

    This will take the HTML document’s <body> element, and append a new text node – a piece of text, basically – containing the word “Hi”. If you didn’t follow any of that, get up to speed with HTML.

    To see the result, scroll right down to the bottom of the Tumblr:

    JavaScript Console Demo

    Slightly more impressive, since we’ve actually changed the contents of the page. The new text node is right at the bottom because we’ve used appendChild() – which adds the specified node after everything else inside the <body>. As far as our browser is concerned, the last few lines of HTML now look like this:

    
    
    <!-- END TUMBLR CODE -->
    
    Hi
    </body>
    </html>
    

    So! Now we have two issues:

    1. How do we use JavaScript to rearrange all the posts in the page?
    2. How do we make this happen automatically, without having to mess around in the console every time we read the Tumblr?

    We’ll address these in order.


    Rearranging the Posts

    First, let’s figure out how to “find” all of the posts in the HTML. In Chrome, right-click somewhere in the top post, and select “Inspect element”. (Firebug should add the same shortcut to Firefox; for other browsers, try the magnifying glass icon.)

    Inspect Element (Chrome)

    The Elements tab of the Developer Tools will appear, with the element you selected highlighted:

    Elements Tab

    As you hover over different elements in this HTML view, you’ll see them highlighted in the page itself. Eventually, you’ll find that the entire post is contained in a div with a class of post. As you can see from the screenshot above, there are several other such div elements, and they are all contained in a master div with an id of contents.

    We can select all of these post elements at once with a single line of code; type this into the JavaScript console:

    
    
    document.getElementById("contents").getElementsByClassName("post");
    

    (Technically, we could have just written document.getElementsByClassName("post"), but who cares?)

    You’ll see – again, in Chrome – some feedback:

    All the posts

    Great! This indicates that it worked. If you click the arrows, you’ll see the contents of each div.

    We might as well assign this to a variable, to save us having to type it out over and over:

    
    
    var posts = document.getElementById("contents").getElementsByClassName("post");
    

    (This time, the console will return undefined; you can check that it assigned the variable correctly by just typing the word posts in the console.)

    We can loop through all of the elements in posts as if it were an array:

    
    
    for (var i=0; i < posts.length; i++) {
         console.log(posts[i]);
    }
    

    Hit Shift-Enter to add a new line to your code without running it, in the JavaScript console. console.log() just traces its contents to the console, which is far less annoying than an alert() and far less disruptive than adding text to the HTML DOM.

    The result of this simple loop will just be a list of all the div elements. Cool. So presumably we can do something like this…

    
    
    var numPosts = posts.length;
    for (var i=numPosts - 1; i >= 0; i--) {
         posts.push(posts[i]);
    }
    

    Try it out! You’ll see this:

    
    
    TypeError: Object #<NodeList> has no method 'push'
    

    Rats.

    A NodeList Is Not an Array

    When we use getElementsByClassName(), we don’t retrieve a simple array of elements, we retrieve a NodeList. Like an array, this is a collection of elements; unlike an array, the collection is updated in real time. If the HTML DOM is modified, the contents of posts gets modified to match.

    For example, let’s create a new div with a class of post and append it to the contents div:

    
    
    var newPostDiv = document.createElement("div");
    newPostDiv.setAttribute("class", "post");
    document.getElementById("contents").appendChild(newPostDiv);
    

    Run that, then type posts and hit Enter. You’ll see an extra div in the list – even though we haven’t touched the posts variable.

    Since a NodeList is not an array, it doesn’t have most of the methods and properties of Array, such as push() In fact, we’ve already used the only property: length. The only method is .item(n), which just gets the nth item in the list.

    However, our earlier demonstration with appendChild() does suggest an alternative solution: what if, instead of trying to rearrange the elements of the NodeList within the NodeList, we rearranged them within the page?

    First, we’ll run through the list in reverse order, and append each element in turn to the contents div; then, we’ll remove the original posts.

    Refresh the Tumblr page to clear out all the extra rubbish we’ve added to the DOM, then do the first step, of adding the elements in reverse order:

    
    
    //have to define posts again, since we lost it when we refreshed
    var posts = document.getElementById("contents").getElementsByClassName("post");
    var numPosts = posts.length;
    for (var i=numPosts - 1; i >= 0; i--) {
         document.getElementById("contents").appendChild(posts[i]);
    }
    

    Okay, now we… wait, what?

    description of image

    The (chronological) first post is already at the top, and the last post is at the bottom, with no posts repeated. This may seem surprising, but it makes sense: we didn’t clone any elements of the NodeList, we just appended them to the contents div, in reverse order. Since the NodeList always reflects the contents of the HTML DOM, we just moved each of the 11 elements to a new position – the 11th element got added to the end (no change in position); then the 10th got moved to be after that; the 9th after that, and so on, until the 1st element was right at the end.

    So, problem solved, in five simple lines of code. Now let’s automate it.


    Turning It Into a Browser Extension

    Three of the top four browsers allow you to create browser extensions – installable add-ons – using JavaScript. (It will not surprise you to learn that Internet Explorer is the exception.) Here are the instructions for Chrome, the instructions for Firefox, and the instructions for Safari.

    But we’re not going to use any of those. Instead, we’ll use a great add-on called Greasemonkey, which allows you to install little JS scripts without needing to package them up as full-blown browser extensions. Essentially, it injects snippets of JavaScript into the page, once it’s loaded.

    Chrome already has Greasemonkey support baked in. Opera has something very similar to Greasemonkey baked in: UserJS. For Firefox, you’ll need to install the Greasemonkey extension. For Safari, install SIMBL, and then GreaseKit. For IE, install IE7Pro or Trixie.

    Writing the Greasemonkey Script

    Create a new text file, and name it ChronologicalTumblr.user.js. Make sure you remove the default .txt extension, and that you use .user.js, rather than just .js – this is the extension for a Greasemonkey script.

    Copy our post rearrangement code into the file:

    
    
    var posts = document.getElementById("contents").getElementsByClassName("post");
    var numPosts = posts.length;
    for (var i=numPosts - 1; i >= 0; i--) {
         document.getElementById("contents").appendChild(posts[i]);
    }
    

    Now, we need to add some extra metadata at the top of the script – details about the script itself. All these details should go in comments, starting with ==UserScript== and ending with ==/UserScript==:

    
    
    // ==UserScript==
    //
    // ==/UserScript==
    
    var posts = document.getElementById("contents").getElementsByClassName("post");
    var numPosts = posts.length;
    for (var i=numPosts - 1; i >= 0; i--) {
         document.getElementById("contents").appendChild(posts[i]);
    }
    

    First, we’ll add a name and a description:

    
    
    // ==UserScript==
    // @name          Chronological Tumblr
    // @description	  Displays Tumblr posts in chronological order
    // ==/UserScript==
    
    var posts = document.getElementById("contents").getElementsByClassName("post");
    var numPosts = posts.length;
    for (var i=numPosts - 1; i >= 0; i--) {
         document.getElementById("contents").appendChild(posts[i]);
    }
    

    Then, we’ll specify a namespace. The combination of the name and the namespace is what uniquely identifies the script; if you try to install another Greasemonkey script with the same name and namespace as an existing script, it will overwrite the old one – if only the name or the namespace match, it’ll just install the new one alongside the old.

    It’s common to use a URL here, so I’ll use Activetuts+’s. You should use your own, since you’re in control of it:

    
    
    // ==UserScript==
    // @name          Chronological Tumblr
    // @description	  Displays Tumblr posts in chronological order
    // @namespace      http://active.tutsplus.com/
    // ==/UserScript==
    
    var posts = document.getElementById("contents").getElementsByClassName("post");
    var numPosts = posts.length;
    for (var i=numPosts - 1; i >= 0; i--) {
         document.getElementById("contents").appendChild(posts[i]);
    }
    

    Now we need to specify which URLs this script should affect – that is, on which web pages the JavaScript should automatically be injected into. I want this script to work on the BtotheF homepage, plus the other archive pages, like http://btothef.tumblr.com/page/2:

    
    
    // ==UserScript==
    // @name          Chronological Tumblr
    // @description	  Displays Tumblr posts in chronological order
    // @namespace      http://active.tutsplus.com/
    // @include       http://btothef.tumblr.com/
    // @include       http://btothef.tumblr.com/page/*
    // ==/UserScript==
    
    var posts = document.getElementById("contents").getElementsByClassName("post");
    var numPosts = posts.length;
    for (var i=numPosts - 1; i >= 0; i--) {
         document.getElementById("contents").appendChild(posts[i]);
    }
    

    The * is a wildcard; it ensures that the script will be inserted into every single archive page of the BtotheF Tumblr.

    We could use a wildcard to make every single Tumblr’s archive pages display in chronological order:

    
    
    // ==UserScript==
    // @name          Chronological Tumblr
    // @description	  Displays Tumblr posts in chronological order
    // @namespace      http://active.tutsplus.com/
    // @include       http://*.tumblr.com/
    // @include       http://*.tumblr.com/page/*
    // ==/UserScript==
    
    var posts = document.getElementById("contents").getElementsByClassName("post");
    var numPosts = posts.length;
    for (var i=numPosts - 1; i >= 0; i--) {
         document.getElementById("contents").appendChild(posts[i]);
    }
    

    In this case, it might be a good idea to improve your script to insert a button or link into the page that rearranges the posts when clicked. That way, you can use it when appropriate, without having to manually add every single Tumblr’s URL as an @include parameter.

    There are other metadata parameters you could add, but this is all we need for now.

    Finishing Off

    Installing the script in Chrome is easy: just drag and drop it from your hard drive into a browser window. It’ll warn you that scripts could potentially be dangerous (just click Continue), and then check again that you want to install this specific one:

    Are you sure?

    Hit Install. If you’re using another browser, refer to the relevant Greasemonkey script’s manual – in any case, it’ll be simple.

    Once it’s installed, you can see it in your list of extensions:

    Just like any other extension.

    Head back to http://btothef.tumblr.com/, or hit refresh if you still have it open.

    description of image

    The posts are now automatically displaying in chronological order!

    It’s not perfect: you may have noticed that the navigation buttons have been moved to the top of the page, since they are contained in a div with a class of post. But hey – if that bugs you, you have the tools to fix it now.


Leave a Reply

Click here to cancel reply.

search search search search search
Find an Article
Categories
  • Flash Video Training
  • Hints and Tips
  • Recommended
Please Support Our Sponsors
Recent Posts
  • Workshop Coding Challenge: Fix This Breakout Game
  • Enable the Latest AIR SDK in Flash Professional CS5.5+
  • Quick Tip: Versioning Your Files With Dropbox (via Webdesigntuts+)
  • Workshop: Nuclear Outrun – Critique
  • Understanding Variables, Arrays, Loops, and Null: The Post-it Note Analogy
Tag Cloud
2011 ActionScript Active Activetuts+ Adobe animation Basic Basix Best Build Button Character Create Creating Critique Custom design Effect Effects Files Flash from Game Guide HTML5 Introduction Macromedia Motion Muzzle part Player Premium Professional Quick Silverlight Simple Text Tool Tutorial Tuts+ Tween Using Video website Workshop
About Our Site:

Hey there and welcome to "Flash Video Training Source", a resource for anybody interested in learning more about Adobe's great tool. We feature educational videos, which will help you master Adobe Flash and help you get to know all of its features. We at "Flash Video Training Source" believe that video training and video... more

Why don't you follow us on Twitter and get the latest video tutorials twitted to your account. Just click on the floating twitter bar to your right!

Go Back In Time
May 2012
M T W T F S S
« Apr    
 123456
78910111213
14151617181920
21222324252627
28293031  
Pretty Blank Box
top

Blogroll

  • Development Blog
  • Documentation
  • Plugins
  • Suggest Ideas
  • Support Forum
  • Themes
  • WordPress Planet

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Archives

  • May 2012
  • April 2012
  • March 2012
  • February 2012
  • January 2012
  • December 2011
  • November 2011
  • October 2011
  • September 2011
  • August 2011
  • July 2011
  • June 2011
  • May 2011
  • April 2011
  • March 2011
  • February 2011
  • January 2011
  • December 2010
  • November 2010
  • October 2010
  • September 2010
  • August 2010
  • July 2010
  • June 2010
  • May 2010
  • April 2010
Powered by WordPress  |  Designed by Elegant Themes  |  Lightning Fast Hosting by Site 5 Hosting