This website uses cookies to improve user experience. By using our website you consent to all cookies in accordance with our Cookie Policy. X

Top 5 things that kill Flash's framerate.

Without a doubt most of us heard that Flash might be slow at times and even thought with each version it gets faster and faster, there are still games out there that might bring even most powerful PC to its knees. Surprisingly enough it might not necessarily be the programmers fault, but actually those inconspicuous graphic designers doing - that's right, ActionScript (especially 3) is already so fast, its contribution to the slowdowns might be marginal compered to some graphically intensive designs. That is why it is time to give those programmers a break and check if we accidentally aren't using any of the 5 most demanding graphics elements:
1. Filters.
Undisputed winner in Flash slow downs, one unfortunately placed filter can turn a smooth animation into a slide show. Not to get into too much details, any MovieClip that has a filter applied to it stops being a vector graphic and is instead turned into a bitmap - with bitmap itself not being a problem but rather the process of creating one. Which is why you need to remember those two things when working with bitmaps:
- avoid bulky graphics (no bigger than average website banner)
- avoid filtered animations (for reasons stated below in: "cache as bitmap")
2. Cache as bitmap.
I must say bitmaps in Flash are quite intriguing; for example lets take simple a red rectangle drawn in vector graphic and in a bitmap - in this case Flash will display the vector one much faster than the bitmap one. However, start filling that rectangle with decorations, patterns or gradients and soon enough it will turn out that the bitmap solution is the faster one. Where lies the boundary? Well, that is something everyone should find out on their own, but generally just adding a simple gradient makes for a good reason to go with the "cache as bitmap" option. Unfortunately, every rose has its thorn... bitmaps can bring great speedups but also massive slowdowns, as even a simple transformation (changing colors, scaling, rotation) might bring devastating results. So when working with bitmaps always remember:
- cache as bitmap is completely pointless on animated MovieClips.
- bitmaps and cached MovieClips are very slow with any kind of transformations.
- if you must, it is much better to transform a real bitmap rather than a MovieClip with "cache as bitmap".
3. Alpha (transparency).
Yeah I know, "give up on transparency? Forget it!" Even so there is a good reason why it takes a third place on this list - this silent assassin doubles the amount amount of time needed to draw a pixel on the screen for each transparent bit. So whenever possible, instead of yet again making another semi-transparent shape to serve as a shadow, actually take a moment to really shade the background graphics.
4. Excessive amount of MovieClips.
It is very easy to get accustom to the possibilities that MovieClips provide, since they are so easy to swap around, edit without affecting outside elements and most importantly clone to bring infinite details into scenes. Of course those features don't come without a price and we have to pay with performance. Each MovieClip on a scene added not only new graphics but also ton of parameters: position, scale, filters, colors, name, visibility, caching etc. and even thought you might not be using them at all, all of them are processed on each frame of animation. Whenever possible try to replaces MovieClips with Graphic objects (or better yet just Shapes).
5. Hidden objects.
In other words everything that we don't, but it is still there. The worst case example of this is masking, as everything under them is still rendered on the screen but afterwards only cut down to fit the designed boundaries . The exact same thing happens with Flash's display area, which also doesn't remove anything, which means every object on the scene impacts the performance the exact same way, no matter on screen or not.

Seek Bar in Flash [basic]

Happy New Year 2012!

Often on the Internet I see people asking how to make a seek bar in a Flash animation (similar to how other video players do it, such as the one used on YouTube) however in the end not many people go through with it - why is that? The answer lays in how Flash handles MovieClips, which is why before I go any further I will take a moment to write few words about them.
It might be hard to visualize it, but each MovieClip is a self contained movie with its own time-line (and settings) and is controlled completely independently of any other objects, which can be seen below (pick any moment, right click and uncheck "play"):

As one might expect the whole animation will be instantly stopped... except for the ball which is a MovieClip. No point in explaining why is that - it just is and will never change. Only thing left to do is to look for alternative solutions, and because stopping all the MovieClips will directly help us with creation of a seek bar it is best to look at two possible workarounds:
1. Remove all the graphics in your animation.
2. Manually stop all the MovieClips with ActionScript.
First solution is the best way to go, as long as you are just starting the creation of your movie, because it is always easier to prepare it beforehand than later convert all the MovieClips into Graphic objects. Afterwards moving around the animation will only require a single call to the gotoAndPlay function, which is exactly what we need for our seek bar. Second solution is only viable in animations with small amount of MovieClips, because seeking and stopping the MovieClips might be a bit too stressful for the processor, especially in the case of a seek bar since it requires a scan through the whole movie. Oh well, sometimes you just don't have a choice.
Code that stops all MovieClip is actually quite simple:
stopMovies(root as MovieClip);
function stopMovies(mc:MovieClip):void {
	for(var i:int = 0; i<mc.numChildren; i++) {
		var d:DisplayObject = mc.getChildAt(i);
		if(d is MovieClip) {
			(d as MovieClip).stop();
			stopMovies(d as MovieClip);
		}
	}
}
Now one might think that the only thing missing here is a gotoAndPlay function and we are set. Unfortunately it is not that simple, as each MovieClip has its own time-line, in will never react to changes in the main time-line (contrary to Graphic objects). Furthermore, replacing every stop function with gotoAndPlay is also pointless as having the main animation on 10th frame does not necessarily mean that each MovieClip is also on the 10th frame - it all comes down to the fact that MovieClip appearing on the, for example, 6th frame, on 10th one will be in 4th frame of its own time-line. It is best to see this in action - animation below has a MovieClip (with 20 frames) appearing on the 10th frame (all of them numbered):
While scrolling, the MovieClip appears to have a mind of his own.
Okay, but why not take the appearing position of the MovieClip and subtract it from the current position? Lets say we want to go to the frame #15 with the MovieClip appearing on the 10th one, so we just take 10 and subtract it from 15 resulting in gotoAndPlay(5) - main time-line stays on 15 while our MovieClip is re-winded to the 5th frame. This is a great idea and perfect solution, but unfortunately Flash has no way of telling us what is the MovieClip's appearing frame. Here is where the challenge for the processor I was talking about earlier comes in, as the next step would be to write down all the starting positions of each MovieClip; which isn't as easy as it sounds, because an animation that takes, for example, 1 minute to play out and is displayed at 20 frames per second, will have 1200 frames worth of scanning! Plus, lets say, 10 MovieClips per frame... Least to say, it is not a very useful solution, which is why for the rest of this article I will assume you are using only Graphic objects.
That is it for theory, time to create our seek bar - taking the bare minimum, we will need MovieClips: a bar representing the length of our whole animation and a marker showing the current position. To make this easier put both of them in a time-line of separate MovieClip (the whole seek bar will be in one place making it easier to, for example, move it between projects) and name them mcBar and mcMarker (instance name). Finally put this code into the time-line of the enclosing MovieClip (one holding the bar and the marker):
import flash.events.MouseEvent;
import flash.events.Event;
import flash.display.MovieClip;

var bSeek:Boolean = false;
var nLength:Number = mcBar.width-mcMarker.width;
mcMarker.mouseEnabled = false;
mcMarker.mouseChildren = false;

if( !mcBar.hasEventListener(MouseEvent.MOUSE_DOWN) ) {
	//to prevent unnecessary duplications on each loop
	mcBar.addEventListener(MouseEvent.MOUSE_DOWN,onSeekStart);
	mcBar.stage.addEventListener(MouseEvent.MOUSE_MOVE,onSeekDrag);
	mcBar.stage.addEventListener(MouseEvent.MOUSE_UP,onSeekStop);
	mcBar.stage.addEventListener(Event.ENTER_FRAME,onRender);
}

function onRender(e:Event):void {
	if(bSeek) return;
	mcMarker.x = ((root as MovieClip).currentFrame/(root as MovieClip).totalFrames)*nLength;
}
function onSeekStart(e:MouseEvent):void {
	bSeek = true;
	onSeekDrag(e);
}
function onSeekDrag(e:MouseEvent):void {
	if(!bSeek) return;
	
	mcMarker.x = mcBar.mouseX;
	if(mcMarker.x > nLength) {
		mcMarker.x = nLength;
	} else if(mcMarker.x<0) {
		mcMarker.x = 0;
	}
	
	var frame:int = int((mcMarker.x/nLength)*(root as MovieClip).totalFrames);
	
	(root as MovieClip).gotoAndStop(frame);
	mcMarker.x = (frame/(root as MovieClip).totalFrames)*nLength;
}
function onSeekStop(e:MouseEvent):void {
	bSeek = false;
	(root as MovieClip).play();
}
Nothing particularly complicated here - clicking on the seek bar moves the marker there and translates its X coordinate into the animation's position.
The whole code + an example how to use it can be download from here: seekbar.zip
And for anyone who wants to try the MovieClip scanning solution I prepared a special class and an example to go with it: seekbarEX.zip. In this case, to avoide conflicts with the animation itself, MovieClip which holds both the marker and the bar is exported for ActionScript with ForusSeekBar class.

Singletons in Flash [basic]

In today's post I will write a little about singletons, which are objects that exist in only one instance - what are they, how to make them in Flash and what are they useful for.
Singleton is a design pattern and like many of those it might appear to overcomplicate things that can be done it much simpler way, however the truth is in return we get much cleaner and more specialized code which is especially useful when working in bigger group or when we often go back to older projects that we have already forgotten, although even smaller, single handily crafted applications will benefit from this solution.
When creating a singleton class we want to have only one object for it in the whole system, in such way that we will always access the same properties independently of the calling location. In most well-known programming languages it can be done by simply writing:
private class Single {
	private static const instance:Single = new Single();
	private function Single():void { }
	public static function getInstance():Single {
		return instance;
	}
}
Unfortunately it won't be the case for Flash, since it doesn't support constructors in private space, which is why we have to work around this problem usually by introducing a parameter that third party won't be able to supply correctly:
public class Singleton {
	private static const instance:Singleton = new Singleton(getInstance);
	public var myVar:Number;
	public function Singleton(f:Function = null) {
		if(f != getInstance) throw new Error("You cannot instance Singleton! Use getInstance() instead.");
		myVar = 5;
	}
	public static function getInstance():Singleton {
		return instance;
	}
}
Well, that is pretty much it, however it is hard to point out any particular advantage for Singletons in this example, that is why we will for something a bit more complex, i.e. application's sound controlling class. Usually in case like this we want to hold all sounds in once place to easily read, play and pause them at the same time, which is a perfect reason to use the singleton pattern like this one (in very simplified form):
public class SoundControl {
	private static var instance:SoundControl;
	private var bIsLoading:Boolean;
	private var aQueue:Array;
	private var aSounds:Array;
	public function SoundControl(f:Function = null) {
	if(f != getInstance) throw new Error("You cannot instance SoundControl! Use getInstance() instead.");
		aSounds = new Array();
		aQueue = new Array();
	}
	public function play(name:String):void {
		if(bIsLoading) {
			aQueue.push(name);
		} else {
			aSounds.push( new Sound(name) );
			/* play sound */
		}
	}
	public function stopAll():void {
		for each(var snd:Sound in aSounds) {
			snd.stop();
		}
		aQueue = new Array();
	}
	private function loadAll():void {
		bIsLoading = true;
		/* load all sounds and call onLoaded when done */
	}
	private function onLoaded():void {
		bIsLoading = false;
		/* play all sounds stored in aQueue */
	}
	public static function getInstance():Singleton {
		if(instance == null) {
			instance = new SoundControl(getInstance);
			instance.loadAll();
		}
		return instance;
	}
}
SoundControl seems to do a lot, but an "outside" person will only see three functions: getInstance(), play() and stopAll(), which is enough to properly control all the sounds in the application, while leaving all the dirty work (volume control, channel assigning, resources managing etc.) to us, the class creators. Additionally we will always be certain that no one will create their own private SoundControl to play sounds that no one else would be able to access because they belong to a different SoundControl object than the one we all agreed to use...

Basics of Stage3D part II: camera movement and pointAt function [expert]

In the previous part of this article I wrote about extending an ActionScript3 Documentation example of 3D graphics to make it work with multiple objects in such way that every object could still be transformed separately. The example also has a bit about the matrix used for camera movement ("view"), which truth to be told did not work like it should because it was missing some basic set-up. And this is where it gets unpleasant for people that are new to the 3d graphics, as information available on the Internet about that set-up are rather mixed and mostly confusing, especially since proper camera movement will actually depend on 3D environment settings. That is why this part of Stage3D basics article will be dedicated to virtual camera and its construction, positioning and pointAt function usage.

Starting where we left of two weeks ago (source code from the guide's previous part: Tutorial3D.zip) is a good idea since we already have some basic camera stuff laid down. Although creating a separate class for the camera would probably be a good idea, the already existing matrix by it self is sufficient for now. In any case, the matrix is ready, however results of its transformation are somewhat… unpredictable, or at least not something we could expect (i.e. x+=-5 will actually result in movement to the right instead of left). This is related to a small omission on Adobe's part in the rendering function, which can cause some sleepless nights. What I am exactly talking about? Lets have a look how finalTransform matrix is created in render function:

finalTransform.identity();   
finalTransform.append(box.getMatrix3D());   
finalTransform.append(world);   
finalTransform.append(view);   
finalTransform.append(projection);
It doesn't seem like there is anything out of ordinary here, but if we stop for a moment and take a close look - lets say we want to move whole world to the left, and camera to the right, and for that we set world to x = -10 and view to x = 5. In perfect world there would 15 units of space between world and camera now, but of course it won't be the case in our application and everything because how finalTransform is being made. Lets take another look, world is moved by -10 and view by +5:
finalTransform.append(-10);   
finalTransform.append(5);
And what the result will be? Of course every object will be moved to the left (-10), then to the right (+5), in the end ending up on x = -5. True, it's very basic stuff, but it is very important to understand that it is not the camera that we are moving but the whole world around it. And this is that little detail thingy we were missing: we aren't moving the camera to the left, but whole to the right! Of course it could be done by just saying "simply move the camera in opposite direction", but … is bad idea - rotation and positioning could be done that way, but poinatAt function will be pretty much useless. Fortunately the solution is very simple, we just have to invert the view matrix:
var camera:Matrix3D = view.clone();  
camera.invert();
Yup, that is it. Whole render function will look like this:
private function render(event:Event):void {  
renderContext.clear(.3, .3, .3);  
var camera:Matrix3D = view.clone();  
camera.invert();  
for each(var box:Box3D in vBox) {  
finalTransform.identity();  
finalTransform.append(box.getMatrix3D());  
finalTransform.append(world);  
finalTransform.append(camera);  
finalTransform.append(projection);  
renderContext.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, finalTransform, true);  
box.render(renderContext);  
}  
renderContext.present();  
}
Those two lines of code are enough to make our camera work as intended, view translation to the left will in face move it to the left and what is most important pointAt will actually work, which I will explain shortly. Right now it is best to test out the camera movement and hopefully get something like this:
(Movement on the arrow keys)
Just in case you can always use the code available at the very and of this post.
Well, now that everything is properly set up, it is time to use pointAt function. And to think that without the knowledge about view matrix inversion prior to finalTransform construction, pointAt would never work as intended! This however doesn't solve all of the problems, there is still a question of parameters used by pointAt, because obviously default ones won't work. Those parameters are:
1. Target's position - matrix will be turned to face that point.
2. Facing direction - in other words "front" direction without any transformations; for camera it always will be Vector3D(0, 0, -1).
3. Up direction - which is the "rising" direction; by default Vector3D(0, -1, 0).
That should be enough. Properly working pointAt should look like this:
Unfortunately, translation won't be affect by the pointAt transformation - lets leave that for another day.
Source code: Tutorial3D-2.zip

Basics of Stage3D part I: displaying multiple objects [advanced]

Two weeks ago I've wrote about support in Flash Professional for Flash Player 11 while mentioning about using the example of 3D rendering from the documentation ( http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display3D/Context3D.html#includeExamplesSummary). However using a pre-made example is one thing and understanding it is whole different matter - that is why this time around I will write about Stage3D (as Adobe like to call there 3D acceleration in Flash).
Just in case the whole code from that example (along with additional libraries needed to run it) is available here: Context3DExample.zip

In the first part of this article I will write a bit about creating and displaying multiple objects while still allowing for separate transformations on each of them. To make this simpler I suggest making a class for 3D cubes, using the already existing code (from the example in the documentation) responsible for creating geometry: IndexBuffer and VertexBuffer. Such class might look like this:

private var vbBuffer:VertexBuffer3D;
private var ibIndex:IndexBuffer3D;
private var m3D:Matrix3D;
private var nCount:int;

public function Box3D(context:Context3D) {
			
            var triangles:Vector.<uint> = Vector.<uint>([...]);
	ibIndex = context.createIndexBuffer(triangles.length);
	ibIndex.uploadFromVector(triangles, 0, triangles.length);
			
	const dataPerVertex:int = 6;
	var vertexData:Vector.<Number> = Vector.<Number>([...]);
	vbBuffer = context.createVertexBuffer(vertexData.length / dataPerVertex, dataPerVertex);
	vbBuffer.uploadFromVector(vertexData, 0, vertexData.length / dataPerVertex);
					
	m3D = new Matrix3D();
	nCount = 12;	
}
				
public function render(context:Context3D):void {
	context.setVertexBufferAt( 0, vbBuffer, 0, Context3DVertexBufferFormat.FLOAT_3 );
	context.setVertexBufferAt( 1, vbBuffer, 3, Context3DVertexBufferFormat.FLOAT_3 );
	context.drawTriangles(ibIndex, 0, nCount);
}
				
public function getMatrix3D():Matrix3D {return m3D;}
Nothing especially complicated here - just remember that m3D matrix will hold the transformation (position, scale) so it is best to build the cube around 0,0,0 coordinates and then later move it with appendTranslation function. Also, one more thing worth pointing out is that setVertexBufferAt is used to set which VertexBuffer will be used to draw triangles (drawTriangles function) and it is called twice, because first it points out the vertexes and next the colours.
So, creating a class for cubes is pretty simple, the problems start when we decide to display them. Assuming all those boxes are stored in vBox vector, the render function used in Context3Dexample needs to be changed to this:
private function render(event:Event):void {
	renderContext.clear(.3, .3, .3);
			
	for each(var box:Box3D in vBox) {
		finalTransform.identity();
		finalTransform.append(box.getMatrix3D());
		finalTransform.append(world);
		finalTransform.append(view);
		finalTransform.append(projection);
	renderContext.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, finalTransform, true);
				
		box.render(renderContext);
	}
			
	renderContext.present();
}
Here it gets a bit more interesting thanks to the two most important things: setProgramConstantsFromMatrix function and finalTransform matrix construction. With setProgramConstantsFromMatrix function we set the matrix (transformations) for the rendered object and it cannot be skipped (or at least it won't make any sense to do this, since you won't be able to see anything on the screen), while finalTransform will be used to create that matrix.
This stuff will probably be pretty confusing to people not familiar with 3D graphics, but the basic idea to remember is that every object (cubs in our case) is actually never modified during the runtime. In other words we create our cube, define its triangles and set some colours, but by it self the cube does not have specific position in the system - we use matrices for that. But the thing is matrices also don't do anything special by themselves, until we call the setProgramConstantsFromMatrix function to combine them. Note however this works somewhat like a filter - "Program" (external code used for rendering process) takes the geometry and passes it through the matrix, displaying results to the screen while not modifying any variables.
Now as for the finalTransform - we start each animation frame by resetting this matrix (identity function) to make sure it contains absolutely no transformations. This is very important for append operations, because existing transformations affect the results, so for example a translation by 10 units to the left followed by a 90 degrees turn will place an object in different spot than by starting with 90 degrees turn and then following it with a translation to the left by 10 units. Just like in the real world the direction we will take on "move to the left" command will be different depending on the side we are already facing. In any case it is best to experiment with this, while remembering that order of matrices addition is extremely important and that is why finalTransform is created by appending other matrices in this particular order: world, view (camera) and projection (defines how we see the world).

As usual the whole code is packed and ready to download from here: Tutorial3D.zip

Publishing for Flash Player 11 in Flash Professional CS5.5 [basic]

Recently Adobe released a new version of Flash Player, this time with a number 11 that features 3D acceleration (which I will write something about soon hopefully), support for bigger bitmaps, JSON etc. However those of you who wish to check out those new functions in Flash Professional are up for an unpleasant surprise - Adobe is yet to release an update that actually allows for publishing to the newer format. There is a workaround for this problem, however it is not quite perfect, but on the other hand the only other way is to switch from Flash Professional to a different programming environment (for example: Flashdevelop which is a perfect alternative for people that are seriously thinking about programming in ActionScript).

So anyway, how to add Flash Player 11 support to Flash Professional?

1. Before anything we will need the latest Flash libraries: http://www.adobe.com/support/flashplayer/downloads.html. At the very end of "ADOBE FLASH PLAYER 11" paragraph there is a link leading to a file called: "PlayerGlobal (.swc)" which will be needed in the next step.

2. Now open your Flash Professional installation folder (on XP by default it is: "C:\Program Files\Adobe\Adobe Flash CS5.5"), then move to "Common" -> "Configuration" -> "ActionScript 3.0". In here you already should see directories like "FP9" or "AIR2.5" - we will focus on Flash Player 11 for which we will create "FP11". To this "FP11" folder put previously downloaded "playerglobal11_0.swc" and rename it to: "playerglobal.swc". The final path to the file should look something like this: "C:\Program Files\Adobe\Adobe Flash CS5.5\Common\Configuration\ActionScript 3.0\FP11\playerglobal.swc".

3. Those libraries give us access to the latest functions available in ActionScript but we still need to tell Flash Professional to actually use them. To achieve this head onto the "Players" directory (which is located within "Configuration", just few steps above our previous location) and duplicate a "FlashPlayer" file (in case there are more files like this, duplicate the one with the highest number in the name) renaming it to "FlashPlayer11" in the mean time. Proceed to open it with a text editor of your choice (Notepad will do just fine) and at the very top find lines that look like this:

  <player id="FlashPlayer10" version="10" asversion="3">
   <name>Flash Player 10 & 10.1</name>
Ten replace them with this:
  <player id="FlashPlayer11" version="13" asversion="3">
   <name>Flash Player 11</name>
("version="13"" is not a spelling error)
Further more find a line that starts with: "playerglobal.swc" which we need to modify so it points to our "FP11" directory (created in the previous step).
Or you could just download the whole profile file from here: FlashPlayer11.zip

4. Theoretically that is all you need to export SWF files in their latest version. Unfortunately it is "theoretically", because in reality Flash Professional won't be able to open them, as it is using an older version of the player. Right now I have both good and bad news: that old player can be replaced... but only for the "debugger" (the usual move testing done by CTRL+ENTER won't work). That is why this is not a perfect workaround, but perhaps still better than nothing.
To replace the old Flash Player you will first need to download a latest debug projector: http://www.adobe.com/support/flashplayer/downloads.html ("Flash Player 11.0 Projector content debugger"). Then open the "Players" folder located in the Flash Profesional installation directory (for XP it will be: "C:\Program Files\Adobe\Adobe Flash CS5.5\Players"). There you will find "Debug" and within it "FlashPlayerDebugger.exe" which is a file you will need to replace with that projector gotten off Adobe site (while at the same time renaming it to " FlashPlayerDebugger.exe" most likely).

5. Now it is only a matter of starting Flash Professional and checking whether debugging actually works (CTRL+SHIFT+ENTER by default) while using the example from the documentation: flash.display3D.Context3D - ActionScript 3.0 Reference (at the very bottom; also read the comments under the example).

3D engine for beginners III [advanced]

In previous parts of this guide dedicated to creating a very bare-bone 3D engine I've mentioned how to display the illusion of perspective and how to control camera movements. This time we will handle rotation. It will be the final chapter of this guide since any further immersion in the topic will require knowledge of more advanced issues, which are better to handle with a "proper" engine (like for example Alternativa3D or Away3D). Not to mention the newest Flash version with number 11 was extended with 3D acceleration, which basically means ActionScript can now be used to create a proper 3D game in likes of Crysis or Gears of War (especially since Adobe presented Unreal Engine 3 working in Flash).
But that is a different story, for now let's focus on that rotation.

1. However before we do anything create two new constants and one variable:

const SPEED:Number = 20;
const ROTATION:Number = Math.PI/16;
var a:Number = 0;
SPEED will be the speed of camera movement, while ROTATION will be the speed of rotation. The a variable will be used to store current rotation angle.

2. Do you remember which part of the code was responsible for transformation from 3D into 2D? We will modify it to include turning of the camera:

var nx:Number;
var nz:Number;
var rx:Number;
var rz:Number;
var bx2:Array = new Array(bx.length);
var by2:Array = new Array(by.length);
var i:Number = 0;
while(i<bz.length) {
	nx = cx-bx[i];
	nz = cz-bz[i];
	rx = cx+( nx*Math.cos(-a) )-( nz*Math.sin(-a) );
	rz = cz+( nx*Math.sin(-a) )+( nz*Math.cos(-a) );
	bx2[i] = vw+( ((cx-rx) / (cz-rz) )*vw);
	by2[i] = vh+( ((cy-by[i]) / (cz-rz) )*vh);
	++i;
}
Not much of a change, I've added additional variables for better clarity and the rotation formula (along the Y axis, which is exactly the same as in any other FPS game). You will probably find nothing shocking here if math is no stranger to you. Long story short for each point we calculate its translation (in case of x: nx = cx-bx[i];), which is rotated (( nx*Math.cos(-a) )-( nz*Math.sin(-a) );) and put back into position ( rx = cx+...). Newly created point is then transformed from 3D into 2D using the method we are already familiar with.

3. Now the only thing left to do is to modify the camera movement to include an option for turning around. We will accomplish this by changing how key presses are translated into actions by the switch(key) command. It is also a good opportunity to optimise the code - replace it with this:

switch(key&0x0000ff) {
case 0x00000f:
		cz += Math.cos(-a)*SPEED;
		cx += Math.sin(-a)*SPEED;
	break;
	case 0x0000f0:
		cz -= Math.cos(-a)*SPEED;
		cx -= Math.sin(-a)*SPEED;
		break;
}
switch(key&0x00ff00) {
	case 0x000f00:
	a += ROTATION;
		break;
	case 0x00f000:
		a -= ROTATION;
		break;
}
In the previous version switch was used to check every possible combination within the key variable, while now switch extracts only a part of key - first one gets up and down keys (0x000f0f&0x0000ff will result in 0x00000f which means the information about the left key, 0x000f00, is omitted), while the second one gets left and right.
Okay, so now we handle the key presses better, but what is actually happening here? Let's start from the end: left and right keys are used to turn (change the angle), while up and down are used for forward and backward movement. Of course since now we have to deal with rotation, the definition of "forward" constantly changes and that is why we need to use cos and sin functions which in this case calculate the translation vector based on the angle.

4. Time to test this out. Final result should look more or less like this:
(Movement with arrow keys)


And the whole class is available here: box3d_rot.zip

From AS2 to AS3: duplicateMovieClip() in ActionScript 3 [advanced]

Programmers that decide to switch to AS3 from AS2 will find sooner or later that the latest ActionScript iteration lacks duplicateMovieClip() function equivalent. It might seem odd, since it is hard to imagine Adobe having problems with implementation of such function. My guess is they are trying to kill wrong AS habits. In any case, sometimes you just have to duplicate a MovieClip and that is why I compiled a list of most common solutions:

1. Custom class.
I think around 90% of people looking for the duplicateMovieClip() alternative should find this solution sufficient. In brief: it is about creating a MovieClip's sub-class and then linking it graphics we want to duplicate. So for example, if we were to create an application with falling stars in the background we of course would start by creating a single MovieClip star and then copying it multiple times. To do this open the properties of that MovieClip star and in advanced settings check "Export for ActionScript".
Export for ActionScript
From now on "Star" class contains the star graphics and can be duplicated by writing:

var mc:MovieClip = new Star();
addChild(mc);
That is it.

2. Using the loadBytes() function within the Loader class.
Well sure, #1 method is pretty nice but what if we want to make copy of externally loaded file? In this case lets start by looking how to load the graphics from outside:

import flash.display.Loader;
import flash.events.Event;
import flash.net.URLRequest;

lLoad = new Loader();
lLoad.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded);
lLoad.load(new URLRequest("your_file.swf"));

function onLoaded(e:Event):void {
	addChild(lLoad.content);
}
Okay, so at first glance Loader doesn’t seem to have that many functions we could use after loading an external SWF file - we could pretty much either unload it or load different file. The second options is out of the question (except if user has local caching enabled Flash will actually load the content from there rather than connecting to the server again) unless we use loadBytes(). The trick here is that loadBytes() can load any file-type supported by load() but does the reading from a ByteArray. The questions now is: where do we get that ByteArray of a loaded MovieClip from? The answer is actually very simple:
function onLoaded(e:Event):void {
	addChild(lLoad.content);
	lLoad.loadBytes(lLoad.content.loaderInfo.bytes);
}
The lLoad.content.loaderInfo.bytes property holds the loaded animation as ByteArray, so it is only a matter of putting it into the loadBytes() and then again catching the onLoaded event resulting in another MovieClip copy without actually establishing any outside connections.
However there is one problem, onLoaded event won't be called instantly... which means we will get our duplicated MovieClip only after few or more milliseconds (depends on FPS value).

3. Using the constructor property for objects loaded with Loader.
Alternative way to duplicate externally loaded SWF is by using the constructor property available for every object created in Flash. Lets just go ahead and see how it works:

function onLoaded(e:Event):void {
	var d:DisplayObject = new lLoad.content["constructor"]();
	addChild(d);
}
(Because constructor property is dynamic this is the only way to access it. Also, don't forget the keyword new!)
Unfortunately it is not a perfect solution. The code will work only when the loaded movie has a custom "Document Class" (it can be anything as long as "Document Class" is not empty), which basically means you have to be the author of the target file.

To save some work in future I've implemented all those solution into a single class - should have no problem with duplication of any MovieClips (and not only): foras_clone.zip
It is used in the following way:

import foras.utils.ForCloner;
import flash.display.DisplayObject;
if(stage==null) return;
var fas_Clone:ForCloner = new ForCloner();
var d:DisplayObject = fas_Clone.cloneMovie(my_mc,onClone);
if(d!=null) {
	d.x = stage.stageWidth*Math.random();
	d.y = stage.stageHeight*Math.random();
	addChild(d);
}

function onClone(d:DisplayObject):void {
	d.x = stage.stageWidth*Math.random();
	d.y = stage.stageHeight*Math.random();
	addChild(d);
}
Because ForCloner class uses the loadBytes() method (mentioned as second solution on the list) cloneMovie() requires a callback function to take over the duplicated MovieClip. Of course it is entirely possible it won't be need and cloneMovie will instantly return a copy. However in most cases it will result in the null value, which is where the callback function is used (onClone in the example above) - it will be given the copy of target MovieClip.
One last thing, if(stage==null) return; line stops the code for executing twice - if everything else fails whole application will be duplicated along with its source code (but at the end only target MovieClip will remain, everything else is deleted).

3D engine for beginners II [advanced]

In the previous part of this guide I've described how to create a basic 3D engine capable of creating a three-dimensional cube, however only in a static image which admittedly wasn't very impressive. That is why this time around we will expend it by adding camera movement.
Lets start by creating two keyboard events within the constructor of our box3d class:
stage.addEventListener(KeyboardEvent.KEY_DOWN,eventKeyDown);
stage.addEventListener(KeyboardEvent.KEY_UP,eventKeyUp);
(Don't forget to import flash.events.KeyboardEvent!)
Those listener were attached to the stage because any other object would require changes to the "focus" value which we don't need nor want to as stage is completely sufficient. Anyway, we need two functions to handle those events:
private function eventKeyDown(e:KeyboardEvent):void {

}
private function eventKeyUp(e:KeyboardEvent):void {

}
Before we continue I would suggest checking if Flash correctly handles key presses with trace(e.keyCode); put into one of the listeners.
In the next step we will work on the actual key presses capture and translation into camera movement, which even though can be done this way:
if(e.keyCode == Keyboard.LEFT) cx -= 20;
else if(e.keyCode == Keyboard.RIGHT) cx += 20;
We won't bother with it as it results in a jerky and limiting animation. Instead we will implement a bit more advanced solution based on bitwise operations - but before that, we need a new variable in our class: var key:Number = 0; which we will use in the following way:
private function eventKeyDown(e:KeyboardEvent):void {
	switch(e.keyCode) {
		case Keyboard.UP:
			key = key | 0x00000f;
			break;
		case Keyboard.DOWN:
			key = key | 0x0000f0;
			break;
		case Keyboard.LEFT:
			key = key | 0x000f00;
			break;
		case Keyboard.RIGHT:
			key = key | 0x00f000;
			break;
	}
}
(Don't forget to import flash.ui.Keyboard!)
OK, I admit, this might look a bit confusing at first (especially for people that are not familiar with bitwise operations or hexadecimal numbers), but in few moments everything will become clear. This code sets key variable to certain values depending on the pressed keys, so for example holding "up" and "left" keys will result with "0x000f0f" value being set to key. It is the outcome of bitwise operations done on hexadecimal numbers - by taking "0x000f00" and "0x00000f" and applying | (OR) to them we get "0x000f0f". That line symbol | represents a bitwise "or" and in some situations works a bit like addition - 100|1 will return 101 (more information can be found in ActionScript's documentation). But anyway, we don't really care about that, it is easier to think of key as a kind of light-board where 0 = light is off (a key is not pressed) and f = light is on (a key is pressed). 0x00ffff = all keys pressed, 0x00f00f0 = only up and right, 0x000000 = no keys are pressed etc.
However eventKeyDown only servers to switch the light on. For the full picture we need the opposite function:
private function eventKeyUp(e:KeyboardEvent):void {
	switch(e.keyCode) {
		case Keyboard.UP:
			key = key ^ 0x00000f;
			break;
		case Keyboard.DOWN:
			key = key ^ 0x0000f0;
			break;
		case Keyboard.LEFT:
			key = key ^ 0x000f00;
			break;
		case Keyboard.RIGHT:
			key = key ^ 0x00f000;
			break;
	}
}
In this case the bitwise ^ (XOR) acts a little like subtraction, where "0x000f0f ^ 0x00000f" will result in "0x000f00".
Well, I think the worst is behind us and now we only need to convert key value into the proper camera movement. To achieve this lets had back into the render function (which we created in the previous part of this guide) and before the graphics.clear(); line add the following code:
switch(key) {
	case 0x00000f: // ^
		cz += 20;
	break;
	case 0x0000f0: // v
		cz -= 20;
		break;
	case 0x000f00: // <
		cx -= 20;
		break;
	case 0x00f000: // >
		cx += 20;
		break;
}
Almost over. Compile the application and make sure everything is working as intended. If you had tried operating the camera straight from the eventKeyDown or eventKeyUp functions you will surely notice an improvement in animation (if not I suggest going back and comparing it to the current solution).
In any case, there is still one more little thing - moving diagonally. Using two keys at once will set key to a number that the switch(key) does not handle, so to finish things off we need to add four more clauses:
	case 0x000f0f:
		cz += 20;
		cx -= 20;
		break;
	case 0x00f00f:
		cz += 20;
		cx += 20;
		break;
	case 0x000ff0:
		cz -= 20;
		cx -= 20;
		break;
	case 0x00f0f0:
		cz -= 20;
		cx += 20;
		break;
That is it. Just in case you can download the whole class from here: box3d_2.zip
And the application itself is presented here: box3d.swf

Putting objects of your own class on the Stage within Flash IDE [basic]

While programming interfaces (or similar stuff) in Flash I started asking myself "wouldn't it be cool if Flash had allowed custom objects of my own class on the Stage"? While the truth is it's entirely possibility even since AS2! But the problem is that you won't hear about it anywhere and Flash doesn't really tell if you the object you have put on the Stage is already that of your own class rather than the standard MovieClip.
To see what this feature is useful for I suggest a following test my Dear reader:

1. Download one of those classes: AS2Test.as (ActionScript2 version) or AS3Test.as (ActionScript3 version).

2. In the new Flash project (AS2 or AS3 depending on the downloaded class) create a MovieClip with at least three different animation frames.

3. If you haven't done so already put the downloaded class into your project's folder and then open the MovieClip's (one created in the previous step) properties.

4. Move to the advanced settings and check the "Export for ActionScript", followed by typing in the downloaded class' name ("AS3Test" for ActionScript3 example in the image below).

(For AS2 "Base Class" won't be available while AS3 will have this field empty).

5. Now simply drag and drop your MovieClip from the Library onto the Stage and then compile the animation (CTRL+Enter by default). If everything went smoothing the MovieClip in the animation should react to the mouses cursor movement and clicks.

This all might seem like a gimmick, but in practice this could save you a lot of time, especially in bigger project where lot of objects are being reused multiple times.


<<<Newer postsOlder posts>>>