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

Interfaces in Flash [basic]

In programming, by ‘Interface’ we understand an abstract definition of methods that by themselves don’t do anything, except for forcing a certain syntax in a class that implements them. In other words we define a function and its arguments in one place and then implement its mechanics in another (target class). Of course by no means its the best way to create a function in Flash, but interfaces have a special trait that makes them irreplaceable in certain scenarios. This trait is ability to cast an object to the interface they implement, which in turn allows us to communicate with it, without actually know what the object is.
I think it is best to demonstrate it on a example, starting from the very beginning: let’s say we want to create a game that displays some information through pop-ups in such way, that each of them contains an “OK” button:
public class MyPopup extends MovieClip {
	private var myButton:OKButton;
	public function MyPopup() {
		myButton = new OKButton(this);
		addChild(myButton);
	}

	public function close():void {
		this.visible = false;
	}
}
public class OKButton extends MovieClip {
	private var myPopup:MyPopup;
	public function OKButton(popup:MyPopup) {
		myPopup = popup;
		this.addEventListener(MouseEvent.CLICK,onMouse);
	}
	private function onMouse(e:MouseEvent):void {
		myPopup.close();
	}
}
At first everything might like fine, but as soon as we start adding more pop-ups the limitation of the above code become apparent - what if we want to reuse the same button for MyPopup2 ? Is adding another argument ( OKButton(popup:MyPopup, popup2:MyPopup2) {} ) enough? Should we repeat this for each new pop-up we want to add? One solution for sure is to create a base class for every pop-up, so we cast it down to use shared methods. However such root classes might bring some troubles in Flash, that I won’t be discussing here. At this point it is probably quite obvious what I am trying to say - the best solution is to use Interfaces. So, let’s create a new AS file:
public interface IPopup {
	function close():void
}
And then modify existing classes:
public class MyPopup extends MovieClip implements IPopup{
	private var myButton:OKButton;
	public function MyPopup() {
		myButton = new OKButton(this);
		addChild(myButton);
	}

	public function close():void {
		this.visible = false;
	}
}
public class MyButton extends MovieClip {
	private var myPopup:IPopup;
	public function MyButton(popup:IPopup) {
		myPopup = popup;
		this.addEventListener(MouseEvent.CLICK,onMouse);
	}
	private function onMouse(e:MouseEvent):void {
		myPopup.close();
	}
}
The difference is quite small, but possibilities definitely much broader. From now on MyButton can communicate with every pop-up without actually knowing what class it is, as long as they implement the proper interface.

Cookies in Flash [basic]

Anyone who regularly browses the Internet is surly aware of so called "cookies", or at least heard about them. Cookies are small pieces of information stored on the user's computer, such as passwords or site's settings (look and behavior). Flash isn't an exception here and does support a similar functionality that is called Shared Objects which allows us to store up to 100Kb of data (more requires user's permission).
Each cookie can be created (or restored) with just one simple line of code:
var soData:SharedObject = SharedObject.getLocal("MyCookie","/");
"MyCookie" is the name of the cookie - if there is already one with that name it will be loaded back into the memory.
Now that the Shared Object is created we can write to it whatever we what, all through the "data" field:
soData.data.message = "Hello world!"
soData.data.myVar = 1337;
Similarly, if we want to read from the Shared Object:
trace(soData.data.myVar); //1337
To make things even simpler all that data is being stored on user's computer automatically, but if needed there is also an option to save it manually by calling the flush() function, which also allows to set the upper limit of cookie's size, making it possible to go over the 100Kb limit by prompting the user for more storage.
Example usage:
(Refreshing the page will save the message and then restore it to the upper text field)
Source: Share.zip

Debugging in local enviroment [basic]

In previous post I've described some very basic debugging methods for already released products - while we are on topic of debugging, lets have a look at some popular and easy methods for fixing errors in local environment. Of course everything comes down to what we want to do with our application, but there will be always room for those universal tricks:

1. Execution speed time.
Skipping past the fact you should build your application also considering slower computers, speed measuring is a great way to test algorithms, especially if we know how much time they need beforehand. For more prominent results it's usually a good idea to add a loop:

public static function measureProcessTime(fun:Function, repeat:int = 10):Number {
	var time:Number = getTimer();
	for(var i:int = 0; i < repeat; i++) {
		fun();
	}
	return getTimer() - time;
}
Note that local functions are especially useful here as Flash allows their creation pretty much everywhere, allowing us to test any part of the code by simply enclosing it in the following way:
var someVar:Number = 0;
someVar = 1;
function debug() {
	var otherVar:Number = 10;
	someVar += otherVar;
}
trace(measureProcessTime(debug));
}

2. Loop traversing.
This is another neat neat way to test algorithms. Basically the idea here is to display one single point in a loop, but with ability to move that point around. Example implementation:

private static var DEBUG_COUNT:int = 0;
private static var DEBUG_STEP:int = 0;
public static function nextStep():void {
	DEBUG_STEP++;
}
public static function prevStep():void {
	DEBUG_STEP--;
	if(DEBUG_STEP<0) DEBUG_STEP=0;
}
public static function resetDebug():void {
	DEBUG_COUNT = 0;
}
public static function countDebug():Boolean {
	DEBUG_COUNT++;
	return  DEBUG_COUNT == DEBUG_STEP;
}
Functions nextStep and prevStep are meant to be connect to the arrow keys, allowing us to traverse the loop. The resetDebug function should be called before the loop we want to test. Finally the countDebug function which will return true when our loop reaches the selected step. Although it doesn't seem like much, loop traversing can be incomparable debugging tool. Good example of this is a line drawing algorithm:
(Use the up and down arrow keys to move around the loop)

3. Graphics overlay.
I think no one will disagree it's easier to see data in graphic representation rather than list of variables, which is why every application should always have some kind of way to draw (using Graphics class) information above every other object. This can be easily done by holding the main application in a "container" MovieClip, while having a single Sprite one step above it, which will be empty but accessible from anywhere in the application:
public static debug:Sprite;
public function DocumentClass() {
	var main:MyApplication = new MyApplication();
	addChild(main);

	var debug:Sprite = new Sprite();
	addChild(debug);
}
Now we just need to write DocumentClass.debug.graphics to start drawing over everything else. Personally I like to use it as a way to check hit-boxes of objects on the screen:

Debugging on user side [basic]

Debugging is a popular term used to describe a process of removing errors (or any kind of unwanted behavior) from a source code. Developing in Flash Professional or FlashDevelop we already have an access to pretty good debugging tool, which no doubt helped all of us fix at least few problems. Unfortunately debugger can only used by the developers themselves and they can not always foreseeing every possible scenario users might find themselves in. Which is why it is always a good idea to implement a mechanism for catching any errors from the user side - lets have a look at the most popular ones.

1. Main Loop.
This, what might seem to be a trivial thing, should be a part of every self-respected applications and not only because it makes debugging a much easier process, but also helps avoid memory leaks and makes whole code easier to read. But what exactly is a "main loop"? In Flash it basically comes down to having only ONE "ENTER_FRAME" event in whole application, which means every other function will executed directly (or indirectly) from the main loop. Such approach will make catching errors a trivial task, as it only requires a simple try and catch around loop's code, ensuring we always stay in control. Here is an example of a main loop:

public function render(e:Event):void {
	try {
		processPlayer();
		processEnemy();
		processMap();
	} catch(e:Error) {
		trace("Error!");
	}
}

2. Log.
Even though catching errors is very important, they might useless without information about circumstances that surround them, which is why a log that details all key functions used by the user is second most important element in every application. Writing down user status (Flash version, user's operating system etc.), button they press or windows they opened, or in case of games, what map they are on, what is their progress and events they already completed will help us recreate the scenario in which user encountered the problem.
Log class is always the easiest one to implement:

public class Log {
	private static var log:String = "";
	public function Log() {}
	public static function add(s:String):void {
		log += s+"n";
	}
	public static function toClipboard():void {
		System.setClipboard(log);
	}
}

3. Console.
Most likely there is no PC gamer didn't ever use a console, even if it only was to enable the "god mode". By console I mean a (usually hidden) applications commend line, which allows every user to fire a predefined functions at any given moment. Implementation of a good console requires a good deal of work, but luckily there is already a nice selection of ready solutions on the Internet, like for example: Flash Console. Everyone should try out creating a console for their application - one time is enough to fall in love for them.

Finally, when our application is ready, it is a good idea to replace the trace function in the main loop with something that will help us receive any possible error's information, by for example sending an e-mail.

Happy Easter!

Today I only have some updates regarding the blog:
First of all, the hosting company has been upgrading their servers make this blog almost completely inaccessible throughout the whole passing week, but it should be alright now.
As for why I don't have any updates this time around, it is because I've been working on something special - a mobile version of the blog. In other words lighter and (hopefully) faster version of the whole site dedicated specifically to users browsing on mobile devices. For anyone interested the lighter version is available here: 4as.pl/mobile but all mobile users are automatically redirected there upon entering the blog. Also, just a quick note, it still needs some polish.

Basics of tile-based engine part 3: line of sight [advanced]

So we already have isometric view and path finding topic behind us, now it is time for the third and final part: field of view. Basically it usually comes down to checking whether there is a direct connection between two points (for example a player character and an enemy), without anything blocking the line. More often than not, it is usually quite a complicated issue, but luckily not in tile-based engines -we just need a line drawing algorithm. Why is that? Line drawing algorithms start at one point and move toward another one pixel by pixel, until they form a line. Now if we were to replace the drawing function with one checking the tiles, the result would be an algorithm that step by step checks a line in between two points for some kind of obstacles.
That said, we first need an algorithm - personally I recommend one from Wikipedia: Bresenham Algorithm. Implemented in ActionScript it might look like this:
function isInSight(tiles:Vector.<Vector.<int>>,x1:Number, y1:Number, x2:Number, y2:Number):Boolean {
	var dx:Number;
	var dy:Number;
	if (x1>x2) {
		dy = y1;
		y1 = y2;
		y2 = dy;
		dx = x1;
		x1 = x2;
		x2 = dx;
	}
	dx = x2-x1;
	dy = y2 - y1;
			
	var y:Number;
	var x:Number;
	var m:Number;
	if (Math.abs(dx)>Math.abs(dy)) {
		m = dy/dx;
		y = y1;
		for (x=x1; x<x2; x++) {
			if(tiles[x][y] == 1) return false;
			y = y+m;
		}
	} else {
		m = dx/dy;
		x = x1;
		if (y1<y2) {
			for (y = y1; y < y2; y++) {
				if(tiles[x][y] == 1) return false;
				x = x+m;
			}
		} else {
			for (y = y1; y > y2; y--) {
				if(tiles[x][y] == 1) return false;
				x = x-m;
			}
		}
	}
	
	if(tiles[x2][y2] == 1) return false;
	return true;
}
The isInSight function will return false when on the way from point 1 to point 2 there will be a tile marked as 1 in two-dimensional array tiles.
Easy. And the best part is that most line drawing algorithms are quite fast making this solution viable even in really big maps.

Basics of tile-based engine part 2: path finding [advanced]

In the previous part I've talking a little about isometric view and how to achieve it a simplest way possible. This time around, just as promised, we will have a look at path finding in tile-based engine using one of the easiest methods available (but not the fastest). I am not really sure if the algorithm presented here has any specific name, but without a doubt it is the most direct way out of all possible solutions.
For all of you that are not interested in details I've prepared a class built around the whole algorithm, plus also a FLA file showing how to work with it: PathFind.zip
Running it will look like this:
(Pick a starting and an ending point but clicking any empty field. SPACE to create different map)

The idea behind the algorithm is quite simple and can be divided into two phases:
1. Target search. Starting for on of the chosen points we check, step by step, every tile in the neighborhood in search of the second specified point, while constantly saving current iteration step into the grid. These numbers are needed in the next phase.
Here is a code snippet from the example:

// ...
var vWrite:Vector.<Vector.<int>> = recreateTiles(tiles);
vWrite[startx][starty] = 1;
vWrite[endx][endy] = -1;
var vCheck:Vector.<Point>;
var vRead.<Point> = new Vector.<Point>();
			
var tile:Point;
var nStep:int = 2;
vRead.push( new Point(startx,starty) );
while(vRead.length != 0) {
				
	vCheck = vRead;
	vRead = new Vector.<Point>();
	for each(tile in vCheck) if(lookupTile(tile.x, tile.y, nStep, vRead,vWrite,vTile)) {
		return retracePath(tile.x,tile.y,nStep,vWrite);
	}
	nStep ++;
}
return null;
// ...
The lookupTile function looks for a next tile to be processed. If the end destination is anywhere in the 4 directions from the current tile, the loop ends and a found path is returned. In other cases vWrite is updated to hold new information, while any found tile is written into vRead to be processed in next iteration.
2. Path backtracking. Once we find our destination it is time to backtrack along the numbers saved in vWrite ,one by one to retrieve our path. Lets say the iteration stopped at 20 step - now we have start searching for the tile containing number 19, then 18, 17, and so on. Untill we reach number 1 which is the starting point (0 is used for tiles that were not checked).

Just a small note to finish this off: the algorithm can be speed up by executing it simultaneously on both starting and ending point, which means the path will be found when both of them meet each other half way through. This method was used in the attached example.
Next time we will have a look at the idea of "field of vision" in tile-based engines.

Basics of tile-based engine part 1: isometric view [basic]

In this three-part article I will try to explain some of basic problems one might stumble upon when working with tile-based engines. Since they are quite old one might think that the topic was already exhausted, however many people still have problems with it, often complicating trivial issues.
One of those issues is isometric view (sometimes might be called "diagonal view") which a specific type of 3D transformation without the perspective and was often used in older strategy games. Although the definition mentions 3D transformation it is actually not required at all and can be replaced with something much simpler, which unfortunately not many people try to do, resulting in many articles like this one focusing on basics of 3D - unnecessarily.
Basically you could sum everything to this simple function:
function getTile(nTargetX:Number,nTargetY:Number,nWidth:Number,nHeight:Number):Point {
	var nScale:Number = nWidth/nHeight;
	var nTransY:Number = (nScale*nTargetY-nTargetX)/2;
	var nTransX:Number = nTargetX+nTransY;
	var nTmpY:Number = Math.round( nTransY/(nHeight*nScale) );
	var nTmpX:Number = Math.round( nTransX/nWidth );	
	var nTileX:Number = (nTmpX-nTmpY)*nWidth;
	var nTileY:Number = (nTmpX+nTmpY)*nHeight;
	return new Point(nTileX,nTileY);
}
Which results in this:
(Green circle is the Point returned by the getTile function)
Try it yourself: tile_example.zip

That is pretty much it, now the only thing left to do is explain how getTile works step by step:
1.
var nScale:Number = nWidth/nHeight;
Scale will be used during the transformation to realign the difference between height and width (as the algorithm works only in 1:1 scale).
2.
var nTransY:Number = (nScale*nTargetY-nTargetX)/2;
var nTransX:Number = nTargetX+nTransY;

Here is where a point on the screen gets transformed into a point in the isometric view.
Usually when we are talking about an isometric view, we are thinking about a space that is rotated by 45 degrees in such way that movement to the right is not a simple +X, but rather some value of X plus partly also some Y. The example will probably make more sense:

As we can see the movement of the mouse cursor to the right is transformed into a point that is only partially moved to the right, because partially it is also moved upward. Armed with this knowledge we can try and write a general equation - since movement to the right (+X) gives a bit of upward movement (-Y) we can say that Y gets smaller along with X getting bigger, or in other words: Y = -nTargetX. However we have to remember it is not a straightforward transformation x=>y (otherwise it would result in 90 degrees turn), which is why have to divide the equation by 2 (as 90 degrees divided by 2 gives us 45... in a great simplification). Now that we know Y, getting X is quite trivial as we only need to subtract the Y value from target X (so the distance remains the same as the one before the transformation) and since Y is already negative we need to use the addition Y = nTargetX+nTransY;. By the way, you can switch plus and minus signs between each other to achieve a -45 degrees rotation.
3.
var nTmpY:Number = Math.round( nTransY/(nHeight*nScale) );
var nTmpX:Number = Math.round( nTransX/nWidth );
var nTileX:Number = (nTmpX-nTmpY)*nWidth;
var nTileY:Number = (nTmpX+nTmpY)*nHeight;

Here we are translating given point into a tile, by "shrinking" the whole space using width and height values, then discarding any numbers after the comma and finally bringing everything back to "normal size". Because I love examples here is another one: if tile #0 is 20 pixels width, then every pixel between 0 and 20 will belong to it. So now the question is: how to check which tile owns the seventh pixel? Lets take that 7 and divide it by 20, resulting in 0.35. Now we discard everything after the comma and get our tile with id #0. Lets re-try that for pixel 27; 27/20 = 1.35; drop the comma stuff and we get #1, which is correct because as we already know 27 doesn't belong to #0.

Phew, that is it for today. In two weeks I will write about a very simple path finding algorithm you could implement in a tile-based engine.

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

Communication between AS2 and AS3[basic]

As soon as ActionScript3 saw the light of the day Adobe instantly pointed out that the virtual machine behind it is completely different than the one used in AS2, which in turn means there is no direct way of communicating between those two languages. Right now someone might think that if that is the case, then there is no point in trying, topic closed. But wait a second, no direct connection doesn't equal to no possible connection at all. Let me put it this way: lets take MySQL for example, Flash doesn't come packed with any means to connect to it directly, yet it doesn't stop us anyway, thanks to PHP (or other methods). Which brings us to the heart of the matter: indirect connection. In case of AS3 and AS2 it is even simpler than using PHP, because both of them include a class for communication between local SWF files - LocalConnection is its name.
Main purpose of LocalConnection is to communicate between two Flash applications running on the same computer, however since its implementation did not change at all in AS3, we can also use it to establish a connection between AS2 and AS3.
Creating a LocalConnection is very easy and almost identical for both languages. For ActionScript2 it will be:
var connectionAS2:LocalConnection = new LocalConnection();
connectionAS2.connect("LocalConnectionTestAS2");
And for ActionScript3:
var connectionAS3:LocalConnection = new LocalConnection();
connectionAS3.client = this;
connectionAS3.connect("LocalConnectionTestAS3");
connectionAS3.addEventListener(StatusEvent.STATUS,onStatus);
function onStatus(e:Event):void { }
AS2 version is quite trivial, however AS3 one requires some explanation. First of all, the line that says connectionAS3.client = this; is very important as it points to object that will handle the incoming function calls, without it the application will simply not work. StatusEvent is added to the LocalConnection only to stop Flash from throwing any errors before the connection is established.
Oh and texts put into the connect() functions are different to allow for bidirectional communication.
Okay, now that we have AS2 and AS3 ready to exchange commands, it is time to create function that will send them. Also, to get a better feedback on the whole process we will include TextFields to display the information. For ActionScript3 it will be:
var tf:TextField = new TextField();
tf.text = "No Messages";
addChild(tf);

function messageFromAS2(msg:String,nx:Number,ny:Number):void {
	tf.text = msg+" "+nx+" "+ny;
	tf.x = nx;
	tf.y = ny;
}
While for ActionScript2 it will be:
this.createTextField("textMsg",this.getNextHighestDepth(),0,0,200,25);
var tf:TextField = this.textMsg;
tf.text = "No Messages";

connectionAS2.messageFromAS3 = function(msg:String,nx:Number,ny:Number):Void {
	tf.text = msg+" "+nx+" "+ny;
	tf._x = nx;
	tf._y = ny;
}
One last thing remaining now is to fire up those functions - Mouse Events will do the trick. For ActionScript3:
stage.addEventListener(MouseEvent.MOUSE_MOVE,onMove);
function onMove(e:MouseEvent):void {
	try {
		connectionAS3.send("LocalConnectionTestAS2","messageFromAS3","AS3 MouseEvent",e.stageX,e.stageY);
	} catch(e:Error) {
		return;
	}
}
For ActionScript2:
this.onMouseMove = function():Void {
	try {
		connectionAS2.send("LocalConnectionTestAS3","messageFromAS2","AS2 Mouse Event",_root._xmouse,_root._ymouse);
	} catch(e) {
		return;
	}
}
In both cases try-catch is used to stop Flash from throwing errors before the connection is established.
In action, the whole thing will look like this:
Source code: localcon.zip

By the way, if you ever find yourself in a situation where you need to access an AS2 file that does not support LocalConnections and can't be modified, I suggest creating a separate SWF file in ActionScript2, then loading (loadMovie() function) the target file to read all the necessary information and send them further down the line wherever you like using LocalConnection.


<<<Newer postsOlder posts>>>