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

Preloaders in Flash [basic]

"Preloading" is simple idea that dates back to the beginnings of the Internet - perhaps even further than that. It is a process of moving all of the applications data or multimedia into a computer's memory, so it can be accessed smoothly without breaks for additional reading. Same goes for Flash, with preloading we will be certain our animations and whatnot won't turn into a slide-show.
It sound simple enough, but implementation of a preloader into Flash can sometimes be quite tricky. Generally speaking, it all comes down to 3 solutions depending on what we need:

1. For animations.
Movies done in Flash that use almost no ActionScript are the easiest target to include a preloader (since there will be nothing to interfere with it), just copy and paste a ready example.
One of the simplest requires a single MovieClip in the very first frame of the main timeline with instance name set to "preloader" (in properties tab) along with this code pasted in to the same frame:

import flash.events.Event;
import flash.events.ProgressEvent;

stop();
loaderInfo.addEventListener(ProgressEvent.PROGRESS,onProgress);
loaderInfo.addEventListener(Event.COMPLETE,onLoaded);

function onProgress(e:ProgressEvent):void {
	var percent:Number = loaderInfo.bytesLoaded/loaderInfo.bytesTotal;
	preloader.gotoAndStop( int(percent*preloader.totalFrames)+1);
}
function onLoaded(e:Event):void {
	loaderInfo.removeEventListener(ProgressEvent.PROGRESS,onProgress);
	loaderInfo.removeEventListener(Event.COMPLETE,onLoaded);
	//moves to a designated frame in the animation after the loading process
	gotoAndPlay(2);
}
The "preloader" MovieClip will have its animation stop on frame number that is equal to percent amount of content loaded, so if the "preloader" has total of 10 frames and the move itself is loaded to, for example 20%, the frame displayed will be 2 (10*20% = 2).
Ready to use example: preloaderSimple.zip

2. For applications created in Flash Professional.
Here it gets a bit tougher. When creating project that heavily use ActionScript people don't usually think about preloaders first and foremost, which actually isn't a bad thing but might bring some complications, especially when exporting to the first frame.
Speaking of exporting to the first frame, lets take a moment to look at this function. When exporting graphics to ActionScript we have an option to "export in 1 frame", which does exactly what it says and puts all of the graphics in the first frame of main timeline - the trouble is, this leaves us with no room to later insert a preloader. In Flash Professional this can be dealt in two ways:
- by changing a designated frame in ActionScript's properties

- or by simply putting the graphics manually on the stage in proper frame. Lets, for example, take a class that makes use of a exported graphic on frame 3 in the main timeline, allowing us to put them on frame 2 (even outside of the screen if needed) while having the "export to 1 frame" opetion turned off.

3. For applications created in FlashDevelop.
… or any other development environment that loads SWC files. I'm referring here to external ActionScript libraries that may or may not come packed with graphics or other multimedia. Those multimedia elements are loaded as soon as there is something referencing the classes they are linked with, which basically means any kind of import from SWC will instantly be blocked till the graphics gets loaded into the memory. On the other hands omitting those imports simply means no SWC class will be compiled into the application. This begs a question: how can something be included along the application without actually importing it? There is only one answer and it was found by Keith Peters at: www.bit-101.com. Long story short, this brilliant trick can be summed down to a single line: [Frame(factoryClass="Preloader")] ("Preloader" is the name of the class that will server as a preloader), which has to be put right before documents class definition (but after all the imports) - called, for example: "Main". Main will get loaded but not initialized because this role will be taken over by the Preloader.
Unfortunately there is still a matter of instancing Main after the loading process, since we still can use imports - we import Main, Main imports something else, which in turn imports something else and sooner or later there will come along a class that imports straight from the SWC file, blocking our application the graphics gets loaded. Fear not however as flash.utils.getDefinitionByName comes to our aid being used in the following way:

var mainClass:Class = getDefinitionByName("Main") as Class;
if(mainClass) {
	addChild(new mainClass() as DisplayObject); 
}
WARNING! The getDefinitionByName() function may from time to time return the NULL value, meaning ENTER_FRAME Event might be good idea to allow for further retries in later times.
As per usual, here is an example code: preloader.zip
And in action it can be viewed here: Preloader.html

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

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.

3D engine for beginners I [basic]

If anyone ever wanted to create their own 3D engine in Flash (and not only) not sure of what to expect, surely they met them self with a lot of mathematics and advanced programming routines during the search for information. It might be a little disheartening, but the truth is you don't need all that fancy stuff to create something basic, like for example: an application that displays a 3D cube.
That is why this post will be dedicated to people who are completely new to the topic of creating a 3D engine (which can display that 3D cube).

All of it will fit into one class - for best effect it should be the document's class. In case you are wondering the "Document Class" can be created on properties tab.

(Enter the class name and press the pencil icon).
After creating the new class we should prepare all the variables that we will need in our little engine. Lets start with the camera position:

var cx:Number = 0;
var cy:Number = 0;
var cz:Number = 0;
Nothing fancy here - camera position will determinate what we see on the screen. I think it is best if I take this moment to explain what effects will the movement have (since we don't have to stick to mathematics' rules and switch stuff like up and down around):
cx is the left(-) or the right(+) movement.
cy is the up(-) or down(+) movement.
cz is the backward/"away from the screen"(-) or forward/"to the screen"(+) movement.
OK, now we need a point where the perspective will focus too:
var vx:Number = stage.stageWidth/2;
var vy:Number = stage.stageHeight/2;
The vanishing point is usually in the middle of the screen and the easiest way to get is to divide the screen in half. Of course nothing stops us from defining a different point (but this will required some modifications to the transformation equation I will talk about later). By the way, the 0,0 point is located on the upper left corner of the screen and everything to the right or down from it consists of positive numbers only.
The last set of variables defines the 3D cube:
var bx:Array = [-50, 50, 50, -50, -50, 50, 50, -50];
var by:Array = [-50, -50, 50, 50, -50, -50, 50, 50];
var bz:Array = [200, 200, 200, 200, 300, 300, 300, 300];
Those three arrays hold points that describe our three-dimensional box. For example if we take bx[0],by[0],by[0] we get the upper left corner of the front facing wall.
Now that we have all the needed parameters we can proceed to create our 3D rendering function. To achieve the smoothest animation it's best to connect it with the ENTER_FRAME event - that is why we will write the following line within the constructor:
addEventListener(Event.ENTER_FRAME,render);
Don't forget to import flash.events.Event! As you can see I named my function "render" and for now it looks like this:
private function render(e:Event):void {
 graphics.clear();
}
Just a standard function definition. We will need the graphics.clear(); line because the process of rendering always looks the same - when entering a new animation frame we remove the old graphics and insert new ones (inserting will be explain in a moment). Anyway, it is time to move on onto the most important part of the application, which is the transformation from 3D into the 2D (because currently no monitor screen can handle anything else than 2D image):
var bx2:Array = new Array(bx.length);
var by2:Array = new Array(by.length);
var i:Number = 0;
while (i<bx.length) {
	bx2[i] = vx+(((cx-bx[i])/(cz-bz[i]))*vx);
	by2[i] = vy+(((cy-by[i])/(cz-bz[i]))*vy);
	++i;
}
So first things first:
var bx2:Array = new Array(bx.length);
var by2:Array = new Array(by.length);
Those arrays will hold all 2D points after the transformation.
Then, in the loop, we have:
bx2[i] = vx+(((cx-bx[i])/(cz-bz[i]))*vx);
by2[i] = vy+(((cy-by[i])/(cz-bz[i]))*vy);
Which is the code responsible for that transformation. Quite frankly you don't need to understand it to use it efficiently, so feel free to skip the following explanation and perhaps return to it later:
cx-bx[i] - we are subtracting a point's coordinate from the camera's position to retrieve the translation vector. It's a standard method when dealing with transformations, because we don't care where the point is, but rather how far it is from the camera - relative information like that is easier to carry between spaces.
cz-bz[i] - here we calculate the distance from the camera. We need this value to create the illusion of perspective.
(cx-bx[i])/(cz-bz[i]) - and here we create that illusion of perspective, so objects will seem to be getting smaller when moving further away.
*vx - after we are done with the perspective it is time to include the viewing angle. Only not in the scope we would expect it to be as bigger number stretch the image (make the angle smaller). Clearly it has nothing to do with the vanishing point's vx that we defined but it just so happens that the best value here is also the half of the screen.
vx+ - and finally our vanishing point.

Now that we have all our points in 2D, it is time to display them:

//drawing:
graphics.lineStyle(1, 0xffffff, 100);
//front face:
graphics.moveTo(bx2[0], by2[0]);
graphics.lineTo(bx2[1], by2[1]);
graphics.lineTo(bx2[2], by2[2]);
graphics.lineTo(bx2[3], by2[3]);
graphics.lineTo(bx2[0], by2[0]);
//back face:
graphics.moveTo(bx2[4], by2[4]);
graphics.lineTo(bx2[5], by2[5]);
graphics.lineTo(bx2[6], by2[6]);
graphics.lineTo(bx2[7], by2[7]);
graphics.lineTo(bx2[4], by2[4]);
//connecting lines:
graphics.moveTo(bx2[0], by2[0]);
graphics.lineTo(bx2[4], by2[4]);
graphics.moveTo(bx2[1], by2[1]);
graphics.lineTo(bx2[5], by2[5]);
graphics.moveTo(bx2[2], by2[2]);
graphics.lineTo(bx2[6], by2[6]);
graphics.moveTo(bx2[3], by2[3]);
graphics.lineTo(bx2[7], by2[7]);
The graphics.lineStyle(1, 0xffffff, 100); part describes the style of the drawing line. First value is the width (in pixels), second is the color, and the last one is transparency.
Next we have the drawing itself, starting from the front face:

Then we add the back face:

And connect them at the end:

(Of course in the application this will be done instantly).
If everything went smoothing an image of 3D cube should be visible on the screen (just like in the last picture).
In the next step we should implement some kind of camera movement but this will be explained later posts.

Whole source code is available here: box3d.zip

From AS2 to AS3: _global equivalent in AS3 [basic]

I once was asked is there a way to access variables that were set on _root or _global. The problem comes from how strict the ActionScript3 is - in AS2 you would just write _global.myVar = 5 and then access it from anywhere, but AS3 just doesn't tolerate dynamic variables (and also there is no _global keyword).
There are two ways to work around it:

1. Use syntax meant for dynamic variables.

root["myVar"] = 5;
It is almost the same thing as in AS2, but since you are using dynamic variables you might find yourself with an extremely slow application (when used excessively). If that is the case you should consider the second option.

2. Use static keyword.
This is probably the most proper way to do it, but requires some additional work. Before you do anything create a "Document Class", which you will find in the properties tab.

Type in any name you want for you class (e.g. "MyClass"), confirm it with enter key (at this point a warning should pop-up saying the class doesn't exist - ignore it) and then click the pencil icon on the side.
If done correctly, new class file should be created in a separate window looking something like this:

package  {
	import flash.display.MovieClip;
	
	public class MyClass extends MovieClip {
		
		public function MyClass() {
			// constructor code
		}
	}
	
}
Now just before the public function MyClass() line, type in:
public static var myVar:Number = 5;
That is pretty much it. From anywhere in your project you can now access this variable through class identifier, for example:
import MyClass;
trace(MyClass.myVar);
Also, since you document class is used as "root" object, you can now access it through root field of each MovieClip. It needs to be casted to your class beforehand though:
import MyClass;
trace((root as MyClass).myVar);


<<<Newer posts