Archive for the ‘AS3’ Category

This isn’t right… MovieClip nested inside Button throwing null object reference error in Flash CS4

Thursday, September 10th, 2009

A great thing about teaching is that your students approach problems in ways you haven’t done before and run into problems that you never knew existed. This is one such problem in Flash CS4 and a curious one at that.

THE PROBLEM: A Button symbol is placed on the Stage on a frame other than the first frame and given an instance name in the Properties panel. In the Actions panel, ActionScript is added that references the instance name of the button on the same frame that the button instance first appears on. The movie is tested and the following error occurs:

TypeError: Error #1009: Cannot access a property or method of a null object reference.
at MovieClipInsideButton_fla::MainTimeline/frame2()

Normally this error means that a particular instance has not been given an instance name in the Properties panel on the frame where the ActionScript appears. However, nothing looks amiss in the ActionScript or on the Stage. Adding a trace statement, such as trace(myButton); reveals null in the output window, meaning the trace statement has run before the instance name has been set to the button instance on the Stage. Hmm… very perplexing, since you may have other buttons and movieclips that work fine when referenced from ActionScript.

THE SOLUTION: From what I found, one scenario will produce this error. If a MovieClip symbol (instance) appears inside a Button symbol and the button appears on any frame other than the first frame, and the frame where the ActionScript references it is the same frame it first appears on—then this behavior will result.

MC_inside_button

There are a few workarounds:

  1. Retrieve the instance from the display list of its parent. Instead of referencing the Button instance on the stage directly, use getChildByName(.) to retrieve a reference to the instance, this can even be set to instance name at the beginning of your timeline code, like so:
    // myButton is the name of the instance as set in the Properties panel.
    // Retrieved child is cast as a SimpleButton, since this is the 
    // class of the Button symbol
    myButton = SimpleButton(getChildByName("myButton"));
  2. Do not nest a MovieClip inside a Button symbol. A Button nested inside a Button, a MovieClip nested inside a MovieClip, and a Button nested inside a MovieClip work fine.
  3. Place the first occurance of the Button instance on any frame before the frame where ActionScript first references it. This behavior appears to indicate Flash is taking too long to parse over the MovieClip inside a Button and runs the ActionScript on the timeline prematurely. Having the instance appear on a frame prior to the frame the ActionScript appears on ensures the instance is completely present in memory before it is referenced.
  4. Place the instance referencing code inside an enter frame event handler function. To ensure the entire frame has been parsed before any ActionScript code is run, enclose the offending code inside the event handler function of the enter frame event, and only make it run once, like so:
    addEventListener( Event.ENTER_FRAME , ensureRendered );
     
    function ensureRendered( evt:Event ) : void
    {
    	removeEventListener( Event.ENTER_FRAME , ensureRendered );
    	// All instance referencing code appears below this point
    	// In this case, instance is named "myButton" on the Stage
    	myButton.width = 200;
    }

This behavior doesn’t seem right to me and even seems it could be a bug. If anyone has an explanation for this behavior, I would love to hear it. You may download an example FLA here: Download Source

UPDATE September 20, 2009: I added a new workaround, which is probably the most succinct and reliable one yet to use. See Retrieve the instance from the display list of its parent in the list of workarounds.

Creating a date countdown timer in ActionScript 3 / Flash

Monday, August 3rd, 2009

Creating a countdown timer in ActionScript is quite easy. The essentials of it are:

  1. Specify a target date to countdown to using the Date class.
  2. Create a Timer instance to check the countdown time each second or so.
  3. At each tick of the timer calculate the number of milliseconds between now and the target date.
  4. Determine how many days, hours, minutes, seconds, etc. that number of milliseconds is equal to.
  5. Update the graphics to reflect the amount of time left.

The following is an example of a countdown timer, with a link to the source code below. This utilizes a reusable class file for the countdown timer. All code specific to this particular implementation can be found in com/anselmbradford/Main.as.

This movie requires Flash Player 9

Download Source

How to build an Object-Oriented ActionScript 3 Preloader in Flash CS4: 2 Methods

Saturday, June 20th, 2009

The magic of creating a preloader in ActionScript 3 lies in the LoaderInfo class. Every instantiated DisplayObject instance (all objects that appear on the stage, plus the stage itself) have a loaderInfo property that returns a LoaderInfo instance that contains information about the loading progress of that particular display object. Creating a preloader for the whole application is a matter of monitoring these LoaderInfo instances.

Method 1: Monitor Stage LoaderInfo instance

Under this method the loading progress is monitored via the LoaderInfo instance associated with the stage. Since all assets that will appear in the application need to be attached to the stage, the stage’s LoaderInfo instance will reflect the loading of all these assets.

Graphics

  1. Go to File → New… and select Flash File (ActionScript 3.0).
  2. Using the Rectangle tool create a rectangle (include a stroke) on the stage that is 100 pixels wide by 10 pixels high.
  3. Click on the fill of the newly created rectangle and select Modify → Convert to Symbol… Name the new instance ProgBar and set the registration point to left-middle. This will be the progress bar of the preloader.

    preloader_pbar

  4. With the new ProgBar instance selected on the stage, go to the Properties panel and name the instance progBar.
  5. Select the whole rectangle (stroke and progress bar instance). Select Modify → Convert to Symbol… Name the new instance Preloader and set the registration point to left-middle. Check the Export for ActionScript button.
  6. Click OK. If you get a warning that says the “definition for this class could not be found” click OK again.
  7. With the new Preloader instance selected, go to the Properties panel and name the newly created instance preloader. Your library should look like the following:

    preloader_library

  8. Select frame 2 of the main timeline, go to Insert → Timeline → Blank Keyframe. All content for the application will appear on frame 2 and beyond.
  9. Go to Insert → New Symbol… Name the new instance Content. If you check Export for ActionScript be sure to uncheck Export in frame 1, otherwise the preloader will not function properly.
  10. Place all content of the application on the timeline of the newly created Content instance.
  11. Return to the main timeline. Select frame 2 and drag an instance of the Content symbol from the library and place it on the stage.
  12. In the Properties panel of the stage name the document class Main. If you get a warning that says the “definition for this class could not be found” click OK.

    preloader_docclass

  13. Save the file.

Code

  1. Go to File → New… and select ActionScript File.
  2. Paste the following code and save the file as Preloader.as in the same directory as the .fla file saved earlier.
    package
    {
    	import flash.display.Sprite;
    	import flash.display.LoaderInfo;
    	import flash.events.Event;
     
    	public class Preloader extends Sprite
    	{
    		/**
    		* Alias for stage LoaderInfo instance
    		*/
    		private var _targetLoaderInfo:LoaderInfo;
     
    		/**
    		* The percent loaded
    		*/
    		private var _loadPercent:Number = 0;
     
    		/**
    		* Constructor
    		* Listen for when the preloader has been added to the stage 
    		* so that the progress of the remaining load can be monitored.
    		*/
    		public function Preloader()
    		{
    			this.addEventListener( Event.ADDED_TO_STAGE , _init );
    		}
     
    		/**
    		* Initialize variables.
    		* Set initial width of the progress bar to 0 
    		* and listen for enter frame event.
    		*/
    		private function _init(evt:Event):void
    		{
    			_targetLoaderInfo = stage.loaderInfo;
     
    			progBar.scaleX = 0;
     
    			this.removeEventListener( Event.ADDED_TO_STAGE , _init );
    			this.addEventListener(Event.ENTER_FRAME, _onCheckLoaded);
    		}
     
    		/**
    		* Check the status of the load, once complete dispatch a complete event.
    		*/
    		private function _onCheckLoaded(evt:Event):void 
    		{
    			_loadPercent = _targetLoaderInfo.bytesLoaded / _targetLoaderInfo.bytesTotal;
    			progBar.scaleX = _loadPercent;
    			if (progBar.scaleX == 1)
    			{
    				this.removeEventListener(Event.ENTER_FRAME, _onCheckLoaded);
    				this.dispatchEvent( new Event(Event.COMPLETE) );
    			}
    		}
    	}	
    }
  3. Go to File → New… and select ActionScript File a second time.
  4. Paste the following code and save the file as Main.as in the same directory as the .fla file saved earlier.
    package 
    {
    	import flash.display.MovieClip;
    	import flash.events.Event;
     
    	public class Main extends MovieClip 
    	{
    		/**
    		* Constructor
    		* Stop timeline and add event listener to preloader.
    		*/
    		public function Main() 
    		{
    			this.stop();
    			preloader.addEventListener( Event.COMPLETE , _initContent );
    		}
     
    		/**
    		* Load has finished, remove preloader and preceed to next frame.
    		*/
    		private function _initContent(evt:Event):void 
    		{
    			preloader.removeEventListener( Event.COMPLETE , _initContent );
    			this.removeChild(preloader);
    			nextFrame();
    		}
    	}
    }
  5. To test the preloader go to Control → Test Movie. Go to View → Simulate Download.
  6. Download method 1 complete source

Method 2: Monitor content SWF LoaderInfo instance

Under this method two SWFs are created, one encapsulating the preloader and the other encapsulating all content. The content SWF is loaded inside of the preloader SWF, which monitors the loading progress.

Graphics

  1. Follow steps 1 – 7 in the previous method.
  2. In the Properties panel of the stage name the document class PreloaderWrapper. If you get a warning that says the “definition for this class could not be found” click OK.
  3. Save the file.
  4. Go to File → New… and select Flash File (ActionScript 3.0).
  5. Add the content for your application to the timeline of this file.
  6. Save the file as content.fla.
  7. Go to Control → Test Movie to create the content.swf that will be loaded by the preloader SWF.

Code

  1. Go to File → New… and select ActionScript File.
  2. Paste the following code and save the file as PreloaderWrapper.as in the same directory as the .fla file saved earlier.
    package 
    {
    	import flash.display.Sprite;
    	import flash.display.Loader;
    	import flash.display.LoaderInfo;
    	import flash.display.DisplayObject;
    	import flash.events.Event;
    	import flash.events.ProgressEvent;
    	import flash.net.URLRequest;
     
    	public class PreloaderWrapper extends Sprite 
    	{
    		/**
    		* Alias for content LoaderInfo instance
    		*/
    		private var _targetLoaderInfo:LoaderInfo;
     
    		/**
    		* The percent loaded
    		*/
    		private var _loadPercent:Number = 0;
     
    		/**
    		* Constructor
    		* Creates Loader instance, adds event listeners and begins loading content SWF.
    		*/
    		public function PreloaderWrapper() 
    		{
    			var loader:Loader = new Loader();
    			_targetLoaderInfo = loader.contentLoaderInfo;
    			_targetLoaderInfo.addEventListener( ProgressEvent.PROGRESS, _loadingData );
    			_targetLoaderInfo.addEventListener( Event.COMPLETE , _finishedLoading );
    			loader.load( new URLRequest("content.swf") );
     
    		}
     
    		/**
    		* Monitor loading progress and update progress bar.
    		*/
    		private function _loadingData( evt:ProgressEvent ):void 
    		{
    			_loadPercent = _targetLoaderInfo.bytesLoaded / _targetLoaderInfo.bytesTotal;
    			preloader.progBar.scaleX = _loadPercent;	
    		}
     
    		/**
    		* Remove event listeners and preloader, and attach content SWF to stage.
    		*/
    		private function _finishedLoading( evt:Event ):void 
    		{
    			_targetLoaderInfo.removeEventListener( ProgressEvent.PROGRESS, _loadingData );
    			_targetLoaderInfo.removeEventListener( Event.COMPLETE , _finishedLoading );
    			this.removeChild(preloader);
    			this.addChild( DisplayObject(LoaderInfo(evt.target).content) );
    		}
    	}
    }
  3. To test the preloader go to Control → Test Movie. Go to View → Simulate Download.
  4. Download method 2 complete source

UPDATE July 30, 2009: I noticed I forgot the private designation on two of the methods in the PreloaderWrapper class. They have been added.

Common Flash Compiler Errors: #1046

Wednesday, March 25th, 2009

This error shows the following in the Compiler Errors window:


1046: Type was not found or was not a compile-time constant: [Class name].

Quick Answer and Solution

Where I have “[Class name]” above you will have any number of names listed, for example it may say Event, Sprite, TextField, etc. What this means is you are using a piece of code that utilizes a class (typically seen as files with a “.as” extension) that you have not “imported” so that your code knows where to find it. To fix this problem perform the following:

  1. Open a web browser and navigate to Google.
  2. Enter the search “[class name] actionscript 3 site:livedocs.adobe.com” (replacing [class name] with whatever the class name is in the error message, such as TextField, MouseEvent, URLLoader, etc.). For example, “Event actionscript 3 site:livedocs.adobe.com”
  3. Look for a search result that lists the class in a format of a series of words with dots between them, probably will be the top result. Examples include:
    • flash.events.Event
    • flash.display.Sprite
    • fl.transitions.Tween
    • flash.geom.Rectangle

    This is the path to the class, which you can use to import the class into your code.

  4. Without clicking on the search result, copy the class name as it appears in the previous step.
  5. Return to Flash and double-click the error message.
  6. Scroll to the top of the code area. Type “import” and paste the path to the class. For example,
    import flash.events.Event;

If you are using code on the Timeline, this can be placed at the top of the Actions panel. If you have written a class file that is referencing another class, this code appears between the package { curly brace, and class declaration, public class MyClass.

For example,

package
{
	// class import statements appear here
	import flash.display.MovieClip;
 
	public class Main extends MovieClip
	{
		public function Main()
		{
		}
	}
}

Technical Overview

A class file is an external text file that contains variables and functions (known as properties and methods in the object-oriented programming context), essentially this means class files are self-contained blocks of code that contain code related to a particular task. To access these variables and functions within your own block of code the class file needs to be imported. If your code contains any references to a class file that has either: (a) not been imported, or (b) is not within the same folder as your .fla or .as files, then a #1046 error will be thrown. For example, suppose you have the following class file declared for a button:

package
{
	import flash.display.MovieClip;
 
	public class MyButton extends MovieClip
	{
		public function MyButton()
		{
			this.addEventListener( MouseEvent.CLICK , _clicked );
		}
 
		private function _clicked( evt:MouseEvent ) : void
		{
			// button was clicked!
		}
	}
}

Testing this code would produce the following error:

1046: Type was not found or was not a compile-time constant: MouseEvent.

With the source listed as…

private function _clicked( evt:MouseEvent ) : void

This is because the class MouseEvent is referenced in the code, but is not imported at the top of the class file. The fix is simple and looks like this:

package
{
	import flash.display.MovieClip;
	// import the MouseEvent class
	import flash.events.MouseEvent;
 
	public class MyButton extends MovieClip
	{
		public function MyButton()
		{
			this.addEventListener( MouseEvent.CLICK , _clicked );
		}
 
		private function _clicked( evt:MouseEvent ) : void
		{
			// button was clicked!
		}
	}
}

Typically if you are a beginning ActionScripter, you will run into this error when referencing classes created by Adobe. However, as you become more advanced in your scripting abilities you may place your own custom class files in “packages” that would then need to be imported using the same above process. In case you are wondering what the stuff is before the actual class name, such as “flash.display” and “flash.events,” this is the “package” that class resides in, which is essentially the folders the class file resides in on disk. For example, suppose I created a class called “MyButton” and placed it in the package “com.anselmbradford.” This class would appear in a text file called “MyButton.as” that would be in a folder called “anselmbradford” that would itself be in a folder called “com.” The class file would look like:

package com.anselmbradford
{
	import flash.display.MovieClip;
 
	public class MyButton extends MovieClip
	{
		public function MyButton()
		{
		}
	}
}

To import this class file into another class file I would place the “com” folder (containing the class file two levels in) in the same directory as my .fla or .as file that I wanted to import this class into. I would then import it using the syntax shown previously. For example:

package
{
	import flash.display.MovieClip;
	// class is imported
	import com.anselmbradford.MyButton;
 
	public class Main extends MovieClip
	{
		public function Main()
		{
			// class is referenced in code, so must be imported
			var button:MyButton = new MyButton();
		}
	}
}

Note: Whole sets of class files that are within the same package can be imported using the “*” wildcard operator. For example, flash.events.Event, and flash.events.MouseEvent, both reside in the flash.events package. Instead of having two lines to import both of these classes, you can have import flash.events.*;, which will import all the necessary classes from the flash.events package.

UPDATE October 4, 2009:This error will also occur if you have a symbol on your stage that has an instance name that is the same as a class name associated with the symbol. Check the Library panel, under the Linkages column, does any of your symbols have a name next to “Export:” that is the same as the instance name in the Properties panel of one of those symbols on the stage?

type_error

Common Flash Compiler Errors: #1042

Thursday, March 19th, 2009

This error shows the following in the Compiler Errors window:


1042: The this keyword can not be used in static methods. It can only be used in instance methods, function closures, and global code.

Quick Answer and Solution

Most likely you are you using the keyword “this” inside a class file, but it is not inside the curly braces of a function. By double-clicking on the error it will take you to the offending line of code. Check carefully to make sure where you have placed the keyword “this” is actually between the opening “{” and closing “}” braces of a function declaration. If it looks correct, but is accompanied by error #1126 (described here), then fix that error first. Also, if the “this” keyword appears in a function that has the “static” keyword in its declaration, error #1042 will also be thrown.

The following are three scenarios where a class file will throw this error:

package
{
	import flash.display.MovieClip;
 
	public class Main extends MovieClip
	{
		public function Main()
		{
		}
		// "this" keyword used outside a function
		this.visible = false;
	}
}
package
{
	import flash.display.MovieClip;
 
	public class Main extends MovieClip
	{
		public function Main()
		{
		}
 
		// function does not have a body because of misplaced semicolon,
		// so error #1126 is thrown
		public function hide():void;
		{
			// the "this" keyword is actually not in the body of a function
			// because of the above #1126 error
			this.visible = false;
		}
	}
}
package
{
	import flash.display.MovieClip;
 
	public class Main extends MovieClip
	{
		public function Main()
		{
		}
 
		// function is a "static method," meaning it runs inside the class,
		// not the object created from the class
		static public function hide():void
		{
			// the "this" keyword is inside a static method
			this.visible = false;
		}
	}
}

The corrected form of the above examples would be:

package
{
	import flash.display.MovieClip;
 
	public class Main extends MovieClip
	{
		public function Main()
		{
		}
 
		public function hide():void
		{
			// the reference to "this" is inside a non-static function
			// (called an instance method)
			this.visible = false;
		}
	}
}

Technical Overview

There are two types of methods (functions) that can appear in a class file, static methods and instance methods. Static methods refer to methods that are run via the class itself, while instance methods refer to methods run via an instance of the class. Consider the following class file:

package
{
	import flash.display.MovieClip;
 
	public class Main extends MovieClip
	{
		public function Main()
		{
		}
 
		static public function staticMethod():void
		{
			trace( "static method called!" );
		}
 
		public function instanceMethod():void
		{
			trace( "instance method called!" );
		}
	}
}

To call the first method, a new “Main” object does not need to be created, as the static method can be called on the class itself, like so:

Main.staticMethod();

Conversely, to access the other method, an (object) instance of the Main class needs to be created and then the method can be called through that object, like so:

var main:Main = new Main();
main.instanceMethod();

Use of the “this” keyword refers to the object instance of the class that the code is currently dealing with (in the above case if this appeared in the body of the instanceMethod() method it would be referring to the object placed in the main variable). Since no object instance has to be created to use static methods, the “this” keyword can not be used within those methods because there is no object in existence to refer to. Additionally, all code outside of a function declaration runs before an object instance is created (before the constructor function runs), so any references to “this” do not have an object to refer to in that context either.

Common Flash Compiler Errors: #1126

Friday, March 13th, 2009

This error shows the following in the Compiler Errors window:


1126: Function does not have a body.

Quick Answer and Solution

By double-clicking on the error it will take you to the offending line of code. This error commonly happens when the end of line designator “;” is placed at the end of a function name declaration, as in:

1
2
3
4
function init() : void;
{
	/*function body*/
}

Notice the presence of the semicolon at the end of line 1. To fix the error the semicolon is removed:

1
2
3
4
function init() : void
{
	/*function body*/
}

Technical Overview

A function is a block of code that will only run when it is “called,” meaning the above example would be run by writing the function name elsewhere, like so: init();. When a particular function is called, the code that appears between the curly braces (“{}”) is run. This is referred to as the function “body.” When you test a movie in Flash the code is read line by line by the compiler and eventually turned into a SWF. However, what you see as a single line of code and what the compiler sees as a single line of code are two different things. The compiler ignores extra white space and carriage returns. For example, to the compiler the following function declaration:

function init() : void
{
	/*function body*/
}

…is the same as:

function init():void{/*function body*/}

Because of this, it depends on the semicolon and closing curly brace (“}”) to denote that a line of code has ended. The closing curly brace is used for every piece of code that creates a block of code (functions, for example), while the semicolon is used for everything else. If a semicolon were to appear before the opening curly brace (“{“) in the above line of code, the compiler would hit the semicolon and throw an error that the function did not have a “body” because it had reached the end of the line of code without encountering an opening and closing curly brace.

Note: The one exception to this rule is the constructor function found in class files, which can oddly enough contain a semicolon after the function name declaration and the compiler will not complain, for example the following will not throw an error:

package
{
	import flash.display.MovieClip;
 
	public class Main extends MovieClip
	{
		public function Main();
		{
			/*constructor function body*/
		}
	}
}

However, while the compiler will not complain, the constructor function actually ends at the semicolon, so what’s written between the curly braces (the “constructor function body”) will not be run when a new object of this class is instantiated (well, actually it will run, but it will be in the scope of the class, not the object, so it will run prior to the creation of the object). Constructor functions are different in one other aspect as well, they do not specify a return type (no “:void” after the parentheses, for example).

Common Flash Compiler Errors: #1009

Thursday, February 26th, 2009

My students often run into the same kinds of errors, so I thought I would post some info on the more common ones. One very common error to receive in Flash is this one:


TypeError: Error #1009: Cannot access a property or method of a null object reference.

Quick Answer and Solution

Somewhere in your code there is a variable that you are using to refer to a property or method of an object (such as a movie clip), however, it does not actually contain an object so it throws an error. Look for the parts of your code where you have a dot following a variable name and some property or method, such as myMC.width or myMC.startDrag(). Place a trace statement above this variable to see if its value is null.

 
trace( myMC );
// if this lists "null" in the output window the next line of code will throw an error
// look for the first occurrence of myMC (where it was created) to see why it does not 
// contain a reference to something other than null
myMC.width = 200;

Technical Overview

Objects are collections of variables and functions that are defined in a class file. In the context of Object-Oriented Programming, variables are referred to as properties, and functions are referred to as methods. A movie clip object (which is an instance of the MovieClip class) contains properties and methods for dealing with the appearance and interactivity of movie clips, such as x, y, width, height, startDrag(), addEventListener(.), etc. When a new object is created it is typically stored in a variable—technically meaning a reference to the object is stored in the variable, not the actual object—the variable acts like a unique identifier to lookup the object within a particular section of code (called the scope of the variable).

For example, a new movie clip object can be created with new MovieClip(), this would then be stored in a variable (named myMC in this example) with the code var myMC:MovieClip = new MovieClip();. Properties and methods of this movie clip object can be accessed using dot notation. For example, to return the width in pixels of the movie clip, the following may be typed:

var myMC:MovieClip = new MovieClip();
trace( myMC.width );
// outputs 0 because the movie clip doesn't have any graphics, 
// and is therefore 0 pixels wide

If the variable was created, but not set to reference a new movie clip object instance, it will be empty and contain the special value of null, denoting the absence of a reference to an object. Trying to access a property or method via the variable would then mean the computer would attempt to find the property or method of a null value, which being a placeholder for “no value,” throws an error.

var myMC:MovieClip;
trace( myMC.width );
// throws error #1009 because the variable myMC does not contain a reference to an object

Flash movie clip transformational properties explorer, manipulate values live!

Thursday, February 12th, 2009

I created this simulation to visually show the relationships between a movie clip’s (actually any display object’s) transformational properties (x, y, width, height, scaleX, scaleY, rotation, and transformational matrix). Drag the square around the “Stage” and move the sliders to transform it. Each property is prefixed with a dot “.” since in a real application these properties would be accessed via myMC.x or myMC.transform.matrix.tx, for example, where myMC is the instance name of the movie clip on the stage.

Additionally, if you look carefully this shows an apparent bug in the way ActionScript 3 handles the width and height properties of a rotated movie clip (see Grant Skinner’s post on the subject). If the movie clip is rotated and the width and height sliders are moved slowly, they will swap their values back and forth as one or the other is adjusted. This could stem from the fact that the height and width are of the dimensions of the bounding box, not the movie clip itself, and they may be trying to maintain the proportions of the movie clip when adjusted. Or it’s a bug.

This movie requires Flash Player 9

Curious about Adobe Open Source? Get started with the Flex SDK on Mac OS X

Tuesday, January 6th, 2009

How about creating a SWF that runs in the Adobe Flash Player without building it in the Flash or Flex Builder authoring environment, using tools that are free and open source? Ever since Adobe made the move from ActionScript 2.0 to 3.0 there has been a gem of a toolkit available that allows precisely that. The Flex SDK (Software Development Kit) allows developers to create SWFs from ActionScript and MXML source code, and with the right setup is not difficult to configure and use.

Housed at Adobe Open Source, the Flex SDK is available in two incarnations through the site:

  • The Open Source Flex SDK containing everything needed to create a functional application using ActionScript and/or MXML and the Flex framework.
  • The Free Adobe Flex 3 SDK containing everything in the Open Source Flex SDK plus additional components such as advanced font encoders, tools for packaging Adobe AIR applications, and the Adobe Flash Player.
  • How to use the Flex SDK

    I have developed an Apache Ant build script that makes—after some configuration—the Flex SDK quite easy to use on Mac OS X. Here’s how to configure it:

    1. Download the latest Flex SDK from Adobe Open Source. Rename the SDK folder flex_sdk_3 and place it in /Applications/ on your hard drive.
    2. Locate Apache Ant on your system. Ant will already be installed if you have installed the Mac OS X Developer Tools (which are an optional install included with every version of OS X) or are running Leopard.

      Open Terminal and type:

      whereis ant

      It should say something like

      /usr/bin/ant

      If Ant is not installed, no path will be shown in Terminal. To install Ant I recommend using MacPorts, an excellent open source utility for managing unix tools on Mac OS X (follow these well written directions for installation). If you are not comfortable using the Terminal, there is a GUI available for MacPorts called Porticus.

    3. Copy the Flex Ant tasks to your Ant installation’s library. These will allow Ant to communicate with the major Flex SDK tools. To copy the tasks, first locate the Ant lib directory, which will be in Ant’s main installation folder. For example on Mac OS X 10.5 it appears at usr/share/ant/lib. Copy /Applications/flex_sdk_3/ant/lib/flexTasks.jar into this directory.
    4. If you are an advanced user and would like to utilize Unit Testing using FlexUnit, Download the FlexUnit Ant Tasks. Place these in the Ant installation’s library folder as well.

      (Note: The project template you will download from my site in the next step includes two SWCs for use with unit testing. For those that may be curious where these came from, here are the links to the original locations: FlexUnit SWC library and FlexUnit Optional SWC library)

    5. Download the Flex SDK example application template from my site. Unzip the archive and place the FlexSDKProjectTemplate folder on your desktop. Open the folder.
    6. Make a copy of build.properties.template and rename it build.properties.
    7. Open the build.properties file you just created and edit the REQUIRED TOOL LOCATIONS section to reflect the path to the Flex SDK, your preferred web browser, and the location of the Flash Player (which you will need to download if you have not already done so).
    8. Using Terminal navigate to the example application template. For example:
      cd Desktop/FlexSDKProjectTemplate/

      And then type the following:

      ant run

      The sample application will launch, typing ant usage will show you what other options are available, such as creating documentation, SWCs, or launching the application in a web browser.

    9. Lastly, to enable the trace() method so that it will work from your code when using the Flash debug player, create a textfile called mm.cfg and fill it with the following:

      TraceOutPutFileName=flashlog.txt
      ErrorReportingEnable=1
      TraceOutputFileEnable=1
      MaxWarnings=0

      Place this file at
      /Library/Application Support/Macromedia/mm.cfg
      . Whenever you have a trace("some text"); statement in your code, it will be written to:

      /Users/[your username]/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt

    Please leave comments with any suggestions, problems, questions, etc. Enjoy!

    Troubleshooting

    Problem: Running ASDoc produces: Execute failed: java.io.IOException: /Applications/flex_sdk_3/bin/asdoc: cannot execute

    Solution: This mostly likely means the ASDoc script Ant uses is not set to be executable. Type the following in Terminal:

    cd /Applications/flex_sdk_3/bin/
    chmod +x asdoc

    The first line changes the directory to the one ASDoc resides in. The second line makes ASDoc executable.

    Problem: Running ASDoc produces: exec returned: 255

    Solution: This mostly likely means the ASDoc script (which is just a text file) contains Window-style line endings. These will need to be converted to linux.

    Install dos2unix using MacPorts and type the following in Terminal:

    cd /Applications/flex_sdk_3/bin/
    dos2unix asdoc

    This will turn off the executable bit in the permission tables, so you will have to re-enable that using the instructions in the first solution above.

    Problem: Running ASDoc produces: Could not create toplevel.xml: /Applications/flex_sdk_3/asdoc/templates/asDocHelper: cannot execute

    Solution: This mostly likely means that a helper script used by ASDoc is not set to be executable. Type the following in Terminal:

    cd /Applications/flex_sdk_3/asdoc/templates/
    chmod +x asDocHelper

Cairngorm versus PureMVC, the most basic example application!

Friday, December 5th, 2008

Awhile back when I was learning to use the Cairngorm framework, Nicolas Lierman had a very basic example of a Cairngorm application. At the time I was trying to slog through the Cairngorm Store example, racking my brains trying to figure out what was going on. I didn’t need such a complex example to start from, just something extremely simple that would compile, and I could build from there. Looking at Nicolas’ example application was an ‘ah ha’ moment when it all came together in my mind. Now I have been learning the PureMVC framework and would like to resurrect a slightly modified version of that Cairngorm example (Nicolas’ used WebService, this uses HTTPService) side-by-side with the same example written in PureMVC. If you are trying to learn either of these frameworks, reference the Cairngorm Explorer and/or the PureMVC Conceptual Diagram and build on these examples. I hope they will help you as much as they helped me to learn the framework’s architecture.

Below is the example application written using the Cairngorm framework. Since the PureMVC example looks and functions exactly the same I will omit it. As you can see it is very simple. Type in your name and it sends it to the server and returns a message.

This movie requires Flash Player 9

The php backend is extremely simple:

<?php
	echo "Hello " . $_REQUEST['name'] . "!";
?>

Download Source Here (You will also need to download Cairngorm and PureMVC).