Pixel Everywhere

There are only 10 types of people in this world. Those who know binary and those who don't.

LocalConnection Bug In IE — September 29, 2011

LocalConnection Bug In IE

If you’re planning to communicate two Flash movies using the LocalConnection class and constantly removing the other Flash movie by removing its HTML tag container, you need to close the connection first.  Unlike Firefox, IE has a tendency to store the previously opened connections.  Otherwise you’ll have a connection that looks like it’s intermittent or on a certain on and off interval every time you open a new connection.

Have fun!

Using htmlText in Flash AS3 CS Versions —

Using htmlText in Flash AS3 CS Versions

There’s a tricky part in using the htmlText property of a text field when using any latest versions of Flash.  One thing to point out is that if you’re not using an embedded font to render an htmlText property of a text field, its  only available characters will depend on another text field that’s being on the stage that’s not using htmlText.  Try this:

1.  Place two dynamic TextFields in the stage and name one as myTextField

2.  In the Actions Panel, type in myTextField.htmlText = “<b>hello world</b>”;

3.  Go back to the stage and manually enter a text to the TextField that has no instance name.  Try placing just one letter like “o” without the quotes

4.  Preview the movie and see what happens to the myTextField’s value and the style.  Looks weird huh!

So, to correctly use htmlText, do the following:

1.  Embed the needed fonts

2.  Use device fonts

*A note on device fonts is that they won’t work on masking.

Enjoy!

Font Manager — January 20, 2011

Font Manager

It’s a good practice to separate your embedded fonts so as not to bloat your main file. One example for this is the embedding of fonts that are contained on a particular .SWF file. This class will act as a font factory for registering those embedded fonts. It can also provide the style and weight properties of a certain standard font.

package Managers
{
	import Interfaces.IFont;	
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.net.URLRequest;
	import flash.text.Font;
	import flash.text.TextFormat;
	public class FontManager extends EventDispatcher
	{
		public static const REGULAR:String = "Regular";
		public static const BOLD:String = "Bold";
		public static const ITALIC:String = "Italic";
		public static const BOLD_ITALIC:String = "Bold Italic";
		public static const UNDERLINE:String = "Underline";
		//
		private var aFonts:Array;
		private var iCtr:int;
		public function FontManager()
		{
			this.iCtr = 0;
			this.aFonts = new Array();
		}
		/**
		 * Sets the target's appropriate fontFamily name according to 
		 * its current style and weight.  Assuming that the fontFamily
		 * naming conventions are:
* FontName Regular
* FontName Bold
* FontName Italic
* FontName Bold Italic

* @param target A DisplayObject that supports TextFormat. * @return The newly styled TextFormat. * */ public static function setStyle(target:*, style:String):TextFormat { var t:* = target; var i:int = t.selectionBeginIndex; var j:int = t.selectionEndIndex; var tf:TextFormat = t.getTextFormat(i, j); var name:String = tf.font ? tf.font : t.getTextFormat(i, i + 1).font; var prefix:String = name.substring(0, name.indexOf(" ") + 1); switch(style) { case FontManager.BOLD: tf.bold = !tf.bold; tf.font = prefix + style; break; case FontManager.ITALIC: tf.italic = !tf.italic; tf.font = prefix + style; break; case FontManager.UNDERLINE: tf.underline = !tf.underline; break; } if(tf.bold && tf.italic) tf.font = prefix + FontManager.BOLD_ITALIC; else if(!tf.bold && !tf.italic) tf.font = prefix + FontManager.REGULAR; t.setTextFormat(tf, i, j); return tf; } public final function addFont(name:String):Boolean { var i:int = this.aFonts.length; for (var a:int = 0; a < i.valueOf(); a++) if (name == this.aFonts[a]) return false; this.aFonts.push(name); return true; } public final function removeFont(name:String):Boolean { var i:int = this.aFonts.length; for (var a:int = 0; a = this.aFonts.length ? this.dispatchEvent(new Event(Event.COMPLETE)) : this.loadFonts(); } public final function get fonts():Array { return this.aFonts.slice(0); } public final function loadFonts():void { var s:String = this.aFonts[this.iCtr.valueOf()]; this.iCtr++; var l:Loader = new Loader(); l.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, this.onError); l.contentLoaderInfo.addEventListener(Event.COMPLETE, this.onFontLoaded); l.load(new URLRequest(s)); } private final function onFontLoaded(e:Event):void { var d:IFont = IFont(e.target.content); if (e.type == Event.COMPLETE) { if (d.regular()) Font.registerFont(d.regular()); if (d.bold()) Font.registerFont(d.bold()); if (d.italic()) Font.registerFont(d.italic()); if (d.boldItalic()) Font.registerFont(d.boldItalic()); } this.iCtr.valueOf() >= this.aFonts.length ? this.dispatchEvent(new Event(Event.COMPLETE)) : this.loadFonts(); } } }

Here’s the CSS format for embedding the fonts.

@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
@font-face
{
	src:url("arial.ttf");
	font-family:"Arial Regular";
	embedFonts: true;
	embedAsCFF: false;
}
@font-face
{
	src:url("ariali.ttf");
	font-family:"Arial Italic";
	embedFonts: true;
	embedAsCFF: false;
}
@font-face
{
	src:url("arialbd.ttf");
	font-family:"Arial Bold";
	embedFonts: true;
	font-weight:bold;
	embedAsCFF: false;
}
@font-face
{
	src:url("arialbi.ttf");
	font-family:"Arial Bold Italic";
	embedFonts: true;
	font-weight:bold;
	font-style:italic;
	embedAsCFF: false;
}

Here’s an example of embedding fonts using a metadata on a .AS file that will be converted in to a .SWF file.

package Fonts
{
	import Interfaces.IFont;
	import flash.display.Sprite;
	public class Arial extends Sprite implements IFont
	{
		[Embed(source = "Fonts/Arials/arial.ttf",
						fontFamily = "Arial Regular",
						embedAsCFF="false")]
						private static const Regular:Class;
		[Embed(source = "Fonts/Arials/arialbd.ttf",
						fontFamily = "Arial Bold",
						fontWeight = "bold",
						embedAsCFF="false")]
						private static const Bold:Class;
		[Embed(source = "Fonts/Arials/arialbi.ttf",
						fontFamily = "Arial Bold Italic",
						fontWeight = "bold",
						fontStyle = "italic",
						embedAsCFF="false")]
						private static const BoldItalic:Class;
		[Embed(source = "Fonts/Arials/ariali.ttf",
						fontFamily = "Arial Italic",
						fontStyle = "italic",
						embedAsCFF="false")]
						private static const Italic:Class;
		public final function regular():Class
		{
			return Arial.Regular;
		}
		public final function bold():Class
		{
			return Arial.Bold;
		}
		public final function italic():Class
		{
			return Arial.Italic;
		}
		public final function boldItalic():Class
		{
			return Arial.BoldItalic;
		}
	}
}

And here’s the interface.

package Interfaces
{
	public interface IFont
	{
		function regular():Class;
		function bold():Class;
		function italic():Class;
		function boldItalic():Class;
	}
}

If you’re going to use the metadata embedded mechanism, just load and automatically register the public classes of the generated .SWF file such as Arial.swf using FontManager.addFont(“Arial”) method.

To use the setStyle method on a Flex 4 project, you can do so like:

<mx:HBox>
<s:Button label="Bold" click="FontManager.setStyle(this.txtTgt, FontManager.BOLD);" />
<s:Button label="Italic" click="FontManager.setStyle(this.txtTgt, FontManager.ITALIC);" />
<s:Button label="Underline" click="FontManager.setStyle(this.txtTgt, FontManager.UNDERLINE);" />
</mx:HBox>

Enjoy!

Storing Values to AS3 using Google Spreadsheets — November 9, 2010

Storing Values to AS3 using Google Spreadsheets

This topic is separated into two parts –storing and retrieving. Retrieving is in another topic. Imagine storing values to a spreadsheet that Flash can retrieve and store them into variables wherein the designer or the project manager no longer has to request for you to change the values. They can change them, themselves. For example, if you have a war game that has a “Bullet Speed” in it, you can just place a column in the spreadsheet and the designers can enter desired values themselves. A self-documenting and a better way to interact with other development teams.

Before we start, there are certain stuffs that you need to setup and download:

1. Firefox and Firebug, which enables us to determine the page header’s request and response values. Once Firebug is installed in Firefox, press F12, go to the “Net” tab and select “Enabled”

2. XAMPP (with cURL enabled) for Windows, which enables us to create a crossdomain policy file that gives us privileges to write into Google’s spreadsheets

3. A Google account to create our spreadsheets

Setting up the spreadsheet

Login to Google and create a spreadsheet. In the empty spreadsheet, search for the phrase “Public on the web”, click “Change”, select “Public on the web” and check “Allow anyone to edit (no sign-in required)”. Save and close the dialog.

Click Form > Create a form. A popup window will appear.

In the Question Title, remove the word “Sample Question 1” and enter the word “BulletSpeed” and click Done.

Remove “Sample Question 2” by clicking its Trash icon.

Click Save.

Before closing the popup window, take note of the formKey value below the window and save it. This value is required when we submit values from Flash to the spreadsheet.

Close the popup window.

By the time the popup window closes, the spreadsheet creates a “Timestamp” and “BulletSpeed” columns in rows A1 and B1, respectively. Timestamp is automatically created by the spreadsheet, which tracks changes in the spread.

Leave the spread like that for now and proceed to setting up the PHP directory and crossdomain proxy file.

Setting up a project directory and crossdomain proxy file using PHP’s cURL

In your XAMPP’s HTDocs directory, create a new directory called WarGame. Inside that directory, create a php file called crossdomain_proxy.php and paste this code:

<?php
	/* Only proxy to URLs matching this */
	$sProxyUrlRegex = '#^http://spreadsheets.google.com/#';
	/**
	* Make a simple status/error page.
	*/
	function showErrorStatus ($iCode=500, $sText='Internal Server Error')
	{
		header("HTTP/1.1 $iCode $sText");
		header("Status: $iCode $sText");
		echo "<html><head><title>Oops</title></head><body><h1>" . $sText . "</h1></body></html>";
	}

	/**
	* Replacement for curl_setopt which only exists in PHP>=5.1.3
	*
	* @param resource $rCh
	* @param array $aCurlOpt
	*/
	function local_curl_setopt_array ($rCh, $aCurlOpt)
	{
		foreach ($aCurlOpt as $sKey=>$sVal) {
			if (!curl_setopt($rCh, $sKey, $sVal)) {
				return false;
			}
		}
		return true;
	}

	/* Set cURL options */
	function init (){
		$aCurlOpt = array (
			CURLOPT_FAILONERROR		=> true, // Fail on non-200 responses
			CURLOPT_POST			=> true,
			CURLOPT_RETURNTRANSFER	=> true,
			CURLOPT_TIMEOUT			=> 60,
			CURLOPT_HEADER			=> false, // Don't include header in response
			CURLOPT_USERAGENT		=> 'Mozilla/5.0 (Windows; U; MSIE 7.0; Windows NT 6.0; en-US)',
			CURLOPT_FOLLOWLOCATION	=> true,
			CURLOPT_MAXREDIRS		=> 5
		);

		/* Check URL is specified */
		if (!isset($_POST['_url']) || empty($_POST['_url'])) {
			showErrorStatus(400, 'No URL specified');
			exit;
		}

		/* Set cURL URL and remove from POST before forwarding */
		$sCurlUrl = $_POST['url'];
		unset($_POST['url']);

		/* Make POST string */
		$aPostData = array();
		foreach ($_POST as $sKey=>$sVal) {
			$sKey = str_replace('_', '.', $sKey); // Revert PHP conversion nonsense
			$aPostData[] = urlencode($sKey) . '=' . urlencode($sVal);
		}

		$sPostData = join('&', $aPostData);

		/* Do cURL stuff */
		if (false == preg_match($sProxyUrlRegex, $sCurlUrl)) {
			showErrorStatus(401, 'Naughty, you can\'t proxy to ' . $sCurlUrl);
		} else if (!$rCh = curl_init($sCurlUrl)) {
			showErrorStatus(NULL, 'Couldn\'t initialize cURL to ' . $sCurlUrl);
		} else if (false == local_curl_setopt_array($rCh, $aCurlOpt)) {
			showErrorStatus(NULL, 'Couldn\'t set cURL options');
		} else if (false == curl_setopt($rCh, CURLOPT_POSTFIELDS, $sPostData)) {
			showErrorStatus(NULL, 'Couldn\'t set POST vars');
		} else if (false == ($sResponse = curl_exec($rCh))) {
			showErrorStatus(NULL, 'Response was false');
		} else {
			/* All good */
			echo $sResponse;
		}
	}
	//
	init();
	exit;
?>

Coding the AS3

function storeVariables():void
{
	var loader:URLLoader = new URLLoader();
	var variables:URLVariables = new URLVariables();
	variables["entry.0.single"] = "hello world";
	var key = "0AlmPB8Zwh3pZdDBjMzY5TzJjZnhTSmFmbmlyVkJXNWc";
	variables["url"] = "http://spreadsheets.google.com/formResponse?key="+key;
	//Call the proxy page passing all the variables above.
	var request:URLRequest = new URLRequest("crossdomain_proxy.php");
	request.data = variables;
	request.method = URLRequestMethod.POST;
	loader.addEventListener(Event.COMPLETE, function(e:Event):void{
		trace(e.target.data);
	});
	loader.load(request);
}

Proving the spreadsheet’s field naming convention

You may be wondering, how did “entry.0.single” get in there? I myself isn’t quite sure as to why Google named it that way. However, to determine how I got this property, I still use Firebug.

Go to the Google spreadsheet…

Tracking the changes by watching the Cache

A simple note whenever you’re trying to modify any of the .php or .as files, always clear the browser’s cache. To prove that the .php file is cached, go to the method “showErrorStatus” in “crossdomain_proxy.php”, try deleting a simple greater-than symbol in the last portion of the echoed string and determine its value in the Firebug’s “Net” tab.

echo “<html><head><title>Oops</title></head><body><h1>$sText</h1></body></html”;

Refresh your browser without clearing the cache and launch Firebug.

Locate “POST crossdomain_proxy.php” and go the the “Response” tab. If the output is not the same on the above, then your Flash page is being cached by the browser.

There you have it! Storing values to the Google spreadsheet using AS3. You may want to proceed in Retrieving Values from Google Spreadsheets using AS3 to continue on the second part of this post.

Download

FlashToGoogleSpreadsheet.zip

No really, what’s the use of AS3 Namespace? —

No really, what’s the use of AS3 Namespace?

One of the purpose of a namespace in AS3 is not only to provide scoping mechanism but also to avoid name conflicts. Assume you’re going to create a StringUtility class that consists of multiple different methods called “trim” developed by your friends namely Abraham and Thomas.

Create a project folder named NamespaceTest.

Inside that directory, create a namespace file called abraham.as like so:

package{
	public namespace abraham = "Abraham Lincoln";
}

Then create a second namespace file called thomas.as like so:

package{
	public namespace thomas = "Thomas Jefferson";
}

Create a class file called StringUtility.as like so:

package{
    public final class StringUtility{
        public function StringUtility(){
           trace(StringUtility.abraham::trim(""));
        }
        //
        abraham static function trim(value:String):String{
            return "a";
        }
        thomas static function trim(value:String):String{
            return "b";
        }
    }
}

Then create a file called NamespaceTest.fla and place this in the Actions Panel:

trace(StringUtility.thomas::trim(""));

A namespace not only allows you to have a multiple function names in a single class but also provides another scoping feature on how to access a method without making method public. To use the trim methods on another projects, just import the namespace itself, which would deliberately make the method look like public. Assuming that you already know name your packages and set your Flash IDE.

SeparateNamespaceTest.fla is on a separate project directory.

import  abraham;
import thomas;
//
trace(StringUtility.::abraham(""));

If you only plan to use your namespaces internally and directly access your multiple methods, declare your namespaces like so inside the class:

package{
    public final class StringUtility{
        public namespace abraham = "Abraham Lincoln";
        public namespace thomas = "Thomas Jefferson";
        //
        public function StringUtility(){
           StringUtility.abraham::trim("");
        }
        //
        abraham static function trim(value:String):String{
            return "a";
        }
        thomas static function trim(value:String):String{
            return "b";
        }
    }
}

I hope that made it clear for you as to what the basic purpose of a namespace in AS3 is.

Event Listeners — October 14, 2010

Event Listeners

In this tutorial, you will learn how to create a basic event listener, which includes an understandable name, how to properly cast the calling object and how to efficiently determine certain type of events that’s currently dispatching.


There are infinite ways of naming a listener. Anyone can name it mouseEventListener, onMouseEventListener or onMouseEventDispatch. On my end, I typically name my event listeners according to their class names. For mouse events, I name it mouseEventListener.

public final function mouseEventListener(e:MouseEvent):void{}

Meanwhile, comparing different type of events that fired the event can be done like so:

public final function onMouseEvent(e:MouseEvent):void{
	switch(e.type){
		case MouseEvent.MOUSE_DOWN:
			//
		break;
		case MouseEvent.MOUSE_UP:
			//
		break;
		case MouseEvent.CLICK:
			//
		break;
	}
}

The Event.target method is a generic object type. This makes it dynamic but slow since Flash has to determine its correct data type. Also there are instances wherein you want to display the properties of the target object that is firing the event regardless of its phases. You can do so by casting it to its correct data type.

public final function onMouseEvent(e:MouseEvent):void{
	var i:Item = Item(e.target);
	switch(e.type){
		case MouseEvent.CLICK:
			i.visible = false;
		break;
	}
}

Congratulations. You have successfully created an efficient and easy to read event listener.

Custom Events —

Custom Events

In this tutorial, you will learn how to extend the native Event class to create your own custom events. Though there are many styles and forms this class can achieve, this tutorial will give you the basic way of creating one.


The very basic look of a custom event class is like this.

package Prezire.Mobiles.Games.HiddenObjectGames.Events{
	import flash.events.Event;
	public class ItemEvent extends Event{
		public function ItemEvent(type:String, 
						bubbles:Boolean, 
						cancelable:Boolean = false){
			super(type, bubbles, cancelable);
		}
	}
}

And to use it would be like:

this.dispatchEvent(new ItemEvent("onFound"));

One that’s vaguely used is the concept of creating a literal value in the first parameter. This of course is acceptable however, is considered unreliable for the reason that it could be misspelled. To solve this, you can create a static variable inside the class.

public static FOUND:String = "onFound";

This makes the whole class look like this.

package Prezire.Mobiles.Games.HiddenObjectGames.Events{
	import flash.events.Event;
	public class ItemEvent extends Event{
		public static FOUND:String = "onFound";
		public function ItemEvent(type:String, 
						bubbles:Boolean, 
						cancelable:Boolean = false){
			super(type, bubbles, cancelable);
		}
	}
}

Once the event is dispatched, the listener of that event can then correctly identify, which type of event is firing. In this case “onFound”.

private final function itemEventListener(e:ItemEvent):void{
	switch(e.type){
		case ItemEvent.FOUND:
			//Animate the target to fade out.
		break;
	}
}

In this example, the letter “n” of the word onFound is capitalized. This doesn’t produce an error however, rest assured that your switch-case’s condition won’t be met.

private final function itemEventListener(e:ItemEvent):void{
	switch(e.type){
		case "oNFound":
			//Animate the target to fade out.
		break;
	}
}

Avoid creating another property inside a custom event class unless it is absolutely necessary. In this example, a bonus method is added on any random occassion once the event is dispatched.

package Prezire.Mobiles.Games.HiddenObjectGames.Events{
	import flash.events.Event;
	public class ItemEvent extends Event{
		public static FOUND:String = "onFound";
		private var iBonus:int;
		public function ItemEvent(type:String, 
						bubbles:Boolean, 
						cancelable:Boolean = false){
			super(type, bubbles, cancelable);
		}
		public final function set bonus(value:int):void{
			this.iBonus = value;
		}
		public final function get bonus():int{
			return this.iBonus;
		}
	}
}

Refer to ie.bonus when adding a bonus value during dispatching.

private final function itemClickListener(e:MouseEvent):void{
	var i:Item = Item(e.target);
	switch(e.type){
		case MouseEvent.CLICK:
			var ie:ItemEvent = new ItemEvent(ItemEvent.FOUND);
			if(Math.random() * 3 < 1){
				ie.bonus = 300;
			}
			i.dispatchEvent(ie);
		break;
	}
}

The example above is acceptable however, why not just place the “bonus” method inside the Item class itself like so?

package Prezire.Mobiles.Games.HiddenObjectGames{
	import flash.displays.MovieClip;
	public class Item extends MovieClip{
		private var iBonus:int;
		public function Item(){
			//
		}
		public final function set bonus(value:int):void{
			this.iBonus = value;
		}
		public final function get bonus():int{
			return this.iBonus;
		}
	}
}

And set the bonus value during dispatch like so:

private final function itemClickListener(e:MouseEvent):void{
	var i:Item = Item(e.target);
	switch(e.type){
		case MouseEvent.CLICK:
			if(Math.random() * 3 < 1){
				i.bonus = 300;
			}
			i.dispatchEvent(new ItemEvent(ItemEvent.FOUND));
		}
	}
}

Congratulations! You have successfully created your own custom event class that is considered reliable, efficient and suitable for the class that needs it.

Packages —

Packages

In this tutorial, you will learn how to name your libraries and their packages in an easy and readable way. Though most of these are unorthodox, it will make your packages readable and easier to maintain.


The word com really does mean computer or related to a word .com in the web.  It’s a concept of having a root name that is unique when compared to all other packages that exists in a specific directory.  In this case, the word com actually means the scope of your company. What’s missing typically is the company name. However, most classes nowadays can be used interchangeably either into a web or desktop application. So the point is, it’s OK to remove the scope if the purpose of your library is generic. In short, you can have a template for the three structures: companyname.scope.packagename.

prezire.com.packagename

or

prezire.local.packagename

or

prezire.packagename

Another feature of ActionScript 3’s is it’s ability to distinguish capital letters in package names.  You can actually name them with inter-caps, combined with a plural convention like Com.PackageNames1.PackageNames2.

For instance, I typically name most of my generic personal library packages as:

Prezire.Graphics.TransformTools

or

Prezire.Numbers.Converters

or

Prezire.Strings.RichTextEditors

So if you have multiple classes, you can just name them under the package as:

Prezire.Mobiles.HiddenObjectGames.HiddenObjectGameBasic

and

Prezire.Mobiles.HiddenObjectGames.HiddenObjectGameAdvanced

With this, conflicts can be avoided when having the same class names.  For example, both Senocular and I have a class called TransformTool.as in each of our own libraries.  If I decide to use either of these classes, on a single .as document, I can just say so using a fully qualified class name like so:

var myTool:Prezire.Graphics.TransformTools.TransformTool = new Prezire.Graphics.TransformTools.TransformTool();
var hisTool:Senocular.TransformTool = new Senocular.TransformTool();

Compare your code being like this. The conventional style wherein there is a word com in the first, mixed plural and / or singular package names and all lower cased letters.  The first one is using a singular hiddenobjectgame folder name all in lower case…

import com.mobiles.hiddenobjectgame.HiddenObjectGameIntro;

…to an unorthodox like this, which maintains the plural form of a folder name HiddenObjectGames using inter-caps.

import Prezire.Mobiles.HiddenObjectGames.HiddenObjectGameIntro;

So there you have it. A cleaner and easier to maintain package!