<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Activetuts+ &#187; Workflow</title>
	<atom:link href="http://active.tutsplus.com/category/tutorials/workflow/feed/" rel="self" type="application/rss+xml" />
	<link>http://active.tutsplus.com</link>
	<description>Flash, Flex &#38; ActionScript Tutorials</description>
	<lastBuildDate>Fri, 19 Mar 2010 19:32:08 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>The Comprehensive Guide to Preloading a Single SWF File</title>
		<link>http://active.tutsplus.com/tutorials/workflow/the-comprehensive-guide-to-preloading-a-single-swf-file/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/the-comprehensive-guide-to-preloading-a-single-swf-file/#comments</comments>
		<pubDate>Fri, 19 Mar 2010 12:00:25 +0000</pubDate>
		<dc:creator>Karl Macklin</dc:creator>
				<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://active.tutsplus.com/?p=3442</guid>
		<description><![CDATA[In this tutorial we&#8217;ll create a SWF that preloads itself, meaning that the preloader and the content is in the same file. We&#8217;ll go over how to do things the right way and avoid the traps.


Step 1: What is Single SWF Preloading?
The idea of single SWF preloading is that you have a Flash object which [...]]]></description>
			<content:encoded><![CDATA[<p>In this tutorial we&#8217;ll create a SWF that preloads itself, meaning that the preloader and the content is in the same file. We&#8217;ll go over how to do things the right way and avoid the traps.</p>
<p><span id="more-3442"></span></p>
<hr />
<h2><span>Step 1:</span> What is Single SWF Preloading?</h2>
<p>The idea of single SWF preloading is that you have a Flash object which preloads itself. That means that the preloader, with its associated functionality and assets, is embedded together in the same SWF file as the whole Flash movie or application.</p>
<p>We&#8217;ll start off this tutorial with some theory and finish it off with creating an FLA together with a preloader class that you can use in future projects. During the course of the tutorial we&#8217;ll discuss common pitfalls and important considerations. </p>
<p>Also, now that Activetuts+ has started focusing on document classes and generally keeping things in class files as much as possible, we&#8217;ll do just that in the practical part of this tutorial. Check out the <a href="http://active.tutsplus.com/tutorials/actionscript/quick-tip-how-to-use-a-document-class-in-flash/">Quick Tip: How to Use a Document Class in Flash</a> if you need to learn the basics.</p>
<p><strong>Make sure you have an updated version of either Flash CS3 or Flash CS4</strong>. I know for certain that a later CS4 update has changed the way classes are loaded and that can make all the difference here!</p>
<p>I&#8217;ll admit right away that this tutorial is quite lengthy for this narrow subject, but it contains all you need to know, so buckle up and let&#8217;s get to it!</p>
<hr />
<h2><span>Step 2:</span> Why Single SWF Preloading?</h2>
<p>The idea of a preloader is quite obvious: you want to make sure the user gets visual feedback indicating that the Flash object is loading. Embedding a large Flash file that takes 10 seconds to load could mean the difference between users staying or leaving the website, should it not be for the preloader telling the user to hold on.</p>
<p>The process of creating &quot;self preloading&quot; Flash files presents some issues and problems. There are other preloading techniques that are really easy to put together, such as one SWF file preloading another and adding it to the stage once loaded.</p>
<p> So why bother? Well, there are situations where you have no choice.</p>
<p> For example, you might want to create Flash games which you hope to spread to as many Flash gaming portals as possible. Most of these portals only support games in form of a single SWF file which leaves you with no choice but to make sure that your game preloads nicely from within itself.</p>
<p>Aside from such obvious examples, there&#8217;s the argument of having a completed product in only one file which makes for easy managing.</p>
<hr />
<h2><span>Step 3:</span> How SWF files are Loaded</h2>
<p>When your browser stumbles upon a Flash object and starts loading it, it starts from the beginning of the timeline. It loads the frames one after another. As soon as the first frame is loaded, it can be displayed.</p>
<p>Our approach here is to put a preloader on the first frame so the user sees something happening, while the browser continues to load the rest of the file. We write code to check the overall progress and when it&#8217;s completed we continue on to the main content of the file.</p>
<p>The challenge is to keep the size of the first frame to a minimum. If you let code and sounds pile up in the first frame you might have a preloader that&#8217;s not visible until after you&#8217;ve loaded maybe 60% of the movie.</p>
<p>A great tip when it comes to using a percentage counter that displays numbers is to use a font that is small in byte size. But this only takes you so far. Unfortunately we have to work quite a bit harder to have things our way!</p>
<p>It&#8217;s been said many times before and it&#8217;s worth saying again:</p>
<blockquote><p>Preloaders, the hardest of the simplest tasks in Flash..</p></blockquote>
<h2><span>Step 4:</span> The Defining Variables</h2>
<p>There are a number of things that will affect what will be put in which frame, such as:</p>
<ul>
<li>Where on the timeline you put assets.</li>
<li>Which frame you choose as the &#8220;class export frame&#8221; (see Step 11).</li>
<li>Whether you put assets before or after the class export frame. </li>
<li>In Flash CS4 &#8211; choosing whether or not to export the asset in the class export frame (in the symbol properties dialog).</li>
<li>In Flash CS3 &#8211; choosing whether or not to export the asset in first frame (in the symbol properties dialog).</li>
<li>Whether you use sounds.</li>
</ul>
<hr />
<h2><span>Step 5:</span> The Problems</h2>
<p>The main problem we face is <em>controlling what ends up on frame one</em>, because, as mentioned above, everything on frame one has to be loaded before the preloader can be displayed.</p>
<p>Other than that, there are differences between how Flash CS3 and CS4 work. In the next step I&#8217;ll make a number of thoroughly researched statements  that you can refer back to if need be. It should be a great resource if you quickly want to troubleshoot your preloading, to figure out why it&#8217;s not behaving the way you expect.</p>
<p>I&#8217;ll try to make the statements a bit more tangible by referring to TweenLite, a great tweening library by Jack Doyle over at <a href="http://www.greensock.com/">greensock.com</a>. We&#8217;ll be using TweenLite in the hands-on part of this tutorial so this will make the most sense.</p>
<hr />
<h2><span>Step 6:</span> The Statements</h2>
<p>These statements hold true for both Flash CS3 and CS4 unless stated otherwise. &quot;Importing TweenLite&quot; basically means &quot;importing and using TweenLite&quot; &#8211; the results may differ if you don&#8217;t actually use the code as the Flash compiler disregards unused imports. Simply typing an import statement does not equal using the code.</p>
<ul>
<li>If you import TweenLite on any frame in the main timeline, TweenLite will be loaded in the first frame of the movie.</li>
<li>If you have a MovieClip that imports TweenLite in its internal timeline and place this MovieClip<strong> after</strong> the class export frame, TweenLite will be loaded in the class export frame.</li>
<li>If you have a MovieClip that imports TweenLite in its internal timeline and place this MovieClip<strong> before</strong> the class export frame, TweenLite will be loaded in the first frame of the movie.</li>
</ul>
<p>The next three statements refer to the scenario where you have a MovieClip which is exported for ActionScript, using an external class file, which in turn imports TweenLite in the class file.</p>
<ul>
<li>Placing the MovieClip <em>after</em> the class export frame will make TweenLite load on the class export frame. There is no difference whether or not you check the &quot;Export in frame X&quot; (&quot;Export in first frame&quot; for CS3) regarding imported classes such as TweenLite. However, the checkbox affects whether or not the assets (shapes, bitmaps) of the MovieClip will be loaded in the export frame or not. In the case of CS3, you can of course only choose wheter or not to load it in the first frame.</li>
<li><strong>In Flash CS4</strong> placing the MovieClip <em>before</em> the class export frame will make TweenLite load on the first frame. There is no difference whether or not you check the &quot;Export in frame X&quot;. The non-code assets of the MovieClip will also load on the first frame.</li>
<li><strong>In Flash CS3</strong> if you place the MovieClip <em>before</em> the class export frame, then regardless of whether you&#8217;ve checked &quot;Export in first frame&quot;, you will get a <em>silent fail</em>! Meaning: the MovieClip you put on stage that should be using an external class file will just appear as a normal MovieClip, not giving you any indication whatsoever. You can still, however, affect whether the shape/bitmap contents of the MovieClip should be loaded in the first frame or not. This doesn&#8217;t really help though as you are equally screwed with the class loading.</li>
</ul>
<p>The next three statements refer to the scenario where you have a MovieClip that is exported for ActionScript as &quot;CustomClass&quot;, either using an external class file or not, which is instantiated and added to stage from a MovieClip that is placed on the timeline (just like the MovieClip from the previous three statements.) This CustomClass is <em>only</em> instantiated and does not previously exist on the main timeline.</p>
<ul>
<li><strong>In Flash CS4</strong> with the &quot;Export in frame X&quot; box checked, CustomClass is loaded in frame X and will display correctly. With the box unchecked it is still loaded in frame X and is displayed correctly.</li>
<li><strong>In Flash CS3</strong> with the &quot;Export in first frame&quot; box checked, CustomClass is loaded in the first frame and will display correctly. With the box unchecked you will get a 1046 Type error, as the class cannot be found.</li>
</ul>
<p>With all these restrictions, let&#8217;s at least consider this positive statement:</p>
<ul>
<li>If you place a MovieClip that only contains shapes/bitmaps, it will only load right before the frame it is needed. Unless you choose to export it earlier, that is!</li>
</ul>
<p>Here&#8217;s a really interesting one:</p>
<ul>
<li><strong>In Flash CS3</strong> you cannot export a sound on anything other than the first frame. <strong>In Flash CS4</strong> you can, on the class export frame.</li>
</ul>
<p>Yes, you read that right. I guess it&#8217;s fair to assume that Adobe wants people to upgrade to CS4. So what to do if you&#8217;re stuck with CS3 and the grass is greener on the other side? I&#8217;ll tell you in the next step.</p>
<hr />
<h2><span>Step 7:</span> Loading Assets in Flash CS3</h2>
<p>This whole step is just for those of you using Flash CS3.</p>
<p>If you read through all the statements in the previous step then you&#8217;ll realise the problem of having lots of MovieClips exported for ActionScript. These will all have to be loaded in frame one, or be unavailable. Luckily, those statements were under the assumption that those assets were never placed on the main timeline, which happens to be our solution! (This is also the only way to load sounds other than in frame one..)</p>
<p>This is how it&#8217;s done:</p>
<ol>
<li>Go into the properties of all the MovieClip/Sprite/Sound assets you want to export and uncheck &quot;Export in first frame&quot;.</li>
<li>In the second frame of the main timeline, create an empty MovieClip called AssetHolder.</li>
<li>In this AssetHolder MovieClip, create an actions layer that has a stop(); call on the first frame.</li>
<li>Still in the AssetHolder, create a layer for each sound you want to use and drag those sounds out to the second frame of its own layer. They <em>do not</em> need to be longer than one frame, luckily. For all other Sprites and MovieClips you can place these in a single layer or multiple for easier organizing. Put these on the second frame as well and leave the first frame empty.</li>
</ol>
<p>This will make all your assets load in the second frame. The solution is a bit tacky, but it&#8217;s not as rough as having to go and buy new software for this one particular issue.</p>
<p><em>(Kudos to <a href="http://www.8bitrocket.com/newsdisplay.aspx?newspage=10807">8bitrocket</a> for this trick!)</em></p>
<hr />
<h2><span>Step 8:</span> Bandwidth Profiler &amp; Size Report</h2>
<p>One thing I should mention before we start working is the bandwidth profiler. This is an essential tool in sorting out your preloading problems. When you preview a movie you can go up to view, then choose bandwidth profiler. Or just hit Ctrl+B.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step8a.jpg" alt="" /></div>
<p>Here you can switch between frame-by-frame graphs and streaming graphs. You can also simulate downloading the movie at a connection speed of your choice by either choosing it from the View menu or hitting Ctrl+Enter once again (change the simulated download speed using the View > Download Settings sub-menu). This is essential in finding out how your preloader will look, without going through the hassle of uploading it and capping your bandwidth. For that specific case though, I can recommend <a href="https://addons.mozilla.org/en-US/firefox/addon/5917">Firefox Throttle</a>.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step8b.jpg" alt="" /></div>
<p>Besides the very useful tool that is the bandwidth profiler there is the option to generate a size report. Hit Ctrl+Shift+F12 to open up the Publish Settings dialog box. </p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step8c.jpg" alt="" /></div>
<p>Go to the Flash tab, and in the Advanced section there is a checkbox labeled &quot;Generate size report&quot;. When this box is checked, previewing or publishing your movie will generate a text file in the same folder as your FLA file that contains useful information on what parts that make up the total size of the movie.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step8d.jpg" alt="" /></div>
<hr />
<h2><span>Step 9:</span> End of Theory</h2>
<p>Finally we can start making a Flash movie with a nice self-contained preloader!</p>
<p>We&#8217;ll be employing a &quot;three frame preloading&quot; technique. On the first frame we&#8217;ll put a preloader MovieClip that has its own class &quot;Preloader&quot;. On the second frame we load all the classes and on the third frame we load and display the content. We&#8217;ll put the content in a MovieClip named Application with an associated class &quot;Application&quot;. This is where the meat of the application goes.</p>
<hr />
<h2><span>Step 10:</span> Create New Document</h2>
<p>Start by creating a new AS3 document. I&#8217;m making it 600&#215;400px, dark gray background, 24 FPS. These settings don&#8217;t matter though.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step10.jpg" alt="" /></div>
<p>Set the document class to Main and hit OK.</p>
<hr />
<h2><span>Step 11:</span> Set the Class Export Frame</h2>
<p>Go to File > Publish Settings, the Flash tab, then the ActionScript 3.0 settings. Type in &#8220;frame 2&#8243; in the &quot;Export classes in frame&quot; field.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step11.jpg" alt="" /></div>
<hr />
<h2><span>Step 12:</span> Design a Preloader</h2>
<p>Obviously the design of a preloader won&#8217;t affect the function. I&#8217;ll give step by step instructions, but feel free to skip these parts and take your own approach if you so wish. Just make sure you note what parts I refer to in the code later on.</p>
<p>Draw a rectangle with rounded corners and give it a blue gradient. Then turn it into a MovieClip symbol, call it Preloader. Choose to export it for ActionScript and call the class Preloader.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step12a.jpg" alt="" /></div>
<p>Within this new MovieClip, draw a new rounded corner rectangle with a gray gradient, turn it into another MovieClip and give it an instance name of progressArea.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step12b.jpg" alt="" /></div>
<p>Go ahead and match up the layer layout I&#8217;ve got going on in the picture above. Next, make a duplicate of the last shape and place it in the Progress bar layer on top of the Progress area one. Give it a light blue gradient, turn it into a MovieClip and give it an instance name of progressBar. Enable guides for 9-slice scaling and make sure you keep the left and right round edges outside.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step12c.jpg" alt="" /></div>
<p>Lastly, make a dynamic text field with an instance name of percentageText. Make the text right-aligned. That way, the percentage sign will never move, only the numbers (which change anyway). Go into character embedding and make sure you embed numerals and the percentage sign (%). To make a really small preloader I&#8217;m using a small pixelfont called <a href="http://www.dafont.com/pixelmix.font">Pixel Mix from dafont.com</a>. I&#8217;m also giving it a blue glow just because I can.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step12d.jpg" alt="" /></div>
<hr />
<h2><span>Step 13:</span> Back to the Stage</h2>
<p>Make sure the whole preloader MovieClip is placed in the first frame and given an instance name of preloader. Create a new layer called &quot;AS&quot; and put a stop(); in the first frame. Keep the preloader in its own layer, &quot;Preloader&quot;. Make another layer called &quot;Application&quot;. This is where we will keep the main content in the end.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step13.jpg" alt="" /></div>
<hr />
<h2><span>Step 14:</span> Create the Main Class</h2>
<p>Create a new ActionScript file and save it in the same directory as your FLA file. Name it Main.as:</p>
<pre name="code" class="javascript">
package
{
	import flash.display.MovieClip;
	import flash.events.Event;

	public class Main extends MovieClip
	{
		public function Main()
		{
			preloader.addEventListener(Event.COMPLETE, onPreloaderComplete);
			preloader.setLoaderInfo(loaderInfo);
		}

		private function onPreloaderComplete(e:Event):void
		{
			gotoAndStop(3);
		}
	}
}</pre>
<hr />
<h2><span>Step 15:</span> Create the Preloader Class</h2>
<p>Create a new ActionScript file and save it in the same directory as Preloader.as:</p>
<pre name="code" class="javascript">
package
{
	import flash.display.LoaderInfo;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.ProgressEvent;

	public class Preloader extends MovieClip
	{
		public function Preloader()
		{
		}

		public function setLoaderInfo(ldrInf:LoaderInfo):void
		{
			ldrInf.addEventListener(ProgressEvent.PROGRESS, onProgress);
			ldrInf.addEventListener(Event.COMPLETE, onComplete);
		}

		private function onProgress(e:ProgressEvent):void
		{
			var percent:int = Math.round(e.bytesLoaded / e.bytesTotal * 100);
			progressBar.width = percent / 100 * progressArea.width;
			percentageText.text = percent + "%";
		}

		private function onComplete(e:Event):void
		{
			dispatchEvent(e);
		}
	}
}</pre>
<hr />
<h2><span>Step 16:</span> Grasping Main and Preloader</h2>
<p>So what do these two classes do?</p>
<p>In Main&#8217;s constructor, we call the custom setLoaderInfo() method of our preloader and pass along the LoaderInfo object that is associated with Main.</p>
<p>Preloader receives this object and adds two event listeners to it. The ProgressEvent triggers the onProgress function, in which we calculate the percentage of the bytes loaded compared to the total bytes to be loaded. The percentage is used to set the width of the progress bar and the text of our text field.</p>
<p>The complete event is simply dispatched back down to Main which in turn jumps the main timeline to frame three when receiving the event.</p>
<hr />
<h2><span>Step 17:</span> Adding Some Content</h2>
<p>To have something to clearly show the preloader working, I&#8217;m adding a nice macro photo of a cat called Runa taken by a friend of mine. You can find the image in the source files provided with this tutorial. I&#8217;ve imported the bitmap and I turn it into a MovieClip called &#8220;Cat&#8221;.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step17.jpg" alt="" /></div>
<p>Feel free to use whatever image you find suitable. Give the clip an instance name of &quot;cat&quot;.</p>
<hr />
<h2><span>Step 18:</span> Creating the Application MovieClip</h2>
<p>As you can see on the screenshot above I&#8217;ve placed the Cat MovieClip on frame three in the Application layer. Take whatever MovieClip you made, cat or no cat, and hit F8 once again to nest it inside a new MovieClip which you call Application. Export this for ActionScript as Application.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step18.jpg" alt="" /></div>
<hr />
<h2><span>Step 19:</span> The Application Class</h2>
<p>Create the Application class by starting a new AS file and saving it as &#8220;Application.as&#8221;. Have the Application class look like this:</p>
<pre name="code" class="javascript">
package
{
	import com.greensock.TweenLite;
	import com.greensock.easing.Sine;
	import flash.display.MovieClip;

	public class Application extends MovieClip
	{

		public function Application()
		{
			TweenLite.to(cat, 7, {
						 scaleX:4,
						 scaleY:4,
						 onComplete:tweenBack,
						 ease:Sine.easeInOut});
		}

		private function tweenBack():void
		{
			TweenLite.to(cat, 3, {
						 scaleX:1,
						 scaleY:1,
						 onComplete:reTween,
						 ease:Sine.easeInOut } );
		}
		private function reTween():void
		{
			TweenLite.to(cat, 7, {
						 scaleX:4,
						 scaleY:4,
						 onComplete:tweenBack,
						 ease:Sine.easeInOut } );
		}
	}
}</pre>
<p>This will animate the cat in and out indefinitely so you will forever remember the detail of her nose fur. How this class works isn&#8217;t important, what <em>is</em> important is that we&#8217;re importing TweenLite and using it, thereby making sure that it will be a part of the SWF file once exported.</p>
<hr />
<h2><span>Step 20:</span> CS3 and CS4 Issues</h2>
<p>Let&#8217;s go back to the school bench again for just a minute.</p>
<p>This movie compiles fine in CS4. The Application MovieClip is set to export on frame 2 unless you&#8217;ve changed it. If you&#8217;ve changed it you might notice something strange. More on this in the next step.</p>
<p>If you&#8217;re on CS3 this setting really matters. You&#8217;ll have to go and make sure you uncheck the &quot;Export in first frame&quot; checkbox in the Properties of the Application MovieClip, otherwise it will all load in the first frame!</p>
<p>That&#8217;s not the only problem. If you try to compile you will get a 1046 Type error, saying that you don&#8217;t have the type TextField available. So as you can guess, CS3 does things a bit different. What&#8217;s happening? Well, you are trying to use a TextField inside the Preloader MovieClip but you don&#8217;t have it imported. In CS4 this is handled automatically for you, but not in CS3.</p>
<p>Fortunately the solution is simple, just add:</p>
<pre name="code" class="javascript">
import flash.text.TextField;</pre>
<p>to your Preloader class, and you&#8217;re all set.</p>
<p>Some of you might have thought already that I should&#8217;ve extended Sprite for my Preloader class instead of MovieClip. Well, this is the reason I didn&#8217;t do that; I wanted to wait until this point to bring it up. Since the Preloader symbol contains both the &quot;ProgressArea&quot; and &quot;ProgressBar&quot;, which both are MovieClips, you would&#8217;ve gotten the same 1046 Type error.</p>
<p>The same solution is possible here too of course. In fact, you should now change the Preloader to extend Sprite instead of MovieClip, and if you&#8217;re using CS3 make sure you import the Sprite class inside the Preloader class as well.</p>
<hr />
<h2><span>Step 21:</span> Yet Another Issue</h2>
<p>I mentioned a strange occurrence in the last step. If you uncheck the &quot;Export in frame 2&quot; of Application and run a simulated download, you&#8217;ll see the preloader disappear, unless you&#8217;ve extended the preloader&#8217;s keyframe to cover the second frame as well.</p>
<p>So what&#8217;s really happening? Simply put, the first stop(); statement doesn&#8217;t count. How&#8217;s that for obvious work flow planning? Note that if you put a trace statement in the first frame after the stop(); call, it does trace out. <strong>Important:</strong> note that this problem only shows itself when we&#8217;re simulating download!</p>
<p>The lesson learned here is<strong> don&#8217;t trust the simulated download</strong>! It won&#8217;t show you accurately how things will load and function. You can just keep the stop(); and preloader in the first frame and you&#8217;ll be fine when it comes to deployment. However it can be a pain to preview unless you have Application set to export on frame 2. And that&#8217;s just for this specific scenario.</p>
<p>In CS3 you have to uncheck the export box on the Application MovieClip otherwise you&#8217;ll end up with it loading in the first frame. But if you do that, you&#8217;ll run into this issue. So go ahead and extend the preloader to the second frame.</p>
<hr />
<h2><span>Step 22:</span> Test the Movie</h2>
<p>Go ahead and preview the movie. Run a simulated download on a low speed and enjoy the masterfully* crafted preloader (*masterfully only applies if you&#8217;ve followed my instructions to the letter).</p>
<p>If you look at the frame-by-frame graph, or a generated size report, you&#8217;ll see that the code is loaded in the second frame. The first frame is only 4kb and consists of the Preloader class and the embedded font glyphs. Now, 4kb is quite affordable as far as wait time before seeing the preloader is concerned, don&#8217;t you think?</p>
<p>You might see different sizes on CS3 and you will definitely see different sizes with different fonts. Or cats.</p>
<hr />
<h2><span>Step 23:</span> Tweening the Preloader</h2>
<p>You might have the idea that you would like to use TweenLite to fade away the preloader by tweening the alpha to 0 &#8211; but you don&#8217;t want to load TweenLite in the first frame since that adds another 8kb to the initial download.</p>
<p>There are several ways to accomplish this and we will solve it by having a MovieClip on the third frame that catches the preloader and tweens it. When completed, it will advance to the fourth frame, which we&#8217;ll have moved Application to.</p>
<p>The reason for putting it in the third frame is that we can&#8217;t put it in the second frame without having TweenLite being loaded in the first frame.</p>
<p>Now we&#8217;re moving away from the standard three frame preloading technique.</p>
<hr />
<h2><span>Step 24:</span> Add a Layer and Stop(); Calls</h2>
<p>Add a new layer called &quot;Preloader catcher&quot;. Make sure you put stop(); calls on frames one, two and three. This is to prevent messed up previewing when simulating a download, as mentioned earlier.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step24.jpg" alt="" /></div>
<p>Go ahead and move Application to the fourth frame as well as extending Preloader to the third frame.</p>
<hr />
<h2><span>Step 25:</span> Create the Catcher</h2>
<p>Make sure you have a keyframe on the third frame of the Preloader catcher layer. Go to this frame, draw a small shape and have the alpha of the fill color set to 0%. This is supposed to be an invisible MovieClip. Turn it into a MovieClip symbol called PreloaderCatcher or something similar.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step25a.jpg" alt="" /></div>
<p>Export the MovieClip as PreloaderCatcher. If you&#8217;re using CS4 it doesn&#8217;t matter if you export it for frame 2 or not, since it will be loaded in that frame no matter what. Well, it does change one thing, remember? Whether or not the <em>shape</em> is loaded on frame 2. In essence it doesn&#8217;t matter considering the near non-existent file size for this shape. You might as well uncheck it for good habit though.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step25b.jpg" alt="" /></div>
<hr />
<h2><span>Step 26:</span> The PreloaderCatcher Class</h2>
<p>Make a new class file called PreloaderCatcher.as:</p>
<pre name="code" class="javascript">
package
{
	import com.greensock.TweenLite;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.Event;
	import Preloader;

	public class PreloaderCatcher extends Sprite
	{
		public function PreloaderCatcher()
		{
			addEventListener(Event.ADDED_TO_STAGE, onAdded);
		}

		private function onAdded(e:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, onAdded);

			var preloader:Sprite = MovieClip(parent).getChildByName("preloader") as Sprite;

			TweenLite.to(preloader, 0.5, {
										alpha:0,
										onComplete:function():void
											{
												MovieClip(parent).nextFrame();
											}
										} );
		}
	}</pre>
<p>As you can see, this class works by first obtaining the preloader by casting the parent as a Sprite and calling getChildByName(&quot;preloader&quot;), where preloader is the instance name. The preloader is cast a Sprite as well, then TweenLite is used to fade it out.</p>
<p>When the tweening is complete, the onComplete function in TweenLite casts the parent as a MovieClip so it&#8217;s possible to call the nextFrame method.</p>
<hr />
<h2><span>Step 27:</span> Why the Four Frames?</h2>
<p>As I said before, we&#8217;ve now moved away from the three frame preloading technique. That in itself isn&#8217;t exactly blasphemy, but I&#8217;m sure some of you wonder why we did that. Instead, we could&#8217;ve handled the preloader tweening inside the Application clip..</p>
<p>In that case, you are perfectly right! The reason I used four frames here was to show you how to do it while keeping things separated. Tweening away the preloader; does that belong to the preloader part, or the Application part? Preloader definitely, but in this case we didn&#8217;t want it to load in the first frame. Therefore, we end up with this extra &quot;catcher&quot; class.</p>
<p>Just remember that this is all optional. Once you know how to do everything you can easily decide whatever your situation requires.</p>
<hr />
<h2><span>Step 28:</span> Sounds and Extra Assets</h2>
<p>In Step 7 I told you about the asset loading problems in CS3. Since this tutorial is aimed towards both users of CS3 and CS4 we will go with the lowest common denominator and use the AssetHolder approach. If you&#8217;re using CS4 you can perform the next steps the same way and it will work just the same, or you can skip the AssetHolder approach.</p>
<p>Start by importing the &quot;music.wav&quot; sound from the source files into your FLA.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step28.jpg" alt="" /></div>
<p>Go in and export it for ActionScript and make sure you uncheck the &quot;Export in first frame&quot; box in CS3. For CS4 this won&#8217;t make much of a difference. I&#8217;m using Flash CS4 which you&#8217;ve probably figured out by now, so the screenshots show the CS4 dialog box. If you want to you can switch from the default MP3 compression to something more pleasing. That way it won&#8217;t sound terrible.</p>
<p>Let&#8217;s go through a couple more steps, adding some text to the movie and putting it all in an AssetHolder MovieClip!</p>
<hr />
<h2><span>Step 29:</span> Create Some Text</h2>
<p>Hit Ctrl+F8 to create a new MovieClip symbol. Name it TextHolder and export it for ActionScript, once again (in CS3) making sure the &quot;Export in first frame&quot; box is unchecked.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step29a.jpg" alt="" /></div>
<p>When creating, you will be &quot;inside&quot; this MovieClip. Type some static text and give it a white color. I&#8217;m using the same PixelMix font as before. To create a simulated stroke color, I give it a glow filter effect with the settings seen below.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step29b.jpg" alt="" /></div>
<hr />
<h2><span>Step 30:</span> Create the AssetHolder</h2>
<p>Create a new layer called AssetHolder. Make a keyframe on the second frame, hit Ctrl+F8 to create a new MovieClip and name it AssetHolder. Do not export this for ActionScript.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step30a.jpg" alt="" /></div>
<p>In the AssetHolder MovieClip, create three layers called AS, music and Assets. Since &#8220;music&#8221; is the name of the sound object we&#8217;re using, that&#8217;s what I&#8217;m naming the layer. Now you must put a stop(); call on the first frame of the AS layer.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step30b.jpg" alt="" /></div>
<p>Next, make a keyframe on the second frame of both the music and Assets layer. Drag the music sound onto the stage when you&#8217;re standing on the second keyframe in the music layer. Then do the same with the TextHolder MovieClip onto the Assets layer.</p>
<p>Exit out of the AssetHolder MovieClip and make sure you place it on the second keyframe of the AssetHolder layer on the main timeline. As you&#8217;ll notice, the MovieClip is not visible, but it is placable, which is quite cool!</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step30c.jpg" alt="" /></div>
<hr />
<h2><span>Step 31:</span> Changing the Application Class</h2>
<p>Alright, now we just want to make sure we play the sound and show the TextHolder MovieClip. Add this to the Application class&#8217;s constructor:</p>
<pre name="code" class="javascript">
var s:Music = new Music();
s.play();

var textHolder:TextHolder = new TextHolder();
textHolder.x = 120;
textHolder.y = 20;
addChild(textHolder);
</pre>
<hr />
<h2><span>Step 32:</span> Preview the Movie</h2>
<p>Go ahead and preview the movie. You should now, regardless of whether you&#8217;re on CS3 or CS4, be able to simulate a download of this movie and see it preload beautifully starting from 1 percent! Note that it isn&#8217;t starting at 0 percent. Had our contents been larger and the preloader smaller then that could have been possible.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step31a.jpg" alt="" /></div>
<p>Now, you might wonder why you&#8217;re staring at this orange cat paired with a short gameshow-esque music tag. This is normal to ask yourself.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/083_singleSWFPreloader/Tutorial/images/step31b.jpg" alt="" /></div>
<hr />
<h2>Conclusion</h2>
<p>Hopefully now you should have all the knowledge you need to preload things the way you want, in a single SWF file! To see the final version of all the class files just download the source files for this tutorial and check them out.</p>
<p>I&#8217;m unhealthily obsessed with this subject so I&#8217;ll gladly enter into discussion in the comments. Please join in if you have questions or ideas!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/the-comprehensive-guide-to-preloading-a-single-swf-file/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>Protect Your Flash Files From Decompilers by Using Encryption</title>
		<link>http://active.tutsplus.com/tutorials/workflow/protect-your-flash-files-from-decompilers-by-using-encryption/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/protect-your-flash-files-from-decompilers-by-using-encryption/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 12:00:22 +0000</pubDate>
		<dc:creator>Nikita Leshenko</dc:creator>
				<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://active.tutsplus.com/?p=3115</guid>
		<description><![CDATA[<img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/preview.jpg" alt="Protect Your Flash Files From Decompilers by Using Encryption">]]></description>
			<content:encoded><![CDATA[<p>Decompilers are a real worry for people who create Flash content. You can put a lot of effort into creating the best game out there, then someone can steal it, replace the logo and put it on their site without asking you. How? Using a Flash Decompiler. Unless you put some protection over your SWF it can be decompiled with a push of a button and the decompiler will output readable source code.</p>
<p>In this tutorial I will demonstrate a technique I use to protect code and assets from theft.</p>
<p><span id="more-3115"></span></p>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/VerletCloth.zip" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/source.jpg" alt="" style="border:none"></a><br />
<a href="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/swf/final.html" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/demo.jpg" alt="" style="border:none"></a>
</div>
<p><strong>Editor&#8217;s Note:</strong> Thanks to <a href="http://psd.tutsplus.com/author/vaclav/" target="_blank">Vaclav</a> for use of his lock icon. Visit <a href="http://psd.tutsplus.com/tutorials/designing-tutorials/create-a-shiny-lock-icon-design/" target="_blank">Psdtuts+</a> to see how he made it..</p>
<h2>Before We Begin</h2>
<p>I used a small project of mine to demonstrate how vulnerable SWFs are to decompilation. You can download it and test yourself via the source link above. I used <a href="http://www.sothink.com/product/flashdecompiler/index.htm" target="_blank">Sothink SWF Decompiler 5</a> to decompile the SWF and look under its hood. The code is quite readable and you can understand and reuse it fairly easily.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/1.png"/></div>
<h2>What Can We do About it?</h2>
<p>I came up with a technique for protecting SWFs from decompilers and I&#8217;m going to demonstrate it in this tutorial. We should be able to produce this:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/2.png"/></div>
<p>The code that is decompiled is actually the code for decrypting the content and has nothing to do with your main code. Additionally, the names are illegal so it won&#8217;t compile back. Try to <a href="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/swf/final.html">decompile it yourself</a>.</p>
<p>Before we get going, I want to point out that this tutorial is not suitable for beginners and you should have solid knowledge of AS3 if you want to follow along. This tutorial is also about low level programming that involves bytes, ByteArrays and manipulating SWF files with a hex editor.</p>
<p>Here&#8217;s what we need:</p>
<ul>
<li><strong>A SWF to protect.</strong> Feel free to download <a href="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/VerletCloth.zip">the SWF I&#8217;ll be working on</a>.</li>
<li><strong>Flex SDK.</strong> We will be using it to embed content using the Embed tag. You can download it from <a href="http://opensource.adobe.com/wiki/display/flexsdk/Download+Flex+3">opensource.adobe.com</a>.</li>
<li><strong>A hex editor.</strong> I&#8217;ll be using a free editor called Hex-Ed. You can download it from <a href="http://www.nielshorn.net/prog/old/hexed/">nielshorn.net</a> or you can use an editor of your choice.</li>
<li><strong>A decompiler.</strong> Whilst not necessary, it would be nice to check if our protection actually works. You can grab a trial of Sothink SWF Decompiler from <a href="http://www.sothink.com/product/flashdecompiler/index.htm" target="_blank">sothink.com</a></li>
</ul>
<h2>Step 1: Load SWF at Runtime</h2>
<p>Open a new ActionScript 3.0 project, and set it to compile with Flex SDK (I use FlashDevelop to write code). Choose a SWF you want to protect and embed it as binary data using the Embed tag:
<pre name="code" class="javascript">
[Embed (source = "VerletCloth.swf", mimeType = "application/octet-stream")]
// source = path to the swf you want to protect
private var content:Class;
</pre>
<p>Now the SWF is embedded as a <em>ByteArray</em> into the loader SWF and it can be loaded through <em>Loader.loadBytes()</em>.</p>
<pre name="code" class="javascript">
var loader:Loader = new Loader();
addChild(loader);
loader.loadBytes(new content(), new LoaderContext(false, new ApplicationDomain()));
</pre>
<p>In the end we should have this code:</p>
<pre name="code" class="javascript">
package
{
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.system.ApplicationDomain;
    import flash.system.LoaderContext;

    [SWF (width = 640, height = 423)] //the dimensions should be same as the loaded swf's
    public class Main extends Sprite
    {
        [Embed (source = "VerletCloth.swf", mimeType = "application/octet-stream")]
        // source = path to the swf you want to protect
        private var content:Class;

        public function Main():void
        {
            var loader:Loader = new Loader();
            addChild(loader);
            loader.loadBytes(new content(), new LoaderContext(false, new ApplicationDomain()));
        }
    }

}
</pre>
<p>Compile and see if it works (it should). From now on I will call the embedded SWF the &#8220;protected SWF&#8221;, and the SWF we just compiled the &#8220;loading SWF&#8221;.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/3.png" width="600"/></div>
<h2>Step 2: Analyze the Result</h2>
<p>Let&#8217;s try to decompile and see if it works.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/4.png"/></div>
<p>Yey! The assets and the original code are gone! What&#8217;s shown now is the code that loads the protected SWF and not its content. This would probably stop most of the first-time attackers who are not too familiar with Flash but it&#8217;s still not good enough to protect your work from skilled attackers because the protected SWF is waiting for them untouched inside the loading SWF.</p>
<h2>Step 3: Decompressing the SWF</h2>
<p>Let&#8217;s open the loading SWF with a hex editor:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/5.png"/></div>
<p>It should look like random binary data because it&#8217;s compressed and it should begin with ASCII &#8220;CWS&#8221;. We need to decompress it! (If your SWF begins with &#8220;FWS&#8221; and you see meaningful strings in the SWF it&#8217;s likely that it didn&#8217;t get compressed. You have to enable compression to follow along).</p>
<p>At first it might sound difficult but it&#8217;s not. The SWF format is an open format and there is a document that describes it. Download it from <a href="http://www.adobe.com/devnet/swf/pdf/swf_file_format_spec_v10.pdf">adobe.com</a> and scroll down to page 25 in the document. There is a description of the header and how the SWF is compressed, so we can uncompress it easily.</p>
<p>What is written there is that the first 3 bytes are a signature (CWS or FWS), the next byte is the Flash version, the next 4 bytes are the size of the SWF. The remaining is compressed if the signature is CWS or uncompressed if the signature is FWS. Let&#8217;s write a simple function to decompress a SWF:</p>
<pre name="code" class="javascript">
private function decompress(data:ByteArray):ByteArray
{
    var header:ByteArray = new ByteArray();
    var compressed:ByteArray = new ByteArray();
    var decompressed:ByteArray = new ByteArray();

    header.writeBytes(data, 3, 5); //read the uncompressed header, excluding the signature
    compressed.writeBytes(data, 8); //read the rest, compressed

    compressed.uncompress();

    decompressed.writeMultiByte("FWS", "us-ascii"); //mark as uncompressed
    decompressed.writeBytes(header); //write the header back
    decompressed.writeBytes(compressed); //write the now uncompressed content

    return decompressed;
}
</pre>
<p>The function does a few things:</p>
<ol>
<li>It reads the uncompressed header (the first 8 bytes) without the signature and remembers it.</li>
<li>It reads the rest of the data and uncompresses it.</li>
<li>It writes back the header (with the &#8220;FWS&#8221; signature) and the uncompressed data, creating a new, uncompressed SWF.</li>
</ol>
<h2>Step 4: Creating a Utility</h2>
<p>Next we&#8217;ll create a handy utility in Flash for compressing and decompressing SWF files. In a new AS3 project, compile the following class as a document class:</p>
<pre name="code" class="javascript">
package
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.net.FileFilter;
    import flash.net.FileReference;
    import flash.utils.ByteArray;

    public class Compressor extends Sprite
    {
        private var ref:FileReference;

        public function Compressor()
        {
            ref = new FileReference();
            ref.addEventListener(Event.SELECT, load);
            ref.browse([new FileFilter("SWF Files", "*.swf")]);
        }

        private function load(e:Event):void
        {
            ref.addEventListener(Event.COMPLETE, processSWF);
            ref.load();
        }

        private function processSWF(e:Event):void
        {
            var swf:ByteArray;
            switch(ref.data.readMultiByte(3, "us-ascii"))
            {
                case "CWS":
                    swf = decompress(ref.data);
                    break;
                case "FWS":
                    swf = compress(ref.data);
                    break;
                default:
                    throw Error("Not SWF...");
                    break;
            }

            new FileReference().save(swf);
        }

        private function compress(data:ByteArray):ByteArray
       {
            var header:ByteArray = new ByteArray();
            var decompressed:ByteArray = new ByteArray();
            var compressed:ByteArray = new ByteArray();

            header.writeBytes(data, 3, 5); //read the header, excluding the signature
            decompressed.writeBytes(data, 8); //read the rest

            decompressed.compress();

            compressed.writeMultiByte("CWS", "us-ascii"); //mark as compressed
            compressed.writeBytes(header);
            compressed.writeBytes(decompressed);

            return compressed;
        }

        private function decompress(data:ByteArray):ByteArray
        {
            var header:ByteArray = new ByteArray();
            var compressed:ByteArray = new ByteArray();
            var decompressed:ByteArray = new ByteArray();

            header.writeBytes(data, 3, 5); //read the uncompressed header, excluding the signature
            compressed.writeBytes(data, 8); //read the rest, compressed

            compressed.uncompress();

            decompressed.writeMultiByte("FWS", "us-ascii"); //mark as uncompressed
            decompressed.writeBytes(header); //write the header back
            decompressed.writeBytes(compressed); //write the now uncompressed content

            return decompressed;
        }

    }

}
</pre>
<p>As you probably noticed I&#8217;ve added 2 things: File loading and the compress function.</p>
<p>The compress function is identical to the decompress function, but in reverse. The file loading is done using FileReference (FP10 required) and the loaded file is either compressed or uncompressed. Note that you have to run the SWF locally from a standalone player, as <em>FileReference.browse()</em> must be invoked by user interaction (but the local standalone player allows to run it without).</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/6.png"/></div>
<h2>Step 5: Uncompressing the Loading SWF</h2>
<p>To test the tool, fire it up, select the loading SWF and choose where to save it. Then open it up with a hex editor and scrub through. You should see ascii strings inside like this:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/7.png"/></div>
<h2>Step 6: Analyze Again</h2>
<p>Let&#8217;s return back to step 2. While the decompiler didn&#8217;t show any useful info about the protected SWF, it&#8217;s quite easy to get the SWF from the now uncompressed loader; just search for the signature &#8220;CWS&#8221; (if the protected SWF is uncompressed search for &#8220;FWS&#8221;) and see the results:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/8.png"/></div>
<p>What we found is a DefineBinaryData tag that contains the protected SWF, and extracting it from there is a piece of cake. We are about to add another layer of protection over the loading SWF : Encryption.</p>
<h2>Step 7: Encryption</h2>
<p>To make the protected SWF less &#8220;accessible&#8221; we will add some kind of encryption. I chose to use as3crypto and you can download it from<a href="http://code.google.com/p/as3crypto/" target="_blank"> code.google.com</a>. You can use any library you want instead (or your own implementation, even better), the only requirement is that it should be able to encrypt and decrypt binary data using a key.</p>
<h2>Step 8: Encrypting Data</h2>
<p>The first thing we want to do is write a utility to encrypt the protected SWF before we embed it. It requires very basic knowledge of the as3crypto library and it&#8217;s pretty straightforward. Add the library into your library path and let&#8217;s begin by writing the following:</p>
<pre name="code" class="javascript">
var aes:AESKey = new AESKey(binKey);
var bytesToEncrypt:int = (data.length &#038; ~15); //make sure that it can be devided by 16, zero the last 4 bytes
for (var i:int = 0; i &lt; bytesToEncrypt; i += 16)
        aes.encrypt(data, i);
</pre>
<p>What&#8217;s going on here? We use a class from as3crypto called AESKey to encrypt the content. The class encrypts 16 bytes in a time (128-bit), and we have to for-loop over the data to encrypt it all. Note the second line : data.length &#038; ~15. It makes sure that the number of bytes encrypted can be divided by 16 and we don&#8217;t run out of data when calling <em>aes.encrypt()</em>.</p>
<p><strong>Note:</strong> It&#8217;s important to understand the point of encryption in this case. It&#8217;s not really encryption, but rather obfuscation since we include the key inside the SWF. The purpose is to turn the data into binary rubbish, and the code above does it&#8217;s job, although it can leave up to 15 unencrypted bytes (which doesn&#8217;t matter in our case). I&#8217;m not a cryptographer, and I&#8217;m quite sure that the above code could look lame and weak from a cryptographer&#8217;s perspective, but as I said it&#8217;s quite irrelevant as we include the key inside the SWF.</p>
<h2>Step 9: Encryption Utility</h2>
<p>Time to create another utility that will help us encrypt SWF files. It&#8217;s almost the same as the compressor we created earlier, so I won&#8217;t talk much about it. Compile it in a new project as a document class:</p>
<pre name="code" class="javascript">
package
{
    import com.hurlant.crypto.symmetric.AESKey;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.net.FileReference;
    import flash.utils.ByteArray;

    public class Encryptor extends Sprite
    {
        private var key:String = "activetuts"; //I hardcoded the key
        private var ref:FileReference;

        public function Encryptor()
        {
            ref = new FileReference();
            ref.addEventListener(Event.SELECT, load);
            ref.browse();
        }

        private function load(e:Event):void
        {
            ref.addEventListener(Event.COMPLETE, encrypt);
            ref.load();
        }

        private function encrypt(e:Event):void
        {
            var data:ByteArray = ref.data;

            var binKey:ByteArray = new ByteArray();
            binKey.writeUTF(key); //AESKey requires binary key

            var aes:AESKey = new AESKey(binKey);
            var bytesToEncrypt:int = (data.length &#038; ~15); //make sure that it can be divided by 16, zero the last 4 bytes
            for (var i:int = 0; i &lt; bytesToEncrypt; i += 16)
                aes.encrypt(data, i);

            new FileReference().save(data);
        }

    }

}
</pre>
<p>Now run it, and make an encrypted copy of the protected SWF by selecting it first and then saving it under a different name.</p>
<h2>Step 10: Modifying the Loader</h2>
<p>Return back to the loading SWF project. Because the content is now encrypted we need to modify the loading SWF and add decryption code into it. Don&#8217;t forget to change the src in the Embed tag to point to the encrypted SWF.</p>
<pre name="code" class="javascript">
package
{
    import com.hurlant.crypto.symmetric.AESKey;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.system.ApplicationDomain;
    import flash.system.LoaderContext;
    import flash.utils.ByteArray;

    [SWF (width = 640, height = 423)] //the dimensions should be same as the loaded swf's
    public class Main extends Sprite
    {
        [Embed (source = "VerletClothEn.swf", mimeType = "application/octet-stream")]
        // source = path to the swf you want to protect
        private var content:Class;

        private var key:String = "activetuts";

        public function Main():void
        {
            var data:ByteArray = new content();

            var binKey:ByteArray = new ByteArray();
            binKey.writeUTF(key); //AESKey requires binary key

            var aes:AESKey = new AESKey(binKey);
            var bytesToDecrypt:int = (data.length &#038; ~15); //make sure that it can be divided by 16, zero the last 4 bytes
            for (var i:int = 0; i &lt; bytesToDecrypt; i += 16)
                aes.decrypt(data, i);

            var loader:Loader = new Loader();
            addChild(loader);
            loader.loadBytes(data, new LoaderContext(false, new ApplicationDomain()));
        }
    }

}
</pre>
<p>This is the same as before except with the decryption code stuck in the middle. Now compile the loading SWF and test if it works. If you followed carefully up to now, the protected SWF should load and display without errors.</p>
<h2>Step 11: Look Inside Using a Decompiler</h2>
<p>Open the new loading SWF with a decompiler and have a look.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/9.png"/></div>
<p>It contains over a thousand lines of tough looking encryption code, and it&#8217;s probably harder to get the protected SWF out of it. We&#8217;ve added a few more steps the attacker must undertake:</p>
<ol>
<li>He (or she) has to find the DefineBinaryData that holds the encrypted content and extract it.</li>
<li>He must create a utility to decrypt it.</li>
</ol>
<p>The problem is that creating a utility is as simple as copy-pasting from the decompiler into the code editor and tweaking the code a little bit. I tried to break my protection myself, and it was quite easy &#8211; I managed to do it in about 5 minutes. So we&#8217;re going to have to take some measurements against it.</p>
<h2>Step 12: String Obfuscation</h2>
<p>First we&#8217;d put the protected SWF into the loading SWF, then encrypted it, and now we&#8217;ll put the final touches to the loading SWF. We&#8217;ll rename classes, functions and variables to illegal names.</p>
<p>By saying <em>illegal names</em> I mean names such as ,;!@@,^#^ and (^_^). The cool thing is that this matters to the compiler but not to the Flash Player. When the compiler encounters illegal characters inside identifiers, it fails to parse them and thus the project fails to compile. On the other hand, the Player doesn&#8217;t have any problems with those illegal names. We can compile the SWF with legal identifiers, decompress it and rename them to a bunch of meaningless illegal symbols. The decompiler will output illegal code and the attacker will have to go over the hundreds of lines of code manually, removing illegal identifiers before he can compile it. He deserves it!</p>
<p>This is how it looks before any string obfuscation:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/10.png"/></div>
<p>Let&#8217;s start! Decompress the loading SWF using the utility we created before and fire up a hex editor.</p>
<h2>Step 13: Your First Obfuscation</h2>
<p>Let&#8217;s try to rename the document class. Assuming you&#8217;ve left the original name (Main), let&#8217;s search for it in the uncompressed loader SWF with a hex editor:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/11.png"/></div>
<p>Rename &#8220;<em>Main</em>&#8221; to <em>;;;;</em>. Now search for other &#8220;Main&#8221;s and rename them to <em>;;;;</em> too.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/12.png"/></div>
<p>When renaming make sure that you don&#8217;t rename unnecessary strings or the SWF will not run.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/13.png"/></div>
<p>Save and run the SWF. It works! And look what the decompiler says:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/14.png"/></div>
<p>Victory!! <img src='http://active.tutsplus.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<h2>Step 14: Renaming the Rest of the Classes</h2>
<p>Keep renaming the rest of your classes. Choose a class name and search for it, replacing it with illegal symbols until you reach the end of the file. As I said, the most important thing here is to use your common sense, make sure you don&#8217;t mess your SWF up. After renaming the classes you can start renaming the packages. Note that when renaming a package, you can erase the periods too and make it one long illegal package name. Look what I made:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/15.png"/></div>
<p>After you finish renaming the classes and the packages, you can start renaming functions and variables. They are even easier to rename as they usually appear only once, in one large cloud. Again, make sure you rename only &#8220;your&#8221; methods and not the built-in Flash methods. Make sure you don&#8217;t wipe out the key (&#8220;activetuts&#8221; in our case).</p>
<h2>Step 15: Compress the SWF</h2>
<p>After you finish renaming you would probably want to compress the SWF so it will be smaller in size. No problem, we can use the compressing utility we created before and it will do the job. Run the utility, select the SWF and save it under another name.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/067_swfEncryption/images/16.png"/></div>
<h2>Conclusion: Have a Final Look</h2>
<p>Open it one last time and have a look. The classes, the variables and the method names are obfuscated and the protected SWF is somewhere inside, encrypted. This technique could be slow to apply at first, but after a few times it takes only a few minutes.</p>
<p>A while ago I created an automatic utility to inject the protected SWF for me into the loading SWF, and it worked fine. The only problem is that if it can be injected using an automatic utility, it can be decrypted using another utility, so if the attacker makes a utility for that he will get all your SWF easily. Because of this I prefer to protect the SWFs manually each time, adding a slight modification so it would be harder to automate.</p>
<p>Another nice application of the technique is <em>Domain locking</em>. Instead of decrypting the SWF with a constant string you can decrypt it with the domain the SWF is currently running on. So instead of having an if statement to check the domain, you can introduce a more powerful way to protect the SWF from placement on other sites.</p>
<p>Last thing, you may want to replace the encryption code with your own implementation. Why? We invested efforts in making the crypto code illegal, but the code we use is from a popular open source library and the attacker could recognize it as such. He will download a clean copy, and all the obfuscation work is rendered unnecessary. On the other hand, using your own implementation will require him to fix all the illegal names before he can continue.</p>
<h2>Other Protection Methods</h2>
<p>Because SWF theft is a big problem in the Flash world, there are other options for protecting SWFs. There are numerous programs out there to obfuscate AS on the bytecode level (like Kindisoft&#8217;s secureSWF). They mess up the compiled bytecode and when the decompiler attempts to output code it will fail, and even crash sometimes. Of course this protection is better in terms of security but it costs $$$, so before choosing how to protect your SWF consider the amount of security needed. If it&#8217;s about protecting a proprietary algorithm your 50-employee Flash studio has been developing for the past two years, you may consider something better then renaming the variables. On the other hand if you want to prevent the kiddies from submitting false high scores you may consider using this technique.</p>
<p>What I like about this technique is the fact that your protected SWF is left untouched when run. AS obfuscation tampers with the byte code and it could possibly damage the SWF and cause bugs (although I haven&#8217;t encountered any myself).</p>
<p>That&#8217;s all for today, hope you enjoyed the tutorial and learned something new! If you have any questions feel free to drop a comment.</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/protect-your-flash-files-from-decompilers-by-using-encryption/feed/</wfw:commentRss>
		<slash:comments>43</slash:comments>
		</item>
		<item>
		<title>Quick Tip: How to Organize Your Flash Project Files</title>
		<link>http://active.tutsplus.com/tutorials/screencasts/quick-tip-how-to-organize-your-flash-project-files/</link>
		<comments>http://active.tutsplus.com/tutorials/screencasts/quick-tip-how-to-organize-your-flash-project-files/#comments</comments>
		<pubDate>Thu, 04 Feb 2010 12:00:24 +0000</pubDate>
		<dc:creator>Daniel Apt</dc:creator>
				<category><![CDATA[Screencasts]]></category>
		<category><![CDATA[Workflow]]></category>
		<category><![CDATA[Tips]]></category>

		<guid isPermaLink="false">http://active.tutsplus.com/?p=3101</guid>
		<description><![CDATA[<img src="http://activetuts.s3.cdn.plus.org/tuts/057_QTFileSetup/preview.jpg" alt="Quick Tip: How to Organize Your Flash Project Files">]]></description>
			<content:encoded><![CDATA[<p>There are two good reasons for keeping your Flash project organized: first, it makes it easier to package up your output files for deployment; second, it stops coders and designers getting in each other&#8217;s way!</p>
<p>In this Quick Tip screencast, Daniel Apt demonstrates how to set up your project&#8217;s folders, and shows three standard ways of doing so.</p>
<p><span id="more-3101"></span></p>
<h3>View Screencast</h3>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/057_QTFileSetup/organized.flv" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/screen.jpg" alt="" style="border:none"></a>
</div>
<p>

<div class="tutorial_image">
		<div id="player10"><a href="http://get.adobe.com/flashplayer/">Get the Flash Player</a> to see this player.</div>
		<script type="text/javascript">
		var so = new SWFObject('http://active.tutsplus.com/wp-content/plugins/flash-player/player.swf','player10','600','385','9');
		so.addParam('allowscriptaccess','always');
		so.addParam('allowfullscreen','true');
		so.addParam('flashvars','&file=http://activetuts.s3.cdn.plus.org/tuts/057_QTFileSetup/organized.flv&bufferlength=1&skin=http://active.tutsplus.com/wp-content/plugins/flash-player/silver.swf&fullscreen=true');
		so.write('player10');
		</script>
		</div>

</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/screencasts/quick-tip-how-to-organize-your-flash-project-files/feed/</wfw:commentRss>
		<slash:comments>23</slash:comments>
		</item>
		<item>
		<title>R.I.P. .fla</title>
		<link>http://active.tutsplus.com/tutorials/workflow/r-i-p-fla/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/r-i-p-fla/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 12:00:31 +0000</pubDate>
		<dc:creator>Tom Green</dc:creator>
				<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://active.tutsplus.com/?p=3064</guid>
		<description><![CDATA[<img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/thumb.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>Just before Adobe announced that there was to be no Flash CS5 Public Beta, Lee Brimelow, a Flash Platform Evangelist at Adobe, released a Sneak Peek of Flash CS5 on his site<a href="http://www.gotoandlearn.com/play?id=11"> gotoandlearn.com</a>. In the overview Lee spends some time talking about the fact that the .fla format is about to become extinct and replaced with a new one named “XFL”. What you may not know is that this format had already found its way into the CS4 studio.</p>
<p>In this article, I&#8217;m going to give you a chance to see what all the chatter is about and to prepare yourselves for the slow disappearance of the .fla format.</p>
<p><span id="more-3064"></span></p>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Exercise.zip" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/source.jpg" alt="" style="border:none"></a>
</div>
<p><strong>Note:</strong> I have included all the files for this example. If you don’t have After Effects don’t dial out. You can still work along because I have also included the XFL file created by After Effects CS4.</p>
<h2>Introduction</h2>
<p>Richard Galvan, the Flash Products Manager, and I have a most interesting relationship. We both highly respect what the other is doing but to call us great friends would be stretching the term. What Richard does know is that he can bounce ideas off of me and that they will go no further until the idea comes to life. For me, this is great because I can start thinking of ways to let you know what’s up when it happens.</p>
<p>In the case of the XFL format, I first heard about it, prior to the CS4 release, on a rainy street corner in Toronto when Richard and I were in a line waiting for entry into an FITC event. “What would you say,Tom”, asked Richard, “if I were to tell you we are thinking of getting rid of the .fla format?” </p>
<p>This one caught me by surprise but, as Richard walked me through the reasoning behind their thinking it became rather clear that this was a great idea.</p>
<p>In fact it wasn’t ,for me, a complete surprise. The rise of XML over the past few years has given Flash developers the luxury of working with Flash content that is external to the .swf. At the same time using XML with Flash had moved into the realm of “easy to accomplish” from the nightmare it had been. All of this is good but there was a major issue: Flash stored documents in a binary source file, the .fla, which was a proprietary specification. XFL is Adobe’s response to this issue.</p>
<h2>Creating an XFL Document</h2>
<p>Contrary to what you may have heard Flash can’t create an XFL document. It can only read them. At the moment there are in fact only two applications in the Adobe lineup that can create these docs: After Effects CS4 and InDesign CS4. Here’s how an XFL document is created in After Effects:</p>
<h2>Step 1: AET.aep </h2>
<p>Open the AET.aep file in After Effects CS4. It is a simple animation of the letters in the Activetuts+ name Raining In and Raining out.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/1.jpg" width="600" height="356" /></div>
<p>I have used this effect in a couple of XFL demos I have done, not because I am lazy but because the focus here is technique not design. In this case notice the two layers named active tuts + In and active tuts + Out. The other feature to be aware of is that the Comp i’s dimensions are  400 X 100 and the frame rate is 24 frames per second.</p>
<h2>Step2: Export</h2>
<p>Select File&gt;Export&gt; Adobe Flash Professional (XFL)&#8230; which will open the XFL Settings dialog box.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/2.jpg" width="511" height="177" /></div>
<h2>Step 3: Format</h2>
<p>Select PNG Sequence from the Format drop down menu.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/3.jpg" width="412" height="321" /></div>
<p>Your two choices  in the Dialog Box section may seem a bit odd. Here’s what they do:</p>
<ul>
<li><strong>Rasterize to:</strong> You need to decided whether the output will be rasterized to a series of PNG images or an FLV. The PNG choice may strike many of you as being one to be avoided at all costs. Exporting a series of images and then sticking them in the Flash movie is, to say the least, a tad heretical. Not quite. If you select this option, frames that are identical and adjacent to each other are rasterized  only once to a single  PNG. That PNG is then referenced several times in the XFL document. Use the FLV option if a layer contains video. Clicking the Format Options button launches the FLV/F4V export settings.</li>
<li><strong>Ignore: </strong>Select this to tell After Effects to ignore layers containing unsupported features such as blending modes other than Normal. Choose this and those layers won’t be added to the XFL document.</li>
</ul>
<h2>Step 4: OK</h2>
<p>Click OK to close the dialog box and get the process underway. </p>
<p>You will be prompted to choose a location for the XFL file and to give it a name (I used AETuts). When you click the Save button the dialog box disappears. You can quit After Effects and open the folder where you placed the XFL document. Inside you will see the .aep file and the XFL file as well as a report of the process. Create a new folder and place a copy of the XFL file into it. We&#8217;ll be using the copy in a moment.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/4.jpg" width="350" height="96" /></div>
<h2>Step 5: Open the XFL File </h2>
<p>Launch Flash and, when it opens, use File&gt;Open to navigate to the XFL file. Open it. A progress bar will appear.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/5.jpg" width="375" height="89" /></div>
<h2>Step 6: Examine the Flash File</h2>
<p>When the file opens notice how the layers order is preserved, the animations are placed on Motion layers and that the file opens as an Untitled Flash file. Another very subtle change is that the Scene 1 link has been renamed Comp 1. This is the name of the item in After Effects. </p>
<p>Why does the XFL document open as an Untitled Flash document? The reason is because this document is contstructed from  the information contained in the XFL document and new documents in Flash always open as Untitled.</p>
<p>So what does all this “information” I have been chattering about look like? Let’s find out. </p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/6.jpg" width="600" height="208" /></div>
<h2>Step 7: Change the Extension </h2>
<p>Quit Flash, navigate to the folder holding the copy of the XFL file and change the XFL file extension to .zip. The icon will change to a .zip file icon. The key aspect of the XFL format, if you pay close attention to what Adobe is saying, is that it is a container format. In fact they are very clear that you should regard an XFL file as a zip file.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/7.jpg" width="136" height="126" /></div>
<h2>Step 8: Uncompress the .zip File</h2>
<p>Using the application you use to open .zip files (I use BetterZip on my Mac) open the .zip file. When it opens you will see that your XFL file contains a lot more than you expected. Move the Library folder and the DOMDocument files to your open folder.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/8.jpg" width="570" height="439" /></div>
<h2>Step 9: Open the Library Folder.</h2>
<p>The structure of this folder is how the Flash Library is created. The only difference between the two is that the contents of the folders are placed into movieclips when the file is constructed.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/9.jpg" width="600" height="395" /></div>
<h2>Step 10: Open the DOMDocument.xml File</h2>
<p>I am not going to get deep into this document but you can see that each element that makes up the animations from the folders  is between the &lt;media&gt; &lt;/media&gt; tags and how the movieclips with animation are constructed as well.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/056_XFL/Images/10.jpg" width="600" height="404" /></div>
<h2>Conclusion:</h2>
<p>The implication of the new format is quite staggering when you really think about it. For example, nothing says you can’t edit one of the images in the Library folder in Photoshop or Fireworks and not have any effect whatsoever on on the Flash timeline. Another is, once this format takes hold, it won’t be odd to see Flash movies authored using XML and Flash being used primarily for the final .swf export.</p>
<p>I am going to leave the final word on this to the master, Colin Moock. When he learned about this change in CS4 he wrote in his<a href="http://www.moock.org/blog/archives/000269.html"> blog</a>: </p>
<blockquote><p>The natural next step in the evolution of XFL authoring would be to take the Flash authoring tool out of the equation altogether. If Adobe were to offer a command-line XFL-to-SWF compiler along with XFL, nearly any decent programmer would be able to create a .swf-authoring tool, even in ActionScript. The Flash developer community itself would finally be able to create its own custom Flash-authoring tools. I wonder who would be the first to nostalgically make Flash 4 for AIR in ActionScript?</p></blockquote>
<p>Wouldn’t that be neat?</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/r-i-p-fla/feed/</wfw:commentRss>
		<slash:comments>26</slash:comments>
		</item>
		<item>
		<title>Animate an Acrobatic Spy Using the Flash Timeline</title>
		<link>http://active.tutsplus.com/tutorials/workflow/animate-an-acrobatic-spy-using-the-flash-timeline/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/animate-an-acrobatic-spy-using-the-flash-timeline/#comments</comments>
		<pubDate>Fri, 01 Jan 2010 12:00:29 +0000</pubDate>
		<dc:creator>Hasier G</dc:creator>
				<category><![CDATA[Animation]]></category>
		<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://active.tutsplus.com/?p=2631</guid>
		<description><![CDATA[<img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/200.jpg" alt="Animate an Acrobatic Spy Using the Flash Timeline">]]></description>
			<content:encoded><![CDATA[<p>The key to animation, like many things, is a logical approach and good workflow. In this tut, Hasier takes you through planning, sketching and refining your animation to give you the movement you&#8217;re looking for.</p>
<p><span id="more-2631"></span></p>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/SpySource.zip" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/source.jpg" alt="" style="border:none"></a>
</div>
<h2>Final Animation Preview</h2>
<p>During this tutorial we will be creating the following animation:</p>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-preview.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-preview.swf" /></object>
</div>
<h2>Overview</h2>
<p>This tutorial will be divided into 4 parts. In each part we will go over the different stages in creating an animation from start to finish. These are the tutorial parts and their contents:</p>
<ol>
<li><strong>Before Animating</strong>
<ul>
<li>Drawing the character </li>
<li>Planning the animation</li>
</ul>
</li>
<li><strong>The Rough Animation</strong>
<ul>
<li>Sketching in Flash</li>
<li>Key drawings and timing</li>
<li>Inbetweens</li>
</ul>
</li>
<li><strong>The Clean Animation</strong>
<ul>
<li>Clean drawings</li>
<li>Optimization</li>
<li>Coloring the character</li>
</ul>
</li>
<li><strong>Finishing Touches</strong>
<ul>
<li>Adding the background</li>
<li>Masking</li>
<li>Creating a shadow</li>
</ul>
</li>
</ol>
<h2>Part I: Before Animating</h2>
<p>In the first part of this tutorial, we will go over the things you need to know before starting to animate. Do not overlook these things; planning your animation before jumping straight into Flash will save you a lot of time later on.</p>
<h2>Step 1: Getting to Know Your Character</h2>
<p>The very first step in creating an animation is, of course, deciding what you want to animate. In this tutorial, we will be animating this:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-01-1.jpg" alt="" /></div>
<p>He&#8217;s a simple spy character I made up some time ago. Because he&#8217;s so simple, it&#8217;s easy to animate him. If this is your first time attempting to animate, I suggest you give my spy a go before moving on to more complex characters.</p>
<p>So, grab a piece of paper and draw the spy a few times. Frame-by-frame animation means drawing the same thing over and over again, so you should feel comfortable drawing your character. Here&#8217;s how I draw him:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-01-2.jpg" alt="" /></div>
<h2>Step 2: Key Drawings</h2>
<p>Once you know your character inside out, it&#8217;s time to start thinking about bringing him to life. Animations are planned through <em>key frames</em> (also called <em>thumbnails</em>). In this tutorial I will refer to them as <em>key drawings</em> so as to not confuse them with Flash&#8217;s keyframes. So, what is a key drawing? Key drawings are the drawings that tell the story and define the movement in an animation. In other words, they are a way to summarize the animation in a few drawings. The example below shows how a slight difference in a key drawing can have a big impact on the final animation:</p>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-02.2.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-02.2.swf" /></object>
</div>
<p>A key drawing must be planned at the start and end of a movement and every time a change in direction or rhythm occurs in the animation. So, take another look at the final animation and sketch the key drawings keeping in mind these pointers. They should look something like this:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-02-2.jpg" alt="" /></div>
<h2>Part II: The Rough Animation</h2>
<p>When you have gotten the hang of drawing your character and have planned out the animation, it&#8217;s time to move on to Flash.</p>
<h2>Step 3</h2>
<p>Start by opening a new Flash document. The default 12 fps is too low for an animation, so for this tutorial we&#8217;ll be using 15 fps.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-03.jpg" alt="" /></div>
<h2>Step 4</h2>
<p>Name the current layer &#8220;BG&#8221;. Select a light color and sketch the basic background of the scene, in our case, a room. Don&#8217;t draw anything fancy, just the elements needed to create the rough animation: walls, floor, and the window.</p>
<p>To sketch in Flash I usually choose a large brush size with pressure sensitivity on and bring the smoothing down to around 10. This gives me more freedom to sketch, as I can vary the stroke thickness as much as I want and have more control over sharp angles because of the low smoothing. I suggest you use the same settings as me. Don&#8217;t worry if your strokes look jagged; we can fix that at the end.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-04.jpg" alt="" /></div>
<h2>Step 5</h2>
<p>Now we&#8217;re going to recreate the key drawings we made previously. Create a new layer and name it something like &#8220;Spy&#8221;. In the first frame, sketch the first key drawing you planned before. Again, just draw the basic shapes. It should look something like this:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-05.jpg" alt="" /></div>
<h2>Step 6</h2>
<p>Insert a blank keyframe (F7) in the &#8220;Spy&#8221; layer. Turn on onion skinning so that you can see the previous frame. With the first drawing as a guide, draw the second key drawing.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-06.jpg" alt="" /></div>
<h2>Step7</h2>
<p>Repeat the same process for the rest of the key drawings. When you&#8217;re done, you should have five keyframes with five different key drawings.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-07.jpg" alt="" /></div>
<h2>Step8</h2>
<p>We now arrive at the most important (and probably the most difficult) step in creating an animation: <em>timing</em>; calculating the time between our key drawings. What we do now will determine the whole animation, so it is important that it is done right.</p>
<p>Select the first frame in the &#8220;Spy&#8221; layer and add a few blank keyframes (F7) between the first and second key drawings. Do the same with the rest keyframes. This is what your timeline should look like:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-08.jpg" alt="" /></div>
<h2>Step 9</h2>
<p>Test the movie (Ctrl+Enter). As you can see, the timing is all wrong, so go back into the .fla to fix it. If the timing between two key drawings is too short, add more blank keyframes between them; if the timing is too long, delete some keyframes.</p>
<p>After tweaking it a bit, test the movie to see if it looks better than before. If it still doesn&#8217;t look right apply some more changes. It&#8217;s hard to picture the animation with only five keyframes, so don&#8217;t worry if it&#8217;s not perfect at this stage; we can tweak the timing again later. So far, this is my result:</p>
<p/>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-09.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-09.swf" /></object>
</div>
<h2>Step 10</h2>
<p>The core of our animation is now complete, but there is still a lot of work to be done. Firstly, we need to add more keyframes to make the animation seem smooth. The drawings that appear between key drawings to complete the animation are appropriately called inbetweens. Drawing inbetweens is quite easy, as we&#8217;ve already done most of the work when we made the key drawings.</p>
<p>Select a keyframe between the first two key drawings and turn on onion skinning. With two drawings as a reference, draw the spy halfway between the key drawings in the current frame.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-10.jpg" alt="" /></div>
<h2>Step 11</h2>
<p>Repeat the process. Draw a new keyframe between each of the key drawings. You should have nine keyframes.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-11.jpg" alt="" /></div>
<h2>Step 12</h2>
<p>Test the movie. If the timing still doesn&#8217;t look right, now is the time to change it. As I said before, timing is the most important part in animation, so take your time to make sure it&#8217;s right. After tweaking keyframes, the animation should look like this:</p>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-12.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-12.swf" /></object>
</div>
<h2>Step 13</h2>
<p>There is little more to explain. Keep adding inbetweens between inbetweens to smooth out the animation until there are no more blank keyframes left. Test your movie to see if anything needs to be fixed. This was my result up to this stage:</p>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-13.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-13.swf" /></object>
</div>
<h2>Part III: The Clean Animation</h2>
<p>The rough animation is now done. In this part of the tutorial we&#8217;ll work on drawing the clean version of our character. </p>
<h2>Step 14</h2>
<p>Create a new folder and name it &#8220;rough&#8221;. Turn the &#8220;BG&#8221; and &#8220;Spy&#8221; layers into guide layers so they will not be shown when the movie is published. Lock both layers and put them in the folder. Create a new layer and name it &#8220;Spy&#8221; again. In this layer we are going to draw the clean version of our character.</p>
<p>Change the fill color to black and set the brush settings as described in Step 4. Now take out the drawings you made at the beginning. Use them as a reference to draw the spy over the rough drawing.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-14.jpg" alt="" /></div>
<h2>Step 15</h2>
<p>Do the same thing for all of the keyframes. You can use onion skinning to use the previous frame as a reference.</p>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-15.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-15.swf" /></object>
</div>
<h2>Step 16</h2>
<p>Things are definitely looking much cleaner, but they are still not clean enough. Take a close look at the clean drawings. You&#8217;ll notice the strokes are jagged. We could leave them as is for this animation, but if we were working on a larger project, we would need to optimize them. Optimizing is a method Flash uses to refine a shape by reducing the amount of curves needed to define the shape.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-16-1.jpg" alt="" /></div>
<p>To optimize the strokes in the animation, select the drawings from all the frames (with &#8220;Edit multiple frames&#8221; turned on) and click Modify > Shape > Optimize (Crt+Alt+Shift+C). The Optimize Curves dialogue box will open up. You can adjust the amount of smoothing with the slider. Check the &#8220;Use multiple passes&#8221; box. This will smooth the shape over and over until no further smoothing can be achieved without affecting the shape. When you click OK, message will come up showing the percentage of the curve reduction.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-16-2.jpg" alt="" /></div>
<h2>Step 17</h2>
<p>Turn off &#8220;edit multiple frames&#8221; and take a look at your drawings. They are much smoother now, but chances are the optimization has altered (at least slightly) the shapes. You can edit them with the Free Transform Tool (Q). Make sure all drawings are closed and have no gaps.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-17.jpg" alt="" /></div>
<h2>Step 18</h2>
<p>It&#8217;s now time to give the spy some color. So grab the Paint Bucket (K) and fill him in! I used #000033 for the head, #010243 for the body, and #FFFFFF for the eyes. </p>
</p>
<p>Note: If you click with the Paint Bucket inside the drawing and nothing happens, it means your drawing has a gap somewhere. Find it and close it with the Free Transform Tool.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-18.jpg" alt="" /></div>
<h2>Part IV: Finishing Touches</h2>
<p>The animation is complete, but there are some improvements still left to do. What I explain here are mere suggestions which you do not have to follow word by word, and I will therefore not spend much time on each one.</p>
<h2>Step 19: A Clean Background</h2>
<p>Now that we&#8217;ve colored the spy we need an equally colorful background. The purpose of this tutorial, however, was to show the process of animation, so creating the background is beyond the scope of this tut. But for those who are curious, here&#8217;s a quick summery of how it was made:</p>
<p>I recreated the room in Swift3D, a program designed to incorporate 3D elements in Flash. I exported the scene as vectors and opened it in Flash. Lastly, I made some changes to the color and added a yellow glow for the lamp.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-19.jpg" alt="" /></div>
<p>You can create your background directly in Flash or any other way want. If you want to use mine, you&#8217;ll find it in the source files.</p>
<h2>Step 20: Masking</h2>
<p>As you have probably already noticed, there&#8217;s a small problem that we need to fix. Because the &#8220;Spy&#8221; layer is on top of the &#8220;BG&#8221; layer, we can see the spy when he&#8217;s supposed to be behind the wall in the first frames. To cover the part of his body that should not be shown we&#8217;ll use a layer mask.</p>
<p>Create a new layer, turn it into a mask layer, and appropriately name it &#8220;Mask&#8221;. Make the &#8220;Spy&#8221; layer masked. If you&#8217;ve been able to follow along this tutorial, you probably know Flash well enough to be familiar with layer masks, but I&#8217;ll go over them quickly:</p>
<p>A mask layer contains a filled shape which allows a linked (masked) layer to be seen through it; all empty areas in the mask layer will become invisible in the masked layer. </p>
<p>Our mask must cover the entire spy (in all the frames where part of his body should be hidden) except for the part that sticks out of the window. They say a picture is worth a thousand words, so take a look below:</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-20.jpg" alt="" /></div>
<p><em>Note:</em> If you lock both the mask layer and the masked layer, you will see the mask&#8217;s effect.</p>
<h2>Step 21: The Shadow</h2>
<p>The last touch I added to the animation was a soft shadow beneath the spy. Create a black circle in a new layer. Transform it so that it looks like the spy&#8217;s shadow.</p>
<p>Convert it into a movie clip and animate it so that is follows the wall and ground below the spy (as I said before, I won&#8217;t get into details; you should be able to do this on your own). The animated shadow should look like this:</p>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-21.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-21.swf" /></object>
</div>
<h2>Step 22: Filters</h2>
<p>To make the shadow look like a shadow, lower its alpha to 25% in the Movie Clip Property Inspector. To make it seem soft, add a blur filter in the filters tab with the parameters shown below.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-22.jpg" alt="" /></div>
<h2>Conclusion</h2>
<div class="tutorial_image">
<object width="550" height="400" data="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-preview.swf" type="application/x-shockwave-flash"><param name="src" value="http://activetuts.s3.cdn.plus.org/tuts/026_animatedMan/-preview.swf" /></object>
</div>
<p>Congratulations! Test your movie, sit back, and relax. You can now call yourself an animator. But keep in mind this is just the beginning! Look around you! There are infinite things to animate! Create your own characters, explore new techniques, develop your own style, and most importantly: have fun animating!</p>
<h2>Other References</h2>
<p>There are many books on traditional animation which I suggest you take a look at. Three books that stand out are:</p>
<ul>
<li><a href=http://www.amazon.com/Illusion-Life-Disney-Animation/dp/0786860707/ref=sr_1_1?ie=UTF8&#038;s=books&#038;qid=1256487493&#038;sr=1-1#noop>The Illusion of Life: Disney Animation</a></li>
<li><a href=http://www.amazon.com/reader/0571238343?_encoding=UTF8&#038;ref_=sib%5Fdp%5Fpt#noop>The Animator&#8217;s Survival Kit</a></li>
<li><a href=http://www.amazon.com/reader/0764159194?_encoding=UTF8&#038;ref_=sib%5Fdp%5Fpt#noop>All About Techniques in Drawing for Animation Production</a></li>
</ul>
<p>If you are interested in Flash animation, you should head to <a href=http://www.biteycastle.com>biteycastle.com</a> and check out Adam Phillips&#8217;s award-winning animations as well as his Bitey Castle Academy.</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/animate-an-acrobatic-spy-using-the-flash-timeline/feed/</wfw:commentRss>
		<slash:comments>31</slash:comments>
		</item>
		<item>
		<title>Introduction to the HYPE ActionScript 3.0 Framework</title>
		<link>http://active.tutsplus.com/tutorials/workflow/introduction-to-the-hype-actionscript-3-0-framework/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/introduction-to-the-hype-actionscript-3-0-framework/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 12:00:29 +0000</pubDate>
		<dc:creator>Tom Green</dc:creator>
				<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://active.tutsplus.com/?p=2459</guid>
		<description><![CDATA[<img src="http://activetuts.s3.cdn.plus.org/tuts/016_hype/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>In this tutorial I&#8217;m going to introduce you to <a href="http://hype.joshuadavis.com/" target="_blank">HYPE</a>, an ActionScript 3 framework released by Joshua Davis and Branden Hall on October 31, 2009.</p>
<p>The purpose of this introduction is not to get into the intricacies of the framework, but to walk you through a rather simple exercise designed to demonstrate some of the possibilities this Open Source project offers you.</p>
<p><span id="more-2459"></span></p>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/016_hype/src.zip" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/source.jpg" alt="" style="border:none"></a><br />
<a href="http://activetuts.s3.cdn.plus.org/tuts/016_hype/HYPETriangles_03.html" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Overview:</h2>
<p>As many of you may have guessed I am not a hard core coder.</p>
<p>The reason, as I will tell anybody who listens, is that &#8220;coding is not hard wired into my genes&#8221;. Give me a blank ActionScript panel in Flash and I&#8217;ll stare at it for hours. What makes this odd is I can read the code when it is given to me. Think of me as being the kind of guy who will sit in a café in France reading a French book but can’t speak the language.</p>
<p>I need to tell you this now because it&#8217;s important you know how I approached the exercise. Also, I want you to clearly understand that even though I have known Josh and Branden for quite a few years, I am not even close to being in their league or part of their &#8220;hype machine&#8221;. I&#8217;m just a guy, like you, who stumbled across something that made my life easier. As a teacher, I&#8217;ve been handed a tool that lets me teach AS3 basics in a manner that gives &#8220;Visual Learners&#8221; immediate feedback.</p>
<p>The thing is, I <em>get</em> that code, like the Flash IDE is a &#8220;creative medium&#8221;. The stuff that happens when artists and designers get hold of code is awesome to behold. Yet talk to people that are coming into Flash or have discovered they need to know AS3 to expand their creative possibilities and you will hear, &#8220;Man, this stuff is hard&#8221;. At that point, frustration takes hold and, as they say, &#8220;Now you know the rest of the story &#8230;&#8221;</p>
<p>This brings me to Josh and Branden. They hear the same story from the people they meet in their travels. The thing is, Josh was once in their shoes and what sets him apart from the rest of the pack is that he mastered the fundamentals of code while, at the same time, bringing his awesome Fine Arts talents to his work. He didn’t do it alone. </p>
<p>Branden and Josh first became deeply involved with each other at FlashForward 2000 when they were both relatively unknown and, since then, a deep and profound professional relationship has developed between them. Over the years, Josh has come up with ideas, Branden has wired them up and then Josh rearranged the wiring to take the work to levels neither expected 10 years ago.</p>
<p>What has always struck me, if you have ever seen them at a conference or presentation, is their infectious sense of &#8220;wonder&#8221; and &#8220;fun&#8221; when it comes to their collaborations or solo efforts. </p>
<p>With the introduction of ActionScript 3, both Josh and Branden quickly realized &#8220;wonder&#8221; and &#8220;fun&#8221; were two words that were  disappearing from the Flash community. Creatives avoided code as a creative medium because the language was perceived, among this group, as too complicated or complex to master. The ability to play what I call &#8220;What if&#8230;&#8221; games became too risky because the odds of breaking the project were almost 100% unless you had a deep understanding of OOP. </p>
<p>In many respects, this explains the rise of the &#8220;Developer&#8221; in the Flash community over the past few years. I am not saying this is a bad thing or &#8220;dissing&#8221; the developers. It is just that because of the complexity of the language the critical balance of the  Designer/Developer partnership became more weighted toward the Developer. Branden and Josh, rather than talk about it, decided to do something about it. </p>
<p>What many people don’t know is the genesis for HYPE was another project, Flow, which essentially tried to make things easier for designers but it fell flat on its face simply because it was too ahead of itself. Rather than give up, Branden retooled Flow and with Josh&#8217;s input it evolved into HYPE.</p>
<p>What has me jacked about the HYPE project is that the words  &#8220;wonder&#8221; and &#8220;fun&#8221; will come back if the creative community gets behind it. As you&#8217;re about to discover, you really don’t need a degree in Rocket Science to get hooked by HYPE. All you need is to be unafraid to to play with numbers and values.</p>
<h2>Step 1 : Download <a href="http://hype.joshuadavis.com/" target="_blank">HYPE.</a></h2>
<p>Be aware that Branden and Josh suggest you have Flash Professional CS4 installed before starting, even though this product will work with CS3.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/016_hype/1.jpg" width="269" height="157"/></div>
<h2>Step 2: Extension Manager</h2>
<p>Unzip the download and double-click the .mxp file to launch the Extension Manager. The Extension Manager will install everything into their ultimate destinations. If you&#8217;re curious, explore the HYPE folder- hype_01 &#8211;  that you have just unzipped. Inside you will find:</p>
<ul>
<li>All the help files inside the <em><strong>doc</strong></em> folder.</li>
<li>Examples of the various HYPE classes, including their corresponding source fla files in the <em><strong>examples</strong></em> folder.</li>
<li>The HYPE classes, found in the <em><strong>src</strong></em> folder.</li>
</ul>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/016_hype/2.jpg" width="529" height="241"/></div>
<h2>Step 3. Launch Flash</h2>
<p>Double-click the <em>Setup Classpath.jsfl</em> to launch Flash. All this step does is let Flash know where everything was placed during the install.</p>
<p>That’s it folks. Now it&#8217;s time to play.</p>
<h2>Getting Caught in the HYPE</h2>
<p>The idea for this exercise actually appeared in a tweet sent by Branden a week or so before the HYPE release. He said Josh was having too much fun playing with the SoundAnalyzer in HYPE and posted <a href="http://hype.joshuadavis.com/02_examples/soundanalyzer/02_soundanalyzer" target="_blank">this link</a>.</p>
<p>The tweet caught my attention because one of the things I love to show is Audio Visualization in Flash. I use it as an example of being fearless around code rather than a full bore ActionScript lesson.. I use myself as the poster child for this and show how, by playing with numbers and changing things I know, the complex can become interesting. I start with a basic visualization and then progress to a full bore light show.</p>
<p>Even though I make it interesting and fun, if I were to get into the nitty-gritty of working with the SoundMixer class and Byte Arrays, I may as well toss a wad of aluminum foil over to the shiny thing the audience is now staring at. They will have dialed out because I&#8217;m going way, way over their heads. When I saw Josh’s example I immediately pawed through the code looking for what wasn’t there; the complexity.</p>
<p>Let’s bring the fun back to playing with audio in Flash:</p>
<h2>Step 4: New Document</h2>
<p>Open a new Flash ActionScript 3.0 document. To get yourself started grab an mp3 audio file. This example uses &#8220;Busted Chump&#8221;, an ActiveDen demo track, but any audio file from your collection will do.</p>
<h2>Step 5: Triangle</h2>
<p>Draw a small filled triangle on the stage and convert it to a movieclip named &#8220;Triangle&#8221;. Once you&#8217;ve drawn the triangle and converted it to a movieclip, delete the movieclip from the stage.</p>
<h2>Step 6: Symbol Properties</h2>
<p>Right-click on the symbol in the Library and open the Symbol Properties. Select Export for Actionscript. Your symbol name will appear as the class. Click OK and disregard the error message that appears.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/016_hype/3.jpg" width="575" height="183"/></div>
<p>As you may have guessed, HYPE is going to pull the symbol out of the Library and allow you to play with it using ActionScript. For those of you recoiling from this, keep in mind that at its heart HYPE is a playground that gives creatives the opportunities to play &#8220;What if &#8230;&#8221; games and see the results with very little effort. In the case of this exercise I am going to play three &#8220;What if &#8230;&#8221; games:</p>
<ol>
<li>What if I put the triangles on a grid?</li>
<li>What if those triangles on the grid pulsated to the music?</li>
<li>What if those pulsating triangles were put into motion?</li>
</ol>
<h2>Step 7: ActionScript</h2>
<p>Enter the following ActionScript:</p>
<pre name="code" class="javascript">
import hype.extended.layout.GridLayout;

var numItems:int = 80;

var gridLayout:GridLayout = new GridLayout(30,30, 70, 50, 10);

  for (var i:uint = 1; i &lt; numItems; ++i) {
  var clip:Triangle = new Triangle();
  gridLayout.applyLayout(clip);
  addChild(clip);
  };
</pre>
<p>The first &#8220;What if &#8221; game involves placing the movieclip in a grid and, to paraphrase Apple, &#8220;there is a class for that&#8221;. In fact, in HYPE there is a class for practically everything you will want to do. If there isn’t, write one because HYPE is Open Source.</p>
<p>The next line tells Flash you want to put 80 triangles on the stage. Having done that, you now determine how they will appear on the grid by adding the parameters into the GridLayout object. In this case I want the grid to start 30 pixels in from the left of the stage and 30 pixels from the top of the stage. Also, there is to be 70 pixels of space between the triangles on the x axis and 50 pixels of space between the rows. The final parameter tells HYPE that I want to see what happens if there are 10 columns of triangles.</p>
<p>The &#8220;for&#8221; loop tells HYPE how to place the 80 triangles on the stage. You grab the movieclip out of the library, give it an instance name, then by using the applyLayout() method of the Gridlayout class, lay the objects into the grid using the parameters of the GridLayout object.</p>
<h2>Step 8: Test</h2>
<p>Save and test the movie.</p>
<p>That was easy and if I want to change up the look all I need to do is to play with the values in the <em>numItem</em> variable and the <em>parameters</em> in the GridLayout object. Don’t like the triangle? Then toss something else &#8211; an image, for example &#8211; into the movieclip or create a completely different movieclip and use that instead.</p>
<div class="tutorial_image"><img src="http://activetuts.s3.cdn.plus.org/tuts/016_hype/4.jpg" width="551" height="419"/></div>
<p></p>
<h4>What if the triangles were tied to an audio track?</h4>
<p>The triangles are on a grid and it is now time for our next &#8220;What if &#8230;&#8221; game. In this case : What if the alpha and scale values of the triangles were tied to an audio track? At this point, many creatives would be, as I said earlier, looking at the &#8220;shiny thing&#8221; over there. Just keep in mind the whole purpose of HYPE is to let you play, not become a hard-core coder. Let’s have some fun:</p>
<h2>Step 9: Import Classes</h2>
<p>Click into line 2 of the Script and add the following code:</p>
<pre name="code" class="javascript">
import hype.extended.behavior.FunctionTracker;
import hype.framework.sound.SoundAnalyzer;
</pre>
<p>These two classes work together in HYPE. FunctionTracker, in very simple terms, manages the functions that are running and makes sure they are mapped to the specific properties of the target object. In our case, we are going to play with the alpha and scale properties of the triangle as it reacts to the audio track.</p>
<p>The SoundAnalyzer class is where the magic happens. What it does, again in very simple terms, is to turn an audio file into data which can then be played with. What I absolutely adore about this class is I don’t have to write a ton of very complex code to get immediate results. I just need to know what the parameters do and then start playing.</p>
<h2>Step 10: SoundAnalyzer Object</h2>
<p>Add the following two lines of code after the import statements:</p>
<pre name="code" class="javascript">
var soundAnalyzer:SoundAnalyzer = new SoundAnalyzer();
soundAnalyzer.start();
</pre>
<p>All these two lines do is to create the SoundAnalyzer object and switch it on using the start() method (which is how you turn these classes on and off in HYPE). Think of the start() method as nothing more than a light switch.</p>
<h2>Step 11: Octaves</h2>
<p>Add the following code under the &#8220;applyLayout&#8221; method in the &#8220;for&#8221; loop:</p>
<pre name="code" class="javascript">
  var ranNum:Number = int(Math.random() *7);
  var alphaTracker:FunctionTracker = new FunctionTracker(clip, &quot;alpha&quot;, soundAnalyzer.getOctave, [ranNum, 0.01, 1]);
  var scaleTracker:FunctionTracker = new FunctionTracker(clip, &quot;scale&quot;, soundAnalyzer.getOctave, [ranNum, 0.5, 4]);

  alphaTracker.start();
  scaleTracker.start();
</pre>
<p>The key to the visualization is the first three lines of the code block.</p>
<p>The SoundAnalyzer class uses the audio track’s octaves; the values for octaves range from 0 to 7. The first line, therefore, creates a random number based on the maximum octave value allowed. Keep this in mind when playing with this value. Numbers greater than 7 will be rounded down to 7.</p>
<p>The next two lines use the functionTracker class to play with the triangles in the grid. You target the object, tell FunctionTracker which property of the object you want to play with, which function is to be run (<em><strong>getOctave</strong></em>) and which values to use.</p>
<p>In this case we&#8217;re going to play with the random octave values- <em>ranNum</em> &#8211; and make sure the alpha values range from 1% to 100% alpha based on the &#8220;size&#8221; of the octave in the audio track. Small numbers mean low alpha, big numbers mean full alpha. Also note that these values must be passed as an Array and that the properties being changed are String values.</p>
<p>The final two lines switch on the functions.</p>
<h2>Step 12: Sound</h2>
<p>Add the following ActionScript to the end of the code block:</p>
<pre name="code" class="javascript">
  	var sound:Sound = new Sound();
  	sound.load(new URLRequest(&quot;YourAudioTrackGoesHere.mp3&quot;));
	sound.play();
</pre>
<h2>Step 13: Test</h2>
<p>Save and test the movie.</p>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/016_hype/HYPETriangles_01.html" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/milestone.jpg" alt="" style="border:none"></a>
</div>
<p></p>
<h4>What if those pulsating triangles were put in motion?</h4>
<p>As you have discovered, this stuff is not hard and, in fact, by simply playing with numbers, you can have a huge amount of fun as you &#8220;tweak up&#8221; how those triangles pulsate and fade. Now that we have that working, let’s play our final &#8220;What if &#8230;&#8221; game and put them in motion. Here’s how:</p>
<h2>Step 14: One More Class</h2>
<p>Click once at the end of the class list and add one more class:</p>
<pre name="code" class="javascript">
import hype.extended.behavior. Oscillator;
</pre>
<p>This class is an absolute blast to play with because it puts an object on an oscillating wave. Here’s the best part: You don’t need a trigonometry background to do it. In fact, there is no math involved. </p>
<h2>Step 15: Define Boundaries</h2>
<p>Add the following ActionScript  below the import statements:</p>
<pre name="code" class="javascript">
  var myWidth = stage.stageWidth;
  var myHeight = stage.stageHeight;
  var freq:int= 20;
</pre>
<p>All this code does is confine the resulting animation to the boundaries of the stage and to set a value for the wave frequency. It is time to play with the grid.</p>
<h2>Step 16: Oscillator Object</h2>
<p>Add the following code after the &#8220;scaleTracker&#8221; variable in the &#8220;for&#8221; loop:</p>
<pre name="code" class="javascript">
  var ypositionOsc:Oscillator = new Oscillator (clip,&quot;y&quot;, Oscillator.sineWave, freq, clip.y, myHeight/3, i/(freq/2));
  var scaleOsc:Oscillator = new Oscillator (clip, &quot;scaleY&quot;, Oscillator.sineWave, freq, 5,50, i/(freq/2));
  var rotateOsc:Oscillator = new Oscillator (clip,&quot;rotation&quot;, Oscillator.sineWave, freq, 0,90, i/(freq/2));

  yOsc.start();
  sOsc.start();
  rOsc.start();
</pre>
<p>Again, the Oscillator object, like the FunctionTracker object, doesn’t require a degree in particle physics. The parameters are really simple: </p>
<ul>
<li>Which object is going to oscillate? </li>
<li>Which property- a string-  of the object is going to be affected?</li>
<li>Which wave is to be applied? Your choices are sineWave, sawWave,squareWave and triangleWave.</li>
<li>What is the wave frequency?</li>
<li>What is the minimum wave value?</li>
<li>What is the maximum wave value?</li>
<li>What wave value do we use to start?</li>
</ul>
<p>In this case we are applying a sineWave to three properties &#8211; y position, yScale and rotation- of the triangle and then using the remaining three parameters to set the look of the wave’s motion.</p>
<p>The remaining three lines switch  the Oscillator on.  The values I used simply popped out of &#8220;I wonder what the animation would look like if I used these numbers?&#8221; Nothing more.</p>
<h2>Step 17: Test</h2>
<p>Save and test the animation.</p>
<div class="tutorial_image">
<a href="http://activetuts.s3.cdn.plus.org/tuts/016_hype/HYPETriangles_03.html" target="_blank"><br />
<img src="http://activetuts.s3.cdn.plus.org/assets/icons/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Conclusion:</h2>
<p>This exercise was designed to introduce you to the HYPE framework and give you a chance to kick the tires. I showed you how to install it and then used three &#8220;What if &#8230; &#8221; scenarios that took a simple triangle and heaved it onto a pulsating and waving grid that was driven by an audio track. In regular ActionScript coding those tasks, to many, would be a reason to &#8220;Flee. Screaming. Into the night&#8221;. </p>
<p>Instead, you discovered that HYPE is aimed at dialing down the developer side of the Flash equation while bringing the fun back to the designer side. Having completed this exercise it might not be a bad idea to revisit the code with a different point of view. What would that be? In many respects, using HYPE to work out ideas very much follows the creative process. It doesn’t get you bogged down in code but instead, by playing with numbers and values, you get to do what you do best: play ‘What If &#8230;’ games.</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/introduction-to-the-hype-actionscript-3-0-framework/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Using AMFPHP with AS3 and CodeIgniter</title>
		<link>http://active.tutsplus.com/tutorials/workflow/using-amfphp-with-as3-and-codeignitor/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/using-amfphp-with-as3-and-codeignitor/#comments</comments>
		<pubDate>Mon, 17 Aug 2009 12:00:55 +0000</pubDate>
		<dc:creator>Ahmed Nuaman</dc:creator>
				<category><![CDATA[ActionScript]]></category>
		<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1136</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/055_AMFPHPAS3/preview1.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>It seems that the <a href="http://amfphp.org">AMFPHP</a> project has now been laid to rest, unfortunately it never made it past the 1.9 beta version and nor did the tutorials. However, Adobe didn&#8217;t give up on it that easily and with the new Flex compilers they&#8217;ve included the <a href="http://livedocs.adobe.com/flex/3/langref/flash/net/ObjectEncoding.html">AMF3 object encoding</a>!</p>
<p>Good news for all you Flexers, but it&#8217;s a different story for all you AS3&#8242;ers. Flex allows you to quickly and simply build a service that will interact with your AMFPHP code, but you have to get your hands dirty with AS3. So, I&#8217;ve decided that it&#8217;s time there&#8217;s a decent set of classes out there that help Bob build a site with AS3 using the AMFPHP gateway.</p>
<p>And to throw some more dirt into the mix, we&#8217;ll be integrating AMFPHP with <a href="http://codeigniter.com/">CodeIgniter</a> so that we have a fantastic PHP framework for the backend.</p>
<p>    <span id="more-1136"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/055_AMFPHPAS3/source.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://flashtuts.s3.cdn.plus.org/055_AMFPHPAS3/preview.html" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<p>As you can see there&#8217;s not much to look at, but in fact it&#8217;s the basis for our Flash communication classes; we can simply and easily send and receive data objects between the client side and the server side without serialisation.</p>
<h2>Before we start&#8230;</h2>
<p>It&#8217;s a logical idea that you&#8217;ve had a good delve with ActionScript and PHP. You don&#8217;t necessarily have to know how to use <a href="http://codeigniter.com/user_guide">CodeIgniter</a> as you could just use a PHP class as a service, but it&#8217;s worth knowing PHP.</p>
<h2>Step 1: Why Use AMFPHP?</h2>
<p>This question gets thrown around a lot. We know that flash can get data from XML, JSON, etc&#8230; But AMFPHP uses a different form of encoding called <a href="http://en.wikipedia.org/wiki/Action_Message_Format">&#8220;Action Message Format&#8221;</a>. It&#8217;s simply sending binary data rather than ASCII. Now there&#8217;s lots of blog posts around comparing XML, JSON and AMF, but at the end of the day AMF has these great advantages:</p>
<ul>
<li>
			You don&#8217;t need to serialise any data! For example, if you&#8217;re passing some objects from PHP to Flash, you need to serialise them as, say, JSON. Flash will then have to parse them in order for them to be usable, this takes time and memory.
		</li>
<li>
			It&#8217;s lighter than XML because you&#8217;re never duplicating yourself. For example, in XML you have to start with a root tag, then more tags, then closing tags, so you&#8217;ll see yourself duplicating tag names and this takes up bandwidth. Further more, XML, just like JSON, needs to be parsed into E4X and this takes time.
		</li>
<li>
			AMF can be fully integrated with your PHP code meaning that you can write less code. I&#8217;ll show you this by using CodeIgniter as well as AMF&#8217;s standard services.
		</li>
</ul>
<p>Remember, AMF isn&#8217;t a replacement for XML or JSON, it&#8217;s simply another tool in your arsenal when it comes to developing scalable dynamic applications.</p>
<h2>Step 2: The Set Up</h2>
<p>Fire up your favourite IDE, whether it&#8217;s <a href="http://www.adobe.com/products/flex/">Flex Builder</a>, <a href="http://fdt.powerflasher.com/">FDT</a>, <a href="http://www.flashdevelop.org/">FlashDevelop</a> or <a href="http://macromates.com/">TextMate</a> and create a new ActionScript project. In addition to this, we&#8217;ll be doing some PHP coding too, so get your PHP IDE ready (I recommend <a href="http://aptana.com/">Aptana</a>)</p>
<p>Additionally, we&#8217;re going to be using <a href="http://blog.greensock.com/tweenliteas3/">GreenSock&#8217;s TweenLite class</a> just to give the application a bit of magic.</p>
<p>For those of you who&#8217;ve read my recent articles: we&#8217;re not going to be delving into PureMVC this time as I wanted the outcome of this article to be a set of classes that you can reuse again, with or without PureMVC.</p>
<h2>Step 3: Creating the Base App</h2>
<p>Just like with any ActionScript app, we need to set up our base app. I&#8217;m just going to start by just creating a simple background for the app, then we&#8217;re going to look at creating the text area for the response and buttons to send a string, array, and object to PHP; so create a new file called &quot;App.as&quot; within &quot;src/&quot;:</p>
<pre name="code" class="javascript">
		package
		{
			import flash.display.GradientType;
			import flash.display.Sprite;
			import flash.geom.Matrix;
			import flash.text.Font;

			[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]

			public class App extends Sprite
			{
				[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
				private var arialFont:Class;

				public function App()
				{
					init();
				}

				private function init():void
				{
					var mat:Matrix = new Matrix();
					var bg:Sprite = new Sprite();

					mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );

					bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
					bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
					bg.graphics.endFill();

					addChild( bg );

					Font.registerFont( arialFont );
				}
			}
		}
	</pre>
<h2>Step 4: Creating the UI</h2>
<p>Since we&#8217;re going to need some sort of UI for the user to be able to interact with our app, we&#8217;re going to have to code one! Now it&#8217;s up to you whether you want to create your UI in the Flash IDE (or the new <a href="http://labs.adobe.com/technologies/flashcatalyst/">Flash Catalyst IDE</a>, looks nice) but I&#8217;m going to be hardcore and code it.. </p>
<p>In terms of UI components, we&#8217;re after:</p>
<ul>
<li>An input text box</li>
<li>A button</li>
<li>A text area</li>
</ul>
<p>It&#8217;s just the start to your UI classes, but these are all we&#8217;re going to need at the moment.</p>
<h2>Step 5: Creating an Input Text Box</h2>
<p>Since I believe that re-writing code is just long and unnecessary, let&#8217;s create a reusable UI button component. Create a new file called &quot;InputTextField.as&quot; within &quot;src/com/flashtuts/lib/display/ui&quot; and use the following code within it:</p>
<pre name="code" class="javascript">
		package com.flashtuts.lib.display.ui
    {
    	import flash.display.Sprite;
    	import flash.text.TextField;
    	import flash.text.TextFieldAutoSize;
    	import flash.text.TextFieldType;
    	import flash.text.TextFormat;

    	public class InputTextField extends Sprite
    	{
    		private var minWidth:Number								= 200;

    		private var bg:Sprite;
    		private var field:TextField;

    		public function InputTextField()
    		{
    			bg = new Sprite();

    			addChild( bg );

    			field = new TextField();

    			addChild( field );
    		}

    		public function init(format:TextFormat, width:Number=0, height:Number=0, backgroundColour:uint=0, strokeThickness:Number=0, strokeColour:uint=0, cornerRadius:Number=0, padding:Number=4):void
    		{
    			field.autoSize = TextFieldAutoSize.LEFT;
    			field.defaultTextFormat = format;
    			field.embedFonts = true;
    			field.type = TextFieldType.INPUT;
    			field.width = ( width &gt; 0 ? width - ( padding * 2 ) : minWidth );
    			field.x = padding;
    			field.y = padding;

    			bg.graphics.clear();
    			bg.graphics.lineStyle( strokeThickness, strokeColour );
    			bg.graphics.beginFill( backgroundColour );
    			bg.graphics.drawRoundRect( 0, 0, ( width &gt; 0 ? width : field.width + ( padding * 2 ) ), ( height &gt; 0 ? height : field.height + ( padding * 2 ) ), cornerRadius );
    			bg.graphics.endFill();
    		}

    		public function set text(text:String):void
    		{
    			field.text = text;
    		}

    		public function get text():String
    		{
    			return field.text;
    		}
    	}
    }
	</pre>
<p>Now, let&#8217;s quickly go through it. We start with our constructor, we construct our two main variables: the background &#8216;bg&#8217; and the textfield &#8216;field&#8217; then we add them to the stage:</p>
<pre name="code" class="javascript">
		public function InputTextField()
		{
			bg = new Sprite();

			addChild( bg );

			field = new TextField();

			addChild( field );
		}
	</pre>
<p>Our class relies on the user using the public function &quot;init()&quot; that will draw the background as well as setting up the text field:</p>
<pre name="code" class="javascript">
		public function init(format:TextFormat, width:Number=0, height:Number=0, backgroundColour:uint=0, strokeThickness:Number=0, strokeColour:uint=0, cornerRadius:Number=0, padding:Number=4):void
		{
			field.autoSize = TextFieldAutoSize.LEFT;
			field.defaultTextFormat = format;
			field.embedFonts = true;
			field.type = TextFieldType.INPUT;
			field.width = ( width &gt; 0 ? width - ( padding * 2 ) : minWidth );
			field.x = padding;
			field.y = padding;

			bg.graphics.clear();
			bg.graphics.lineStyle( strokeThickness, strokeColour );
			bg.graphics.beginFill( backgroundColour );
			bg.graphics.drawRoundRect( 0, 0, ( width &gt; 0 ? width : field.width + ( padding * 2 ) ), ( height &gt; 0 ? height : field.height + ( padding * 2 ) ), cornerRadius );
			bg.graphics.endFill();
		}
	</pre>
<p>Then finally we want to be able to set some text (if we need to) and to get any text that the user has entered, so we use get/set functions:</p>
<pre name="code" class="javascript">
	    public function set text(text:String):void
		{
			field.text = text;
		}

		public function get text():String
		{
			return field.text;
		}
	</pre>
<p>You can see that you&#8217;re able to set an ample number of variables. You can always come back and change this, but for the time being it works for this tutorial, so let&#8217;s continue.</p>
<p>We now want to add this field to our application, so I&#8217;ve created a new function called &quot;addTextField()&quot;, and called it within &quot;init()&quot;, so our app&#8217;s code looks like this:</p>
<pre name="code" class="javascript">
		package
        {
        	import com.flashtuts.lib.display.ui.InputTextField;

        	import flash.display.GradientType;
        	import flash.display.Sprite;
        	import flash.geom.Matrix;
        	import flash.text.Font;
        	import flash.text.TextFormat;

        	[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]

        	public class App extends Sprite
        	{
        		[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
        		private var arialFont:Class;

        		public function App()
        		{
        			init();
        		}

        		private function init():void
        		{
        			var mat:Matrix = new Matrix();
        			var bg:Sprite = new Sprite();

        			mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );

        			bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
        			bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
        			bg.graphics.endFill();

        			addChild( bg );

        			Font.registerFont( arialFont );

        			addTextField();
        		}

        		private function addTextField():void
        		{
        			var textField:InputTextField = new InputTextField();

        			textField.init( new TextFormat( 'Arial', 12, 0x000000 ), 200, 25, 0xFFFFFF, 1, 0x333333, 5 );

        			textField.text = 'Hello';

        			addChild( textField );
        		}
        	}
        }
	</pre>
<p>You can see that within the function I&#8217;ve created a new text format and passed that, with other parameters too, to our &quot;InputTextField()&quot; class. Fire up a preview and you&#8217;ll see your text field in the top left hand corner. Before we position anything, let&#8217;s finish the other UI components.</p>
<h2>Step 6: Creating a Button</h2>
<p>Now that we have our input text area down, let&#8217;s create a button that&#8217;ll allow us to push the data we enter to AMFPHP. So create file called &quot;Button.as&quot; inside &quot;src/com/flashtuts/lib/display/ui/&quot; and use the following code:</p>
<pre name="code" class="javascript">
	    package com.flashtuts.lib.display.ui
        {
        	import flash.display.Sprite;
        	import flash.text.TextField;
        	import flash.text.TextFieldAutoSize;
        	import flash.text.TextFormat;

        	public class Button extends Sprite
        	{
        		private var bg:Sprite;
        		private var field:TextField;

        		public function Button()
        		{
        			this.buttonMode = true;
        			this.mouseChildren = false;

        			bg = new Sprite();

        			addChild( bg );

        			field = new TextField();

        			addChild( field );
        		}

        		public function init(text:String, format:TextFormat, backgroundColour:uint=0, strokeThickness:Number=0, strokeColour:uint=0, cornerRadius:Number=0, padding:Number=4):void
        		{
        			field.autoSize = TextFieldAutoSize.LEFT;
        			field.defaultTextFormat = format;
        			field.embedFonts = true;
        			field.mouseEnabled = false;
        			field.text = text;
        			field.x = padding;
        			field.y = padding;

        			bg.graphics.clear();
        			bg.graphics.lineStyle( strokeThickness, strokeColour );
        			bg.graphics.beginFill( backgroundColour );
        			bg.graphics.drawRoundRect( 0, 0, field.width + ( padding * 2 ), field.height + ( padding * 2 ), cornerRadius );
        			bg.graphics.endFill();
        		}
        	}
        }
	</pre>
<p>A quick run through: much like our &quot;InputTextField()&quot; class, we construct our two variables &#8216;bg&#8217; and &#8216;field&#8217; and also set properties so that this class acts as a button:</p>
<pre name="code" class="javascript">
	    public function Button()
		{
			this.buttonMode = true;
			this.mouseChildren = false;

			bg = new Sprite();

			addChild( bg );

			field = new TextField();

			addChild( field );
		}
	</pre>
<p>Again, just like our &quot;InputTextField()&quot; class, we set up the display of the class:</p>
<pre name="code" class="javascript">
	    public function init(text:String, format:TextFormat, backgroundColour:uint=0, strokeThickness:Number=0, strokeColour:uint=0, cornerRadius:Number=0, padding:Number=4):void
		{
			field.autoSize = TextFieldAutoSize.LEFT;
			field.defaultTextFormat = format;
			field.embedFonts = true;
			field.mouseEnabled = false;
			field.text = text;
			field.x = padding;
			field.y = padding;

			bg.graphics.clear();
			bg.graphics.lineStyle( strokeThickness, strokeColour );
			bg.graphics.beginFill( backgroundColour );
			bg.graphics.drawRoundRect( 0, 0, field.width + ( padding * 2 ), field.height + ( padding * 2 ), cornerRadius );
			bg.graphics.endFill();
		}
	</pre>
<p>Finally we need to adjust our app&#8217;s base class like so:</p>
<pre name="code" class="javascript">
	    package
        {
        	import com.flashtuts.lib.display.ui.Button;
        	import com.flashtuts.lib.display.ui.InputTextField;

        	import flash.display.GradientType;
        	import flash.display.Sprite;
        	import flash.geom.Matrix;
        	import flash.text.Font;
        	import flash.text.TextFormat;

        	[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]

        	public class App extends Sprite
        	{
        		[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
        		private var arialFont:Class;

        		public function App()
        		{
        			init();
        		}

        		private function init():void
        		{
        			var mat:Matrix = new Matrix();
        			var bg:Sprite = new Sprite();

        			mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );

        			bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
        			bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
        			bg.graphics.endFill();

        			addChild( bg );

        			Font.registerFont( arialFont );

        			addTextField();
        		}

        		private function addTextField():void
        		{
        			var format:TextFormat = new TextFormat( 'Arial', 12, 0x000000 );
        			var textField:InputTextField = new InputTextField();
        			var button:Button = new Button();

        			textField.init( format, 200, 25, 0xFFFFFF, 1, 0x333333, 5 );

        			textField.text = 'Hello';

        			addChild( textField );

        			button.init( 'Click on me!', format, 0xCCCCCC, 1, 0x333333, 5 );

        			addChild( button );
        		}
        	}
        }
	</pre>
<p>If you ran this in debug you&#8217;d see a button over a text field, so nearly there!</p>
<h2>Step 7: Create a Text Area</h2>
<p>This one won&#8217;t be so hard as we&#8217;ve done the hard work in the &quot;InputTextField()&quot; class already, so all we&#8217;ll need to do is set the height and width of our textarea, a simple enough copy and paste job. So create a new file called &quot;InputTextArea.as&quot; inside &quot;src/com/flashtuts/lib/display/ui/&quot; and use the following code:</p>
<pre name="code" class="javascript">
	    package com.flashtuts.lib.display.ui
        {
        	import flash.display.Sprite;
        	import flash.text.TextField;
        	import flash.text.TextFieldAutoSize;
        	import flash.text.TextFormat;

        	public class InputTextArea extends Sprite
        	{
        		private var minHeight:Number							= 200;
        		private var minWidth:Number								= 200;

        		private var bg:Sprite;
        		private var field:TextField;

        		public function InputTextArea()
        		{
        			bg = new Sprite();

        			addChild( bg );

        			field = new TextField();

        			addChild( field );
        		}

        		public function init(format:TextFormat, width:Number=0, height:Number=0, backgroundColour:uint=0, strokeThickness:Number=0, strokeColour:uint=0, cornerRadius:Number=0, padding:Number=4):void
        		{
        			field.autoSize = TextFieldAutoSize.LEFT;
        			field.defaultTextFormat = format;
        			field.embedFonts = true;
        			field.multiline = true;
        			field.wordWrap = true;
        			field.height = ( height &gt; 0 ? height - ( padding * 2 ) : minHeight );
        			field.width = ( width &gt; 0 ? width - ( padding * 2 ) : minWidth );
        			field.x = padding;
        			field.y = padding;

        			bg.graphics.clear();
        			bg.graphics.lineStyle( strokeThickness, strokeColour );
        			bg.graphics.beginFill( backgroundColour );
        			bg.graphics.drawRoundRect( 0, 0, ( width &gt; 0 ? width : field.width + ( padding * 2 ) ), ( height &gt; 0 ? height : field.height + ( padding * 2 ) ), cornerRadius );
        			bg.graphics.endFill();
        		}

        		public function set text(text:String):void
        		{
        			field.text = text;
        		}

        		public function get text():String
        		{
        			return field.text;
        		}
        	}
        }
	</pre>
<p>I think at this point there&#8217;s no need to explain the whole class, but it&#8217;s worth mentioning the configuration of the field that allows it to become a text area. We simply added two more properties and set them to true: &#8216;multiline&#8217; and &#8216;wordwrap&#8217;. These turn the input box into a text area.</p>
<p>So finally, let&#8217;s add the last component to the app&#8217;s class:</p>
<pre name="code" class="javascript">
	    package
        {
        	import com.flashtuts.lib.display.ui.Button;
        	import com.flashtuts.lib.display.ui.InputTextArea;
        	import com.flashtuts.lib.display.ui.InputTextField;

        	import flash.display.GradientType;
        	import flash.display.Sprite;
        	import flash.geom.Matrix;
        	import flash.text.Font;
        	import flash.text.TextFormat;

        	[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]

        	public class App extends Sprite
        	{
        		[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
        		private var arialFont:Class;

        		public function App()
        		{
        			init();
        		}

        		private function init():void
        		{
        			var mat:Matrix = new Matrix();
        			var bg:Sprite = new Sprite();

        			mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );

        			bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
        			bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
        			bg.graphics.endFill();

        			addChild( bg );

        			Font.registerFont( arialFont );

        			addTextField();
        		}

        		private function addTextField():void
        		{
        			var format:TextFormat = new TextFormat( 'Arial', 12, 0x000000 );
        			var textField:InputTextField = new InputTextField();
        			var textArea:InputTextArea = new InputTextArea();
        			var button:Button = new Button();

        			textField.init( format, 200, 25, 0xFFFFFF, 1, 0x333333, 5 );

        			textField.text = 'Hello';

        			addChild( textField );

        			textArea.init( format, 200, 200, 0xFFFFFF, 1, 0x333333, 5 );

        			textArea.text = 'Text will appear here that's returned from the server!';

        			addChild( textArea );

        			button.init( 'Click on me!', format, 0xCCCCCC, 1, 0x333333, 5 );

        			addChild( button );
        		}
        	}
        }
	</pre>
<p>Finally, let&#8217;s just align our UI so it&#8217;s usable and set the &#8216;textField&#8217; and &#8216;textInput&#8217; so that they&#8217;re class wide functions rather than within the &quot;addTextField()&quot; function:</p>
<pre name="code" class="javascript">
		package
		{
			import com.flashtuts.lib.display.ui.Button;
			import com.flashtuts.lib.display.ui.InputTextArea;
			import com.flashtuts.lib.display.ui.InputTextField;

			import flash.display.GradientType;
			import flash.display.Sprite;
			import flash.geom.Matrix;
			import flash.text.Font;
			import flash.text.TextFormat;

			[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]

			public class App extends Sprite
			{
				private var textField:InputTextField 					= new InputTextField();
				private var textArea:InputTextArea 						= new InputTextArea();

				[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
				private var arialFont:Class;

				public function App()
				{
					init();
				}

				private function init():void
				{
					var mat:Matrix = new Matrix();
					var bg:Sprite = new Sprite();

					mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );

					bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
					bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
					bg.graphics.endFill();

					addChild( bg );

					Font.registerFont( arialFont );

					addTextField();
				}

				private function addTextField():void
				{
					var format:TextFormat = new TextFormat( 'Arial', 12, 0x000000 );
					var button:Button = new Button();

					textField.init( format, 200, 25, 0xFFFFFF, 1, 0x333333, 10 );

					textField.text = 'Hello';

					addChild( textField );

					textArea.init( format, 300, 200, 0xFFFFFF, 1, 0x333333, 10 );

					textArea.text = 'Text will appear here that\'s returned from the server!';

					addChild( textArea );

					button.init( 'Click on me!', format, 0xCCCCCC, 1, 0x333333, 10 );

					addChild( button );

					textField.x = ( stage.stageWidth / 2 ) - ( ( textField.width + button.width + 20 ) / 2 );
					textField.y = 20;

					button.x = textField.x + textField.width + 20;
					button.y = 20;

					textArea.x = ( stage.stageWidth / 2 ) - ( textArea.width / 2 );
					textArea.y = 60;
				}
			}
		}
	</pre>
<p>So that&#8217;s our base class pretty much finished. Now we&#8217;ll move on to writing the classes for AMFPHP communication.</p>
<h2>Step 8: Starting With the Basics</h2>
<p>I&#8217;m assuming that you&#8217;ve worked with loading data into Flash player before. When working with static data that&#8217;s normally loaded right at the start of your application being loaded, using XML or JSON is fine. It&#8217;s also fine with dynamic data, but AMF gives you the advantage of a constant gateway, good performance and, most importantly, less code to write as there&#8217;s no need encode or decode the data.</p>
<p>What normally happens when working with data and Flash is you&#8217;d normally either load a static file or have XML or JSON dynamically created, for example:</p>
<ul>
<li>A static file: ./assets/xml/data.xml</li>
<li>A dynamic file: http://mydomain.com/data.php?someId=1234</li>
</ul>
<p>It&#8217;s all fair and well loading data, but what if you want to send data? Yep you can of course set up a few classes to send data to your site&#8217;s dynamic scripts but then you&#8217;ll already have set up a class for retrieving data and then you&#8217;ll have to modify it so that it&#8217;ll allow you to send data. Plus of course, you&#8217;ll need to update your dynamic scripts on your site&#8217;s servers. Now this is where AMFPHP is so great, you only need to create one set of classes for ActionScript and then all your PHP code can be contained within one simple code base. I&#8217;ll also extend it to show you how you can use a framework, in this case CodeIgniter.</p>
<h2>Step 9: Creating the ActionScript Classes</h2>
<p>Since AMFPHP is a remote connection service, you may want to create other classes in the future, besides what&#8217;s the point of duplicating code? What we&#8217;ll do is create three classes:</p>
<ul>
<li>&quot;RemoteConnectionService.as&quot;: this will act as our base class and will have useful functions that we can use in the future for other remote connection services</li>
<li>&quot;RemoteConnectionServiceEvent.as&quot;: this will act as the events class that the base class will use</li>
<li>&quot;AMFPHPService.as&quot;: and this will be our AMFPHP connection class</li>
</ul>
<p>This way we&#8217;ll be able to create a nice set of classes but also have them clean and scalable should we need to write some new ones in the future.</p>
<h2>Step 10: Creating the Base Class</h2>
<p>First thing we&#8217;ll do is start with the base class. So create a file called &quot;RemoteConnectionService.as&quot; within &quot;src/com/flashtuts/lib/data/&quot; and it&#8217;ll extend the &quot;NetConnection&quot; class:</p>
<pre name="code" class="javascript">
		package com.flashtuts.lib.data
		{
			import flash.net.NetConnection;

			public class RemoteConnectionService extends NetConnection
			{
				public function RemoteConnectionService()
				{
					super();
				}

			}
		}
	</pre>
<p>Now we&#8217;ve got our class, we need to write some code, so we&#8217;ve got to think what functions can be placed within the base rather than be duplicated. I would suggest using the constructor to set up the connection, then using the base to handle any events the connection sends and finally we create a standard function that we will use to send our data.</p>
<p>The first thing to do is to write our constructor:</p>
<pre name="code" class="javascript">
		package com.flashtuts.lib.data
		{
			import flash.events.NetStatusEvent;
			import flash.net.NetConnection;
			import flash.net.Responder;

			public class RemoteConnectionService extends NetConnection
			{
				public var handleReady:Boolean							= true;

				public var data:Object;
				public var gatewayURL:String;
				public var responder:Responder;

				private var loadedEvent:String;
				private var readyEvent:String;
				private var faultEvent:String;

				public function RemoteConnectionService(gatewayURL:String, loadedEvent:String='', readyEvent:String='', faultEvent:String='', encoding:uint=3)
				{
					this.gatewayURL = gatewayURL;
					this.loadedEvent = loadedEvent;
					this.readyEvent = readyEvent;
					this.faultEvent = faultEvent;

					objectEncoding = encoding;

					if ( gatewayURL )
					{
						responder = new Responder( handleResponseResult, handleResponseFault );

						addEventListener( NetStatusEvent.NET_STATUS, handleNetEvent );

						connect( gatewayURL );
					}
				}
			}
		}
	</pre>
<p>Now you may be wondering what on earth all that is, not to fear, here&#8217;s a quick run down:</p>
<ul>
<li><strong>The public vars:</strong><br />Since this class is going to act like a service we need to tell it where the AMFPHP gateway is, therefore we set the &#8216;gatewayURL&#8217;, furthermore in order to have result and fault listeners we have to create a new &quot;Responder()&quot; (you may be wondering why this isn&#8217;t through events, maybe Adobe were hungover that day) and we will bind this responder to our calls. Finally it&#8217;s always handy to have the ability to store the data we receive from our transactions in an accessible public var, in this case called &#8216;data&#8217;.</li>
<li><strong>The private vars and &#8216;handleReady&#8217; var:</strong><br />Now since this is the base class for our remote connection service, there may be times when you&#8217;ll want to manipulate the data before it&#8217;s sent back to your application. Therefore instead of just having a &#8216;ready&#8217; event fired, I&#8217;ve set a &#8216;loaded&#8217; event too. This will allow you to hook into the service, manipulate the data and then dispatch the &#8216;ready&#8217; event. By default, any subclasses will define these events as part of the &#8216;RemoteConnectionServiceEvent()&#8217; class, but we have the ability, when super-ing, to say otherwise, allowing for greater flexibility.</li>
</ul>
<p>When we construct the class, remember this is a base class so it&#8217;ll always be super-ed rather than constructed itself, we pass in the &#8216;gatewayURL&#8217;, the events, and the encoding value (<a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/net/ObjectEncoding.html">this defaults to &#8216;3&#8242; which is AMF3 style encoding</a>, perfect for us).</p>
<h2>Step 11: Handling the Responses and Event</h2>
<p>Now we need to create the event and responder handlers for this class, so let&#8217;s add them:</p>
<pre name="code" class="javascript">
		package com.flashtuts.lib.data
		{
			import com.flashtuts.lib.events.RemoteConnectionServiceEvent;

			import flash.events.NetStatusEvent;
			import flash.net.NetConnection;
			import flash.net.Responder;

			public class RemoteConnectionService extends NetConnection
			{
				public var handleReady:Boolean							= true;

				public var data:Object;
				public var gatewayURL:String;
				public var responder:Responder;

				private var loadedEvent:String;
				private var readyEvent:String;
				private var faultEvent:String;

				public function RemoteConnectionService(gatewayURL:String, loadedEvent:String='', readyEvent:String='', faultEvent:String='', encoding:uint=3)
				{
					this.gatewayURL = gatewayURL;
					this.loadedEvent = loadedEvent;
					this.readyEvent = readyEvent;
					this.faultEvent = faultEvent;

					objectEncoding = encoding;

					if ( gatewayURL )
					{
						responder = new Responder( handleResponseResult, handleResponseFault );

						addEventListener( NetStatusEvent.NET_STATUS, handleNetEvent );

						connect( gatewayURL );
					}
				}

				private function handleNetEvent(e:NetStatusEvent):void
				{
					dispatchEvent( new RemoteConnectionServiceEvent( faultEvent, e.info.code ) );
				}

				private function handleResponseResult(data:Object):void
				{
					dispatchEvent( new RemoteConnectionServiceEvent( loadedEvent, data ) ); 

					if ( handleReady )
					{
						handleLoaderDataReady( data );
					}
				}

				public function handleLoaderDataReady(data:Object):void
				{
					this.data = data;

					dispatchEvent( new RemoteConnectionServiceEvent( readyEvent, data ) );
				}

				private function handleResponseFault(data:Object):void
				{
					dispatchEvent( new RemoteConnectionServiceEvent( faultEvent, data ) );
				}
			}
		}
	</pre>
<p>Here you see that we&#8217;ve added the responder functions &quot;handleResponseResult()&quot; and &quot;handleResponseFault()&quot;. Also, we have the &quot;handleNetEvent()&quot; just incase anything falls on it&#8217;s face and finally we have the &quot;handleLoaderDataReady()&quot; that will be called once the data is ready &#8211; instead of any hooks you may want to use.</p>
<p>You can see that it&#8217;s always dispatching events that you&#8217;re able to define. This will allow for greater flexibility and scalability in the long run.</p>
<h2>Step 12: Creating the Events Class</h2>
<p>Since we&#8217;re dispatching events from our service base class, it makes sense to have a default events class. If you&#8217;re feeling lazy and can&#8217;t be bothered to create your own events class, you can just use this as we&#8217;ll specify the class to use these events by default, so create a file called &quot;RemoteConnectionServiceEvent.as&quot; inside &quot;src/com/flashtuts/lib/events/&quot;:</p>
<pre name="code" class="javascript">
		package com.flashtuts.lib.events
		{
			import flash.events.Event;

			public class RemoteConnectionServiceEvent extends Event
			{
				public static const NAME:String							= 'RemoteConnectionServiceEvent';

				public static const LOADED:String						= NAME + 'Loaded';
				public static const READY:String						= NAME + 'Ready';
				public static const FAULT:String						= NAME + 'Fault';

				public var data:Object;

				public function RemoteConnectionServiceEvent(type:String, data:Object=null, bubbles:Boolean=true, cancelable:Boolean=false)
				{
					super( type, bubbles, cancelable );

					this.data = data;
				}
			}
		}
	</pre>
<p>It&#8217;s a pretty basic events class, we&#8217;re extending the standard &quot;Event()&quot; class and adding our own public var called &#8216;data&#8217; so that we can send data with the event and easily retrieve it through our listeners.</p>
<h2>Step 13: Creating the AMFPHP Class</h2>
<p>Now our base class and it&#8217;s events class are ready, all we need to do is extend the base so that we can use it for our AMFPHP service class. Create a new file called &quot;AMFPHPService.as&quot; inside &quot;src/com/flashtuts/lib/data/&quot;:</p>
<pre name="code" class="javascript">
		package com.flashtuts.lib.data
		{
			import com.flashtuts.lib.events.RemoteConnectionServiceEvent;

			import flash.net.ObjectEncoding;

			public class AMFPHPService extends RemoteConnectionService
			{
				public function AMFPHPService( url:String )
				{
					super( url, RemoteConnectionServiceEvent.LOADED, RemoteConnectionServiceEvent.READY, RemoteConnectionServiceEvent.FAULT, ObjectEncoding.AMF3 );
				}
			}
		}
	</pre>
<p>Don&#8217;t be confused, it&#8217;ll all make sense in a few paragraphs time, let&#8217;s start with the constructor: like I&#8217;ve said further up, our base class will always be super-ed, so within the constructor we pass the &#8216;url&#8217; variable given to this class when it&#8217;s constructed as well as the events and finally the default encoding. The reason I&#8217;m choosing to separate the &quot;AMFPHPService()&quot; class from the &quot;RemoteConnectionService()&quot; class is because it&#8217;ll allow for greater flexibility and scalability, as you can write other services that will take advantage of the base, but have different events and functions.</p>
<p>Before we continue, it&#8217;s worth talking these special variables called <a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/statements.html#..._(rest)_parameter">&#8230;(rest)</a> which basically means that a function can accept any number of comma-delimited arguments, for example:</p>
<p>Traditionally you&#8217;d need to declare a function&#8217;s arguments like this:</p>
<pre name="code" class="javascript">
		function test(arg1, arg2, arg3, arg4):void
		{
			...
		}
	</pre>
<p>However with &#8230;(rest) arguments you can do this:</p>
<pre name="code" class="javascript">
		function test(... args):void
		{
			...
		}
	</pre>
<p>And call it like this:</p>
<pre name="code" class="javascript">
		test('var1', 'var2', 'var3', 'var4', 'var5', 'varN', 'varN+1');
	</pre>
<p>So you can use any number of variables. These are then accessible in the function as an array, for example:</p>
<pre name="code" class="javascript">
		function test(... args):void
		{
			trace(args.length);
		}

		test('var1', 'var2'); // traces 2
		test('var1', 'var2', 'var3', 'var4', 'var5'); // traces 5
	</pre>
<p>&quot;NetConnection.call()&quot; takes advantage of these &#8230;(rest) arguments allowing you to send any number of arguments to your gateway. However, the function also requires you to give the &#8216;responder&#8217;, something that we created within our &quot;RemoteConnectionService()&quot; class. So since we&#8217;re always going to need to use this &quot;call()&quot; function but don&#8217;t want to write the &#8216;responder&#8217; variable every time we use it, we should put it within our base class. Go ahead and open up the &quot;RemoteConnectionService()&quot; class then update it with this:</p>
<pre name="code" class="javascript">
		package com.flashtuts.lib.data
		{
			import com.flashtuts.lib.events.RemoteConnectionServiceEvent;

			import flash.events.NetStatusEvent;
			import flash.net.NetConnection;
			import flash.net.Responder;

			public class RemoteConnectionService extends NetConnection
			{
				public var handleReady:Boolean							= true;

				public var data:Object;
				public var gatewayURL:String;
				public var responder:Responder;

				private var loadedEvent:String;
				private var readyEvent:String;
				private var faultEvent:String;

				public function RemoteConnectionService(gatewayURL:String, loadedEvent:String='', readyEvent:String='', faultEvent:String='', encoding:uint=3)
				{
					this.gatewayURL = gatewayURL;
					this.loadedEvent = loadedEvent;
					this.readyEvent = readyEvent;
					this.faultEvent = faultEvent;

					objectEncoding = encoding;

					if ( gatewayURL )
					{
						responder = new Responder( handleResponseResult, handleResponseFault );

						addEventListener( NetStatusEvent.NET_STATUS, handleNetEvent );

						connect( gatewayURL );
					}
				}

				public function send(method:String, ... args):void
				{
					call.apply( null, [ method, responder ].concat( args ) );
				}

				private function handleNetEvent(e:NetStatusEvent):void
				{
					dispatchEvent( new RemoteConnectionServiceEvent( faultEvent, e.info.code ) );
				}

				private function handleResponseResult(data:Object):void
				{
					dispatchEvent( new RemoteConnectionServiceEvent( loadedEvent, data ) ); 

					if ( handleReady )
					{
						handleLoaderDataReady( data );
					}
				}

				public function handleLoaderDataReady(data:Object):void
				{
					this.data = data;

					dispatchEvent( new RemoteConnectionServiceEvent( readyEvent, data ) );
				}

				private function handleResponseFault(data:Object):void
				{
					dispatchEvent( new RemoteConnectionServiceEvent( faultEvent, data ) );
				}
			}
		}
	</pre>
<h2>Step 14: Tying it in</h2>
<p>Now that our service classes are ready, if we go back to our app&#8217;s base class we have to add the service by creating it as a class-wide variable and constructing it within our &quot;init()&quot; function:</p>
<pre name="code" class="javascript">
		package
		{
			import com.flashtuts.lib.data.AMFPHPService;
			import com.flashtuts.lib.display.ui.Button;
			import com.flashtuts.lib.display.ui.InputTextArea;
			import com.flashtuts.lib.display.ui.InputTextField;

			import flash.display.GradientType;
			import flash.display.Sprite;
			import flash.events.MouseEvent;
			import flash.geom.Matrix;
			import flash.text.Font;
			import flash.text.TextFormat;

			[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]

			public class App extends Sprite
			{
				private var service:AMFPHPService						= new AMFPHPService( 'http://localhost/amfphp/gateway.php' );
				private var textField:InputTextField 					= new InputTextField();
				private var textArea:InputTextArea 						= new InputTextArea();

				[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
				private var arialFont:Class;

				public function App()
				{
					init();
				}

				private function init():void
				{
					var mat:Matrix = new Matrix();
					var bg:Sprite = new Sprite();

					mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );

					bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
					bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
					bg.graphics.endFill();

					addChild( bg );

					Font.registerFont( arialFont );

					addTextField();
				}

				private function addTextField():void
				{
					var format:TextFormat = new TextFormat( 'Arial', 12, 0x000000 );
					var button:Button = new Button();

					textField.init( format, 200, 25, 0xFFFFFF, 1, 0x333333, 10 );

					textField.text = 'Hello';

					addChild( textField );

					textArea.init( format, 300, 200, 0xFFFFFF, 1, 0x333333, 10 );

					textArea.text = 'Text will appear here that's returned from the server!';

					addChild( textArea );

					button.init( 'Click on me!', format, 0xCCCCCC, 1, 0x333333, 10 );

					addChild( button );

					textField.x = ( stage.stageWidth / 2 ) - ( ( textField.width + button.width + 20 ) / 2 );
					textField.y = 20;

					button.x = textField.x + textField.width + 20;
					button.y = 20;

					textArea.x = ( stage.stageWidth / 2 ) - ( textArea.width / 2 );
					textArea.y = 60;
				}
			}
		}
	</pre>
<p>And since we&#8217;re going to be using the service when the user hits the button, we need to add the event listeners to the buttons and then set up the function that will run our service&#8217;s &quot;send()&quot; function to make the call:</p>
<pre name="code" class="javascript">
		package
		{
			import com.flashtuts.lib.data.AMFPHPService;
			import com.flashtuts.lib.display.ui.Button;
			import com.flashtuts.lib.display.ui.InputTextArea;
			import com.flashtuts.lib.display.ui.InputTextField;

			import flash.display.GradientType;
			import flash.display.Sprite;
			import flash.events.MouseEvent;
			import flash.geom.Matrix;
			import flash.text.Font;
			import flash.text.TextFormat;

			[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]

			public class App extends Sprite
			{
				private var service:AMFPHPService						= new AMFPHPService( 'http://dev.ahmednuaman.com/amfphp/gateway.php' );
				private var textField:InputTextField 					= new InputTextField();
				private var textArea:InputTextArea 						= new InputTextArea();

				[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
				private var arialFont:Class;

				public function App()
				{
					init();
				}

				private function init():void
				{
					var mat:Matrix = new Matrix();
					var bg:Sprite = new Sprite();

					mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );

					bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
					bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
					bg.graphics.endFill();

					addChild( bg );

					Font.registerFont( arialFont );

					addTextField();
				}

				private function addTextField():void
				{
					var format:TextFormat = new TextFormat( 'Arial', 12, 0x000000 );
					var button:Button = new Button();

					textField.init( format, 200, 25, 0xFFFFFF, 1, 0x333333, 10 );

					textField.text = 'Hello';

					addChild( textField );

					textArea.init( format, 300, 200, 0xFFFFFF, 1, 0x333333, 10 );

					textArea.text = 'Text will appear here that's returned from the server!';

					addChild( textArea );

					button.init( 'Click on me!', format, 0xCCCCCC, 1, 0x333333, 10 );

					button.addEventListener( MouseEvent.CLICK, handleButtonClick );

					addChild( button );

					textField.x = ( stage.stageWidth / 2 ) - ( ( textField.width + button.width + 20 ) / 2 );
					textField.y = 20;

					button.x = textField.x + textField.width + 20;
					button.y = 20;

					textArea.x = ( stage.stageWidth / 2 ) - ( textArea.width / 2 );
					textArea.y = 60;
				}

				private function handleButtonClick(e:MouseEvent):void
				{
					service.send( 'HelloWorld.say', textField.text );
				}
			}
		}
	</pre>
<p>You&#8217;ll see that we&#8217;re using a method called &#8216;HelloWorld.say&#8217;, this is a test AMFPHP service and I&#8217;ll show you how to create your own later. And finally we need to add listeners to the service so that we can handle the ready event and display the response in the text area:</p>
<pre name="code" class="javascript">
		package
		{
			import com.flashtuts.lib.data.AMFPHPService;
			import com.flashtuts.lib.display.ui.Button;
			import com.flashtuts.lib.display.ui.InputTextArea;
			import com.flashtuts.lib.display.ui.InputTextField;
			import com.flashtuts.lib.events.RemoteConnectionServiceEvent;

			import flash.display.GradientType;
			import flash.display.Sprite;
			import flash.events.MouseEvent;
			import flash.geom.Matrix;
			import flash.text.Font;
			import flash.text.TextFormat;

			[SWF( width='600', height='400', frameRate='30', backgroundColor='#000000' )]

			public class App extends Sprite
			{
				private var service:AMFPHPService						= new AMFPHPService( 'http://dev.ahmednuaman.com/amfphp/gateway.php' );
				private var textField:InputTextField 					= new InputTextField();
				private var textArea:InputTextArea 						= new InputTextArea();

				[Embed( systemFont='Arial', fontName='Arial', mimeType='application/x-font' )]
				private var arialFont:Class;

				public function App()
				{
					init();
				}

				private function init():void
				{
					var mat:Matrix = new Matrix();
					var bg:Sprite = new Sprite();

					mat.createGradientBox( stage.stageWidth, stage.stageHeight, Math.PI * .5 );

					bg.graphics.beginGradientFill( GradientType.LINEAR, [ 0x333333, 0x000000 ], [ 1, 1 ], [ 0, 255 ], mat );
					bg.graphics.drawRect( 0, 0, stage.stageWidth, stage.stageHeight );
					bg.graphics.endFill();

					addChild( bg );

					Font.registerFont( arialFont );

					addTextField();

					service.addEventListener( RemoteConnectionServiceEvent.READY, handleDataReady );
				}

				private function addTextField():void
				{
					var format:TextFormat = new TextFormat( 'Arial', 12, 0x000000 );
					var button:Button = new Button();

					textField.init( format, 200, 25, 0xFFFFFF, 1, 0x333333, 10 );

					textField.text = 'Hello';

					addChild( textField );

					textArea.init( format, 300, 200, 0xFFFFFF, 1, 0x333333, 10 );

					textArea.text = 'Text will appear here that's returned from the server!';

					addChild( textArea );

					button.init( 'Click on me!', format, 0xCCCCCC, 1, 0x333333, 10 );

					button.addEventListener( MouseEvent.CLICK, handleButtonClick );

					addChild( button );

					textField.x = ( stage.stageWidth / 2 ) - ( ( textField.width + button.width + 20 ) / 2 );
					textField.y = 20;

					button.x = textField.x + textField.width + 20;
					button.y = 20;

					textArea.x = ( stage.stageWidth / 2 ) - ( textArea.width / 2 );
					textArea.y = 60;
				}

				private function handleButtonClick(e:MouseEvent):void
				{
					service.send( 'HelloWorld.say', textField.text );
				}

				private function handleDataReady(e:RemoteConnectionServiceEvent):void
				{
					textArea.text = e.data.toString();
				}
			}
		}
	</pre>
<p>That&#8217;s our ActionScript classes done! Now on to some PHP!</p>
<h2>Step 15: Using AMFPHP</h2>
<p>The first thing to do is to go to the <a href="http://sourceforge.net/project/downloading.php?group_id=72483&#038;filename=amfphp-1.9.beta.20080120.zip&#038;a=38538191">AMFPHP web site and download yourself a copy of the code base</a>. Once you&#8217;ve got it, uncompress it and stick it on your testing server or run it on your localhost. If you&#8217;re new to PHP, it&#8217;s worth reading up on it at <a href="http://www.w3schools.com/PHP/DEfaULT.asP">w3schools.com</a>.</p>
<p>Once you&#8217;re happy that you know enough about PHP, it&#8217;s time to get your hands dirty! The idea behind AMFPHP is that you can create a set of services and call them much like how you import files in ActionScript, for example:</p>
<p>AMFPHP comes with a standard service called &#8216;HelloWorld.say&#8217;. The class and file are called &#8216;HelloWorld&#8217; and the function is called &#8217;say&#8217;. AMFPHP goes to the services folder, finds a file called &#8216;HelloWorld.php&#8217;, constructs the class called &#8216;HelloWorld&#8217; and then runs the function called &#8217;say&#8217;. If you were to have a class called &#8216;Test&#8217; that belonged to the &#8216;com.flashtuts&#8217; code base, so you created a file called &#8216;Test.php&#8217; inside the folders &#8216;com/flashtuts/&#8217; then you would reference the service like &#8216;com.flashtuts.Test.function&#8217;. Simple eh?</p>
<p>The first thing we&#8217;re going to do is just get our PHP class to return a simple string and then we&#8217;ll move on to integrating CodeIgniter.</p>
<h2>Step 16: Saying Hello Back</h2>
<p>Since we&#8217;ve defaulted the text in our input field to say &#8216;Hello&#8217;, we may as well say something back, so create a new file called &quot;HelloWorld.php&quot; inside the &quot;services&quot; folder in your AMFPHP folder and use the following class:</p>
<pre name="code" class="php">
		&lt;?php
		/* include the AMFPHP utils */
		include_once( AMFPHP_BASE . 'shared/util/MethodTable.php' );

		class HelloWorld
		{
			function say($msg)
			{
				return 'You said: ' . $msg;
			}
		}

		?&gt;
	</pre>
<p>Now if you fire up your application you&#8217;ll see that the server will return &#8216;You said: (whatever you said, probably hello!)&#8217; in the text area, without the bracket bit at the end. Yay, you&#8217;ve used AMFPHP, good work! Let&#8217;s get a bit deeper.</p>
<h2>Step 17: Using a Database</h2>
<p>We&#8217;ve returned what we sent to the server, but who wants that eh? Surely we&#8217;d want to store something in the database right? So, let&#8217;s sort that out. Open up the file &quot;globals.php&quot; in the AMFPHP base directory and you&#8217;ll see a bit of code that&#8217;s commented out like this:</p>
<pre name="code" class="php">
		/*
		if(!PRODUCTION_SERVER)
		{
			define("DB_HOST", "localhost");
			define("DB_USER", "root");
			define("DB_PASS", "");
			define("DB_NAME", "amfphp");
		}
		*/
	</pre>
<p>You can either copy this and paste it underneath or just uncomment it, we&#8217;ll be using it to set our DB access. So enter your DB username, password and database, so it looks like this:</p>
<pre name="code" class="php">
		if(!PRODUCTION_SERVER)
		{
			define("DB_HOST", "localhost");
			define("DB_USER", "bob");
			define("DB_PASS", "bobsCatsName");
			define("DB_NAME", "bobsDatabase");
		}
	</pre>
<p>Now we&#8217;re ready to alter our PHP class, so load up the &quot;HelloWorld.php&quot; service class and paste the following inside:</p>
<pre name="code" class="php">
		&lt;?php
        include_once( AMFPHP_BASE . 'shared/util/MethodTable.php' );

        class HelloWorld
        {
        	var $db;

        	function __construct()
        	{
        		$this-&gt;db = mysql_connect( DB_HOST, DB_USER, DB_PASS );
        		mysql_select_db( DB_NAME );
        	}

        	function say($msg)
        	{
        		return 'You said: ' . $msg;
        	}

        	function put($data)
        	{
        		$query = mysql_query( 'INSERT INTO hello_world ( id, data ) VALUES ( \'\', \'' . $data . '\' )', $this-&gt;db );

        		if ( $query )
        		{
        			return mysql_insert_id();
        		}
        		else
        		{
        			return mysql_error();
        		}
        	}
        }

        /* End of file HelloWorld.php */
        /* Location: ./services/HelloWorld.php */
        ?>
	</pre>
<p>Here&#8217;s a quick run through:</p>
<ul>
<li>We create a class wide variable called $db, we&#8217;ll use this to store our database connection so that we won&#8217;t need to reconnect within our functions</li>
<li>The &quot;__construct()&quot; function sets up the database connection for us</li>
<li>The &quot;put()&quot; function inserts the string $data into a table called &#8216;hello_world&#8217; within our database</li>
</ul>
<p>Cool yea? let&#8217;s try it out. Change the method in your ActionScript app to &#8216;HelloWorld.put&#8217;, fire up the debug and have a go. Then use your SQL browser or <a href="http://www.phpmyadmin.net/">phpMyAdmin</a> to check the results in your database. You should see the insert id returned in your text area.</p>
<h2>Step 18: Tying in CodeIgniter</h2>
<p>Now stopping with the above is fine, you can go ahead and make a few classes and functions that will suit your site&#8217;s needs, but what if you have bigger aspirations? We all know that building apps can be faster when using frameworks and <a href="http://codeigniter.com/">CodeIgniter</a> is a great framework. I don&#8217;t want to get into the argument of which framework to use because at the end of the day CodeIgniter works for me for a few simple reasons:</p>
<ul>
<li>It&#8217;s lightweight</li>
<li>It&#8217;s simple to install</li>
<li>It&#8217;s easy to learn</li>
<li>It&#8217;s got good community support</li>
<li>And it&#8217;s free!</li>
</ul>
<p>There are other frameworks out there, but for this tut I&#8217;m going to show you how you can hook CodeIgniter into the AMFPHP platform.</p>
<h2>Step 19: Installing CodeIgniter</h2>
<p><a href="http://codeigniter.com/download.php">Grab yourself a copy of CodeIgniter from their site</a>, decompresss it and stick it up on your server or localhost. It&#8217;s pretty simple to install but for the time being we don&#8217;t need to set up a database or anything like that. For future reference, <a href="http://codeigniter.com/user_guide/">have a read of their user guide</a>. So if you then load up your browser and point it towards where you&#8217;ve put CodeIgniter you&#8217;ll see something like this:</p>
<div class="tutorial_image">
		<img src="http://flashtuts.s3.cdn.plus.org/055_AMFPHPAS3/assets/image/1.jpg" />
	</div>
<h2>Step 20: Creating the Hook</h2>
<p>Ok, now we need to modify CodeIgniter&#8217;s output by using a hook. A hook is simply a method that allows us to &#8216;hook&#8217; into the core of the system without directly editing CodeIgniter&#8217;s code. So we need to edit CodeIgniter&#8217;s config so that we can enable hooks, register our hook and then write our hook. Within your CodeIgniter directory open up &quot;system/application/config/config.php&quot;, scroll down to line 91 and change the variable to true:</p>
<pre name="code" class="php">
	   $config['enable_hooks'] = TRUE;
	</pre>
<p>Now open up &quot;hooks.php&quot; in the same folder and add the following code before the &#8216;/* End of file &#8230; */&#8217; line (so add it to line 13):</p>
<pre name="code" class="php">
	    $hook['display_override'] = array(
        								'class'		=> 'AMFPHP',
        								'function'	=> 'output',
        								'filename'	=> 'amfphp.php',
        								'filepath'	=> 'hooks'
        							);
	</pre>
<p>What we&#8217;re telling CodeIgniter here is that we want it to override it&#8217;s display output method and instead re-route everything to our hook class called &#8216;AMFPHP&#8217; within the &#8216;hooks/amfphp.php&#8217; file. Since that fine doesn&#8217;t exist, create the file &quot;system/application/hooks/amfphp.php&quot; and use the following code:</p>
<pre name="code" class="php">
	    &lt;?php if ( !defined('BASEPATH') ) exit( 'No direct script access allowed' ); 

        class AMFPHP
        {
        	function output()
        	{
        		if ( !defined( 'AMFPHP' ) )
        		{
        			$CI =&#038; get_instance();

        			$CI->output-&gt;_display( $CI-&gt;output-&gt;get_output() );
        		}
        	}
        }

        /* End of file amfphp.php */
        /* Location: ./system/application/hooks/amfphp.php */
        ?&gt;
	</pre>
<p>All we&#8217;re doing here is telling CodeIgniter to write its output. This way we&#8217;re controlling the system by checking to see we&#8217;re not making a request via AMFPHP so it can display the code as normal, otherwise AMFPHP won&#8217;t work.</p>
<h2>Step 21: Creating the Controller</h2>
<p>Ok we&#8217;re nearly there, all we have to do now is create our controller so that we can return the data back to the AMFPHP gateway. Create a file called &quot;system/application/controllers/main.php&quot; and paste this in the file:</p>
<pre name="code" class="php">
	    &lt;?php if ( !defined('BASEPATH') &#038;&#038; !defined('AMFPHP') ) exit( 'No direct script access allowed' ); 

        class Main extends Controller
        {
        	function __construct()
        	{
        		parent::Controller();
        	}

        	function index()
        	{
        		global $value;

        		$value = $_POST;
        	}
        }

        /* End of file main.php */
        /* Location: ./system/application/controllers/main.php */
        ?&gt;
	</pre>
<p>All we&#8217;re going to do here is just return the variables we sent to AMFPHP as an array rather than as the string we sent. This will show you how magic AMFPHP is, the fact that you don&#8217;t need to serialise objects before sending them back and forth is a great asset and speeds things up.</p>
<h2>Step 22: Configuring AMFPHP</h2>
<p>We&#8217;re really nearly there! We now need to create a service that will invoke the CodeIgniter framework. This service will act in the same way as the &quot;HelloWorld.php&quot; service we created, but will instead fire up CodeIgniter so that we can access all of it&#8217;s goodness. Create a new file inside your AMFPHP directory &quot;services/CI.php&quot; and paste in the following code:</p>
<pre name="code" class="php">
	    &lt;?php
        include_once( AMFPHP_BASE . 'shared/util/MethodTable.php' );

        class CI
        {
        	function execute($path='', $vars=false)
        	{
        		global $value;

        		define( 'AMFPHP', true );

        		if ( $vars &#038;&#038; is_array( $vars ) )
        		{
        			$_POST = $vars;
        		}

        		$_SERVER['PATH_INFO'] = $_SERVER['QUERY_STRING'] = $_SERVER['REQUEST_URI'] = '/' . $path;

        		require_once( '../../codeigniter/index.php' );

        		return $value;
        	}
        }

        /* End of file CI.php */
        /* Location: ./services/CI.php */
        ?&gt;
	</pre>
<p>We define a function called &quot;execute()&quot; where we will pass the URL of our &#8217;spoof&#8217; CodeIgniter method (if you&#8217;re confused, it works on the basic principle of MVC URLs where by the application responds to URL patterns like http://host/controller/function/value1/value2/valueN, you can find out more here: <a href="http://codeigniter.com/user_guide/general/urls.html">http://codeigniter.com/user_guide/general/urls.html</a>) and the values for that method. In then requires the &#8216;index.php&#8217; file of your CodeIgniter app, make sure it can find this by the way!</p>
<h2>Step 23: One Last Configuration Item</h2>
<p>You&#8217;re so close! One last thing to do is to tell CodeIgniter to only explicitly show errors, so open up the &quot;index.php&quot; file in your CodeIgniter directory and edit line 12 to be:</p>
<pre name="code" class="php">
	    error_reporting(E_ALL ^ E_NOTICE);
	</pre>
<p>We&#8217;re telling PHP not to display any notice errors, only full fat ones!</p>
<p>And that&#8217;s the PHP side down! All we need to do now is go back to our ActionScript code and change the method, so open up your app&#8217;s base file and change the method and values we send like so:</p>
<pre name="code" class="javascript">
	    private function handleButtonClick(e:MouseEvent):void
        {
			service.send( 'CI.execute', 'main', [ textField.text, 'another var', 1, 0xFFFFFF, { data: 'test', data2: 'test2' } ] );
		}
	</pre>
<p>Here we&#8217;re sending an Array rather than a number of values. This is easier and means that you can have your gateway receive the method (as the &#8216;URL&#8217;) and the data as an Array.</p>
<p>There we have it! You&#8217;ve just dug deep into AMFPHP from both the ActionScript and PHP side! Congrats!</p>
<h2>Conclusion</h2>
<p>While some people may ask what&#8217;s the point of this, there will be times within a professional developers life where he or she will need to use AMFPHP when it comes to sending and receiving data. And while XML and JSON work just fine, the beauty with AMFPHP is that when you&#8217;ve set up the classes (as you just have) you don&#8217;t have to worry about the joys of serialising data and parsing it at the receiving end as it&#8217;s all done for you!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/using-amfphp-with-as3-and-codeignitor/feed/</wfw:commentRss>
		<slash:comments>22</slash:comments>
		</item>
		<item>
		<title>Introduction to Unit Testing</title>
		<link>http://active.tutsplus.com/tutorials/workflow/introduction-to-unit-testing/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/introduction-to-unit-testing/#comments</comments>
		<pubDate>Mon, 20 Jul 2009 12:00:54 +0000</pubDate>
		<dc:creator>Jesse Freeman</dc:creator>
				<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=1215</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/preview.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>Unit testing is relatively new to ActionScript projects. Although FlexUnit has been around for a while it wasn&#8217;t intuitive to set up and there were a lot of inconsistencies with the documentation. Lucky for us, FlexUnit is now built into Flash Builder 4. Although the documentation is still sparse, this tutorial will be a good primer for setting up a Test Suite, going over several unit test examples and showing how to run/analyze them.</p>
<p><span id="more-1215"></span></p>
<p>For those of you who aren&#8217;t familiar with unit testing let&#8217;s see what Wikipedia has to say</p>
<blockquote><p>
In computer programming, unit testing is a software verification and validation method where the programmer gains confidence that individual units of source code are fit for use&#8230; Unit tests are typically written and run by software developers to ensure that code meets its design and behaves as intended. &#8211; <a href="http://en.wikipedia.org/wiki/Unit_testing" target="_blank">wikipedia</a>
</p></blockquote>
<p>In this tutorial I&#8217;ll show you how I set up a few simple unit tests on my Flash Camo framework. You&#8217;ll need to download a copy of <a href="http://labs.adobe.com/technologies/flashbuilder4/" target="_blank">Flash Builder 4</a> (in Beta right now) to follow along. Also, you&#8217;ll want to download the latest version of Flash Camo (2.2.1) from <a href="http://code.google.com/p/flash-camouflage/downloads/list" target="_blank">here</a>.</p>
<h2>Step 1: Setting up a Unit Test Project</h2>
<p>Let&#8217;s create a new project called <em>UnitTestIntro</em>.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/create_unit_test_demo.jpg" alt="create_unit_test_demo" width="515" height="512"/></div>
<p>We&#8217;ll need to place our Flash Camo SWC into a <em>libs/swcs</em> folder inside our project:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/flashcamo_setup.jpg" alt="flashcamo_setup" width="225" height="203"/></div>
<p>Finally we&#8217;ll need to tell our project where to find our SWC, right-click on the project and go into its properties. Go to the ActionScript Build Path and select the Library Path tab. Click on Add SWC Folder and point it to the lib/swcs directory.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/add_swc_folder.jpg" alt="add_swc_folder" width="513" height="220"/></div>
<p>Now that we have everything setup, we can begin doing some basic unit testing. It&#8217;s important to note that you cannot do unit testing directly in a Flex Library Project. That&#8217;s not an issue for this project but if you want to test a library of code what I usually do is set up a new project (like we are doing here) then link the two projects together and create all the tests in the new project.</p>
<p>If you are not working in a Flex Library project and want to test your code you can simply create your tests in the same project. I would suggest keeping the two separate, this way you can clearly see what are test classes and what are real classes. We&#8217;ll get into this a little later when you see how we set up the test.</p>
<h2>Step 2: Drafting a Plan</h2>
<p>Before I start anything, I take a moment to figure out exactly what I&#8217;m going to do. This is very critical when setting up unit tests. This kind of development is called <b>Test Driven Development</b>. I think I see another definition coming up:</p>
<blockquote><p>
Test-driven development (TDD) is a software development technique that uses short development iterations based on pre-written test cases that define desired improvements or new functions. Each iteration produces code necessary to pass that iteration&#8217;s tests. Finally, the programmer or team refactors the code to accommodate changes. A key TDD concept is that preparing tests before coding facilitates rapid feedback changes. &#8211; <a href="http://en.wikipedia.org/wiki/Test-driven_development" target="_blank">wikipedia</a></p></blockquote>
<p>Since this is a short intro we&#8217;re going to use an existing code library to test against. However, as you build your own application you should be writing tests along the way to validate that the code works and that any changes/refactoring doesn&#8217;t break your code&#8217;s implementation. Here&#8217;s an outline of the tests we&#8217;ll perform:</p>
<ul>
<li>Create an instance of a CamoPropertySheet.</li>
<li>Validate that it can parse CSS.</li>
<li>Test the number of selectors it found.</li>
<li>Test that the CamoPropertySheet can be converted back to a string.</li>
<li>Test what happens when we request a selector that was not found.</li>
<li>Validate clearing a CamoPropertySheet.</li>
</ul>
<p>If you&#8217;re new to Flash Camo you can check out the intro I wrote (<a href="http://flash.tutsplus.com/tutorials/workflow/intro-to-flash-camo-part-1" target="_blank">part 1</a> and <a href="http://flash.tutsplus.com/tutorials/workflow/intro-to-flash-camo-part-2" target="_blank">part 2</a>) but you can easily do this tutorial without any knowledge of how the framework works. Again, this is simply going to be a code library for us to test with.</p>
<h2>Step 3: Creating Our First Test</h2>
<p>Now that we have a plan for doing our testing, let&#8217;s create our first test. Right-click on your project and select New &gt; Test Case Class</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/new_test_case_class.jpg" alt="new_test_case_class" width="236" height="419"/></div>
<p>You will now be presented with the creation wizard. It should be familiar to anyone who has created a class in Flex/Flash Builder before. Here is what the window looks like:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/new_testcase_class_wizard.jpg" alt="new_testcase_class_wizard" width="499" height="610"/></div>
<p>Let&#8217;s talk about a few of the new fields in the wizard. We can start with the fact that Superclass is already filled in for us: <em>flexunit.framework.TestCase</em>. You can&#8217;t change this and probably shouldn&#8217;t. All this does is extend the base test class from the Unit Test Framework. Next you&#8217;ll see a few check boxes for code generation. Leave all of these checked by default. Finally there is a field for the Class we want to test.</p>
<p>Since we&#8217;re going to test Flash Camo&#8217;s CamoPropertySheet let&#8217;s fill the following values into the form:</p>
<pre name="code" class="javascript">
Name: CamoPropertySheetTest
Class to test: camo.core.property.CamoPropertySheet
</pre>
<p>Here&#8217;s a screen shot of how I set this up:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/fill_in_new_testcase_class.jpg" alt="fill_in_new_testcase_class" width="499" height="610"/></div>
<p>Hit finish and we should have our first test ready for us to add some code to.</p>
<h2>Step 4: Anatomy of a TestCase Class</h2>
<p>Let&#8217;s take a look at the code Flash Builder has generated for us:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/testcase_class.jpg" alt="testcase_class" width="600" height="632"/></div>
<p>We start out by having a private property called <em>classToTestRef</em> which is set to the value of our CamoPropertySheet. This allows the test to create an instance of this class and forces the compiler to import it when we run our test.</p>
<p>The next important method is <em>setUp</em>. This is where we&#8217;ll create an instance of our test class, configure it and make sure everything is ready for us to perform a test.</p>
<p>The last method here is <em>tearDown</em>. This is where we&#8217;ll destroy our test class&#8217; instance when the test is complete. This is very important when running multiple tests.</p>
<p>You may have noticed at the end of the class there&#8217;s another method called <em>testSampleMethod</em> which is commented out. This is an example of how you would set up a single test.</p>
<p>Each test will be a method we add to this class. When we run the Unit Test Harness it will automatically call all of our methods dynamically, of course starting with setUP and finishing with <em>tearDown</em>.</p>
<p>Now that we have a basic understanding of the TestClass setup let&#8217;s look at running it.</p>
<h2>Step 5: Running the Unit Test</h2>
<p>Before we can run this we&#8217;ll need at least one test. Let&#8217;s uncomment the <em>testSampleMethod</em> for this example.</p>
<p>Once you&#8217;ve uncommented the <em>testSampleMethod</em> let&#8217;s right-click on our project and select Run As &gt; Execute FlexUnit Test.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/execute_flexunit_test.jpg" alt="execute_flexunit_test" width="282" height="111"/></div>
<p>You should now see the following window prompting us to select which test we want to run.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/run_test_config.jpg" alt="run_test_config" width="476" height="463"/></div>
<p>As you see, this is set up for when we have lots to test but for now we only have one testSampleMethod to run. Click Select All and hit OK.</p>
<p>After the test is run, your web browser will pop up with the following page:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/swf_test_output.jpg" alt="swf_test_output" width="600" height="212"/></div>
<p>If you go back to Flash Builder you&#8217;ll also see this in the FlexUnit Results panel:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/eclipse_test_output.jpg" alt="eclipse_test_output" width="600" height="76"/></div>
<p>See how easy this was to run? We&#8217;ve performed our first unit test and already we have a single error. Before we move on to fix this error let&#8217;s talk about these two windows.</p>
<p>The webpage that was open should automatically close but sometimes it doesn&#8217;t. This is a simple swf that performs our tests in FLash and outputs some data the Flash Builder reads to display to final results of the test. You can ignore this webpage for the most part.</p>
<p>The FlexUnit Results panel is where all of the results will be shown as well as a place that allows you to organize and filter the test feedback. We&#8217;ll go over this a little later in the tutorial when we actually have something to test.</p>
<h2>Step 6: Set Up</h2>
<p>Before we can really get into testing we&#8217;ll need to setup our test class. let&#8217;s add the following code to the <em>setUp</em> method:</p>
<pre name="code" class="xml">
var xml:XML = &lt;css&gt;&lt;![CDATA[/* This is a comment in the CSS file */
							baseStyle {
								x: 10px;
								y: 10px;
								width: 100px;
								height: 100px;
								padding: 5px;
								margin: 10px;
							}

							baseStyle .Button{
								x: 0px;
								y: 0px;
								background-color: #000000;
							}

							#playButton {
								background-color: #FFFFFF;
							 	background-image: url('/images/full_screen_background.jpg');
							}

							#fullScreenButton{
								background-color: #FF0000;
								background-image: url('/images/full_screen_background.jpg');
							}

							#playButton:over {
								background-color: #333333;
							}

							interactive {
								cursor: hand;
							}
									]]&gt;
										&lt;/css&gt;;
rawCSS = xml.toString();
sheet = new CamoPropertySheet();
sheet.parseCSS(rawCSS);
</pre>
<p>We&#8217;ll also need to setup some properties:</p>
<pre name="code" class="javascript">
private var sheet:CamoPropertySheet;
private var rawCSS:String;
</pre>
<p>Here&#8217;s what&#8217;s happening in this setup: in order for us to test our CamoPropertySheet we are going to need some CSS as a string. Normally I would load in the CSS from an external file but since we&#8217;re doing a simple test I just create a new XML block and put the CSS text inside of the first node. Normally, you don&#8217;t have to wrap CSS for the CamoPropertySheet inside of XML but when working with large strings inside of the editor I find it easier to use xml since you can wrap the text and it retains some formatting.</p>
<p>Next you&#8217;ll see that we set our rawCSS property to the xml&#8217;s string value. This converts the xml into a string. Then we create a new CamoPropertySheet. Finally, we tell the sheet to parse the rawCSS.</p>
<p>That&#8217;s all there is to setting up this particular class. The setup is different for each class you test. It is important to demonstrate that we&#8217;re doing the bare minimum to get a class ready to be tested and we can&#8217;t test a class without values can we?</p>
<h2>Step 7: Our First Test</h2>
<p>Let&#8217;s get right to it. Once a CamoPropertySheet has successfully parsed a css string we can request an array of Selector names to verify everything has indeed been parsed. For those not familiar with CSS jargon, a selector is the name of a css style ie <em>baseStyle{&#8230;}</em> would have a selector called <em>baseStyle</em>.</p>
<p>In here is what our test would look like in English:</p>
<ol>
<li>Get a list of selectors from the CamoPropertySheet.</li>
<li>Get the length of the selector array.</li>
<li>Compare the length value to 6 (the number we are expecting returned).</li>
</ol>
<p>Let&#8217;s replace our <em>testSampleMethod</em> with the following method:</p>
<pre name="code" class="javascript">
public function testParseCSS():void
{
	var selectors:Array = sheet.selectorNames;
	var total:Number = selectors.length;

	assertEquals(total,6);
}
</pre>
<p>As you can see we get an array of selector names. Next we get the total and introduce our first test <em>assetEquals</em>. In the next step I&#8217;ll explain the assertMethods in more detail, but let&#8217;s just run this and see if the test passes.</p>
<p>When you run the test you should see the following in the FlexUnit Results panel:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/first_test_pass.jpg" alt="first_test_pass" width="600" height="93"/></div>
<p>Nice, our test passed. We received the exact number of selectors that we were expecting. Let&#8217;s look at what assert tests we can use.</p>
<h2>Step 8: Assertions</h2>
<p>In unit testing we run assertions. Each assertion handles a particular type of test. Here is a brief overview of the most common assertions you will probably use:</p>
<ul>
<li><b>assertEquals</b> &#8211; test to see if one value equals another.</li>
<li><b>assertFalse</b> &#8211; test to see if value equals false.</li>
<li><b>assertNotNull</b> &#8211; test to see if value is not equal to null.</li>
<li><b>assertNotUndefined</b> &#8211; test if value is not undefined.</li>
<li><b>assertNull</b> &#8211; test if value is null.</li>
<li><b>assertStrictlyEquals</b> &#8211; test to see if two values strictly equal each other.</li>
<li><b>assertTrue</b> &#8211; test to see if value is true.</li>
<li><b>assertUndefined</b> &#8211; test to see if value is undefined.</li>
</ul>
<p>Now, before we test an example of each one let&#8217;s set up our <em>tearDown</em> method.</p>
<h2>Step 9: Tear Down</h2>
<p>This is going to be a very short step but it&#8217;s a very important one. Let&#8217;s add the following line to our <em>tearDown</em> method after <em>super.tearDown()</em>:</p>
<pre name="code" class="javascript">
sheet = null;
</pre>
<p>What this basically does is remove the reference to our CamoPropertySheet so the Garbage Collector can remove it.</p>
<p>You should always set up your <em>tearDown</em> especially when running multiple test classes or a large test suite.</p>
<h2>Step 10: Assert Equals</h2>
<p>We&#8217;ve already seen an example of this before in Step 7, but let&#8217;s go through and add another <em>assertEquals</em>. Here is the next test we&#8217;ll perform:</p>
<ol>
<li>Compress CSS text (remove white spaces, special characters and other obstacles the css parser may not be able to recognize) since the CamoPropertySheet automatically compresses css test when it is parsed.</li>
<li>Convert the CamoPropertySheet into text (this will be a compressed version of the rawCSS we used earlier).</li>
<li>Compare that the CamoPropertySheet text is equal to our compressed css string.</li>
</ol>
<p>In order to run the test, let&#8217;s add the following method:</p>
<pre name="code" class="javascript">
public function testToString():void
{
	var compressedCSS:String = "baseStyle{x:10;y:10;width:100;height:100;padding:5;margin:10;}baseStyle .Button{x:0;y:0;background-color:#000000;}#playButton{background-color:#FFFFFF;background-image:url('/images/full_screen_background.jpg');}#fullScreenButton{background-color:#FF0000;background-image:url('/images/full_screen_background.jpg');}#playButton:over{background-color:#333333;}interactive{cursor:hand;}";
	assertEquals(sheet.toString(), compressedCSS);
}
</pre>
<p>Now run the Unit Test and make sure you select both tests from the check boxes. New tests don&#8217;t automatically get selected. If everything went well you should see a success and that 2 tests were run.</p>
<h2>Step 11: Assert False</h2>
<p>We can do a simple test to make sure if we request a Selector that doesn&#8217;t exist we get a false value. Here&#8217;s how we would do this with the CamoPropertySheet:</p>
<ol>
<li>Make a request for a selector that doesn&#8217;t exist.</li>
<li>Check the returned selector&#8217;s name to see if it equals &#8220;EmptySelector&#8221; &#8211; a constant on the PropertySelector class.</li>
<li>Assert if the value is false.</li>
</ol>
<p>Here is the code to perform the test:</p>
<pre name="code" class="javascript">
public function testEmptySelector():void
{
	var selector:PropertySelector = sheet.getSelector("testSelector");
	var exists:Boolean = (selector.selectorName == PropertySelector.DEFAULT_SELECTOR_NAME) ? false : true;

	assertFalse(exists);
}
</pre>
<p>As you can see, we&#8217;re simply requesting a fake style name <em>testSelector</em>. We check to see if the selector&#8217;s name is the default name applied when no selector is found. Finally we pass the exists variable to the <em>assertFalse</em> method. When you run this you should now see 3 passes totaling a success.</p>
<h2>Step 12: Assert Not Null</h2>
<p>Next we want to make sure that the text value from our CamoPropertySheet is never null. Let&#8217;s look at how to structure our test:</p>
<ol>
<li>call <em>toString</em> on our CamoPropertySheets instance and test to see if it is not null</p>
</ol>
<p>Here&#8217;s our test method:</p>
<pre name="code" class="javascript">
public function testCSSValue():void
{
	assertNotNull(sheet.toString());
}
</pre>
<p>This is pretty straight forward so when you run the test we should now have 5 successes. Every time we run the test we can check to see the names of our method tests by clicking on the Default Suite folder our FlexUnit Results Panel back in Flash Builder.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/test_run.jpg" alt="test_run" width="351" height="133"/></div>
<h2>Step 13: Assert Not Undefined</h2>
<p>In this next test we&#8217;re going to follow up on the empty selector test to verify that every selector has a <em>selectorName</em>.</p>
<ol>
<li>Get a selector that doesn&#8217;t exist.</li>
<li>Get a selector that does exist.</li>
<li>Test to see if both selectors&#8217; names are not undefined.</li>
</ol>
<p>Here is the test method:</p>
<pre name="code" class="javascript">
public function testSelectorsHaveNames():void
{
	var selectorA:String = sheet.getSelector("testSelector").selectorName;
	var selectorB:String = sheet.getSelector("baseStyle").selectorName;

	assertNotUndefined(selectorA, selectorB);
}
</pre>
<p>The first two lines are self explanatory; we simply ask for two selectors and one of which we know does not exist. When we do the assert however you&#8217;ll notice we&#8217;re passing in two values instead of the normal one we&#8217;ve done up until this point. This is not a unique example, in fact each of the assert methods allow you pass in any number of values to test. Here we simply make sure that selectorA and selectorB are not undefined.</p>
<h2>Step 14: Assert Strictly Equals</h2>
<p>Here is an example of how to strictly compare two objects. Here I&#8217;m using strings which may not be the best use of this example but it&#8217;s good to see the test in action. What are we going to do?</p>
<ol>
<li>Clone the CamoPropertySheet.</li>
<li>Test that the string value of our CamoPropertySheet is equal to the value of a cloned CamoPropertySheet.</li>
</ol>
<pre name="code" class="javascript">
public function testClone():void
{
	var clone:CamoPropertySheet = sheet.clone() as CamoPropertySheet;

	assertStrictlyEquals(sheet.toString(), clone.toString());
}
</pre>
<p>
As you can see we call the clone method of the CamoPropertySheet to get back an exact copy of the PropertySheet. Next we run it through the assert test by calling the <em>toString</em> method on each. If the returned CSS test is the same we have a success for the test.</p>
<h2>Step 15: Assert True</h2>
<p>
Now we want to test that when we request a selector, it has a property we are expecting. Here is the test:
</p>
<ol>
<li>Request the <em>baseStyle</em> selector.</li>
<li>Test to see if the selector has the property <em>x</em>.</li>
</ol>
<p>Here is the test method:</p>
<pre name="code" class="javascript">
public function testSelectorHasProperty():void
{
	var selector:PropertySelector = sheet.getSelector("baseStyle");
	assertTrue(selector.hasOwnProperty("x"));
}
</pre>
<p>As you can see here we are expecting our <em>baseStyle</em> selector to have the x property. If this exists we can assume that it was correctly parsed from the CSS string. Since it exists we have passed this test.</p>
<p>Each of these tests becomes self explanatory as to how you implement them. Let&#8217;s look into what happens when we fail a test in the next two steps.</p>
<h2>Step 16: Assert Undefined</h2>
<p>We&#8217;re going to test for undefined now but Flash Camo has been designed to not return undefined. So the following test will fail. Let&#8217;s check out what we&#8217;re going to test for.</p>
<ol>
<li>Call the clear method on the CamoPropertySheet.</li>
<li>Test to see if calling <em>toString</em> will return undefined.</li>
</ol>
<p>Here&#8217;s the code for the test:</p>
<pre name="code" class="javascript">
public function testClear():void
{
	sheet.clear();
	assertUndefined(sheet.toString());
}
</pre>
<p>Now let&#8217;s run this test and go onto the next step to discuss the results.</p>
<h2>Step 17: Failing A Test</h2>
<p>If you did the previous step and ran the unit test, you should see the following in the FlexUnit Results panel:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/test_fail.jpg" alt="test_fail" width="600" height="201"/></div>
<p>Notice how we have 1 failure from our <em>testClear</em> method?</p>
<p> If you double-click on the failed test in the Test Results panel you will jump to the source of the test that failed. This is a great way to correct your mistake or alter the test so it doesn&#8217;t fail. There isn&#8217;t much more to failing a test then this. Every test that fails will show up in this panel, you can tell the panel to only show failed tests by clicking on the red exclamation mark above where it tells you how many errors you had.</p>
<p>Now that we have failed this test replace it with the following:</p>
<pre name="code" class="javascript">
public function testClear():void
{
	sheet.clear();
	assertEquals(sheet.toString(),"");
}
</pre>
<p>If you run the test again you&#8217;ll see that it will pass. Now you have 7 out of 7 passed tests and this class is successfully working. Let&#8217;s talk about setting up unit tests for your own custom classes.</p>
<h2>Step 18: Auto Generating Test Classes</h2>
<p>Up until this point we have been testing a precompiled library, but you may be interested in how this will work on your own classes. We&#8217;re going to alter the doc class a little then run a custom unit test on it. To get started, replace all of the code in the UnitTestIntro class with the following:</p>
<pre name="code" class="javascript">
package
{
	import flash.display.Sprite;

	public class UnitTestIntro extends Sprite
	{

		private var _firstName:String;
		private var _lastName:String;
		private var _loggedIn:Boolean;

		public function UnitTestIntro()
		{
			_firstName = "Jesse";
			_lastName = "Freeman";
		}

		public function get firstName():String
		{
			return _firstName;
		}

		public function get lastName():String
		{
			return _lastName;
		}

		public function isLoggedIn():Boolean
		{
			return _loggedIn;
		}
	}
}
</pre>
<p>Once you have the code in place, right-click on <em>UnitTestIntro</em> and select New &gt; Test Case Class. If you look at the wizard this time you&#8217;ll see all of the fields are filled in for us:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/unit_test_intro_test.jpg" alt="unit_test_intro_test" width="508" height="609"/></div>
<p>This time, instead of clicking Finish, hit next and look at the following window:</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/unit_test_automation.jpg" alt="unit_test_automation" width="492" height="596"/></div>
<p>Here you can select all of the public methods of that class to test. Notice how our getters for firstName and lastName are not part of this list. Unit testing can only be performed on public methods. Also, you will see every inherited method of the class so we have Sprite/DisplayObject methods here since our doc class extends Sprite. Select <em>isLoggedIn</em> and hit finish.</p>
<p>If you scroll down to the bottom of the new test class that was just generated you&#8217;ll see it has automatically added in a testMethod for isLoggedIn.</p>
<div class="tutorial_image"><img src="http://flashtuts.s3.cdn.plus.org/062_IntroUnitTesting/images/test_created_automatically.jpg" alt="test_created_automatically" width="511" height="210"/></div>
<p>When testing your own code Flash Builder can help automate the process of scaffolding your tests. This is a great help when dealing with large classes that have lots of methods.</p>
<h2>Step 19: Best Practices</h2>
<p>By now you should have a solid understanding of how Unit Testing in Flash Builder works. You may even be ready to start setting up your own test. There are a lot of things I wasn&#8217;t able to cover in this short tutorial so here are some things to keep in mind when creating your tests.</p>
<ul>
<li>Keep your code small and easily testable. Make short methods, break code down into &#8220;units&#8221; to help facilitate testing. It&#8217;s ok to have lots of methods in your classes. Not only does it help you when unit testing but also when extending classes and dealing with inheritance overriding.</li>
<li>Test a behavior and not a method. This tutorial showed you how I would interact with the instance of the CamoPropertySheet. I was testing behavior responses for the underlying parsing/retrieval system. Make sure you are not testing that functions simply return values but that the underlying logic is correct. Did something get parsed, did the dependent methods do what they were expected to do?</li>
<li>Keep your test names clean. You should be able to easily understand what is going on by simply looking at the name of the test method. Remember this code is not compiled into your final application so if you have incredibly long method names, that&#8217;s ok as long as they&#8217;re descriptive.</li>
<li>Don&#8217;t rely on the console window for your test. This means you shouldn&#8217;t expect a developer to watch trace outputs to see if the test is working correctly. Instead make the test fail or succeed and not output its results.</li>
<li>Do a search for Unit Testing in other languages to see how it has been implemented elsewhere. Also pick up a book on Test Driven Development (TDD).</li>
</ul>
<h2>Conclusion</h2>
<p>As you can see, setting up Unit Testing is very simple, but creating applications revolving around Test Driven Development is an art form in its own right. Hopefully after this intro you&#8217;ll be comfortable setting up a simple test to validate that your code works as expected. As you rely more and more on Unit testing the number of bugs in your code will dramatically go down. As long as you remember to code towards passing a test, keeping your methods small and validating your unit tests often, you&#8217;ll be well on your way to building more stable code.</p>
<p>Thanks for reading.</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/introduction-to-unit-testing/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Intro to Flash Camo Part 2</title>
		<link>http://active.tutsplus.com/tutorials/workflow/intro-to-flash-camo-part-2/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/intro-to-flash-camo-part-2/#comments</comments>
		<pubDate>Mon, 15 Jun 2009 12:00:29 +0000</pubDate>
		<dc:creator>Jesse Freeman</dc:creator>
				<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=872</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/preview_2.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>Welcome to the part two of my introduction to the <a href="http://code.google.com/p/flash-camouflage/" target="_blank">Flash Camouflage</a> Framework. In part 1 we built the foundation for our site, components, labels, css parser, and set up our PropertySheet. In this part we&#8217;re going to focus on the design side of our site by cleaning up the layout, skins and adding interaction.</p>
<p>Let&#8217;s get started.</p>
<p><span id="more-872"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/source.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://jessefreeman.com" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Preview</h2>
<p>To refresh our memory, this is the final product we&#8217;re going to create. It is the <b>Bobble Person Site Launcher</b> I use on <a href="http://jessefreeman.com" target="_blank">http://jessefreeman.com</a>.</p>
<div class="tutorial_image">
<a href="http://www.jessefreeman.com/" target="_blank"><img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/1_bobblehead_preview.jpg" alt="1_bobblehead_preview" width="532" height="358"/></a>
</div>
<h2>Step 15: Decals Sheets</h2>
<p>I&#8217;ve talked about creating a <a href="http://flash.tutsplus.com/tutorials/effects/build-a-smart-flash-decalsheet-system/" target="_blank">Decal Sheet System</a> before, but now we&#8217;re going to take advantage of Flash Camo&#8217;s own built in system. Let&#8217;s talk about how Decals work in Camo.</p>
<p>The main feature of the framework is the DecalSheet system (located in the &quot;camo.core.decal&quot; package); made up of the <b>DecalSheetManager</b>, <b>DecalSheet</b> and <b>Decal</b> classes. The DecalSheet concept was inspired by the decals you would get with model airplanes. Each model kit would contain sheets of graphics and on each sheet you could peel off a decal and place it on the model. Camo&#8217;s version of the DecalSheet allow you to load in external images, cut out decals and skin your application with them.</p>
<p>For this step you will need Photoshop CS 3/4 to open the psd. You can download it from <a href="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/downloads/bobble_head_skin.zip">here</a>.</p>
<p>Once you have downloaded the PSD, open it up and take a look.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/2_bobble_head_skin.jpg" alt="2_bobble_head_skin" width="600" height="390"/>
</div>
<p>As you can see we have our simple design. I&#8217;ve gone ahead and done all of the prep work for you so let&#8217;s just go to &quot;save as&quot; and create a new PNG. Note: if you go to &quot;Save For Web&quot; you will see the slices we&#8217;ll be using later in the tutorial.</p>
<p>We&#8217;ll save this png as &quot;default.png&quot; to our &quot;html-template/images/skins&quot; folder in our BobbleHeadApp project. You can also right-click on the following image and use it instead of the PSD. Make sure you save it as &quot;default.png&quot;</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/3_bobble_head_skin.png" alt="3_bobble_head_skin" width="570" height="359"/>
</div>
<p>Now that we have our skin, we need to create a Global DecalSheet Manager.</p>
<h2>Step 16: Create a Global DecalSheet Manager</h2>
<p>Our site is going to make extensive use of the DecalSheet system, but first we&#8217;re going to need to come up with a way to make it accessible throughout our application. Just like we did with the GlobalStyleSheetManager, we&#8217;re going to create a Singleton for our DecalSheetManager class.</p>
<p>The <b>DecalSheetManager</b> (located in the &quot;camo.core.managers&quot; package) is the manager for the decal system. It handles the xml that defines a list of DecalSheet images and coordinates for cutting out each Decal. It also stores a collection of DecalSheets to make creating complex Decal lookup tables easier to manage. You can configure DecalSheets and Decals on the DecalSheetManager at run time or with XML. Once this data is set, the DecalSheetManager goes out and gets all the images it needs for the DecalSheet images. </p>
<p>Now we&#8217;re ready to set up our GlobalDecalSheetManager class. You&#8217;ll need to create a new class called &quot;GlobalDecalSheetManager&quot; and put it into &quot;com.jessefreeman.managers&quot; package.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/4_create_global_decal_sheet.jpg" alt="4_create_global_decal_sheet" width="534" height="484"/>
</div>
<p>Here&#8217;s the code for the class:</p>
<pre name="code" class="javascript">
package com.jessefreeman.managers
{
	import camo.core.managers.DecalSheetManager;

	public class GlobalDecalSheetManager
	{

		public static const INIT:String = "init";

		private static var __instance:DecalSheetManager;

		/**
		 *
		 * @param enforcer
		 *
		 */
		public function GlobalDecalSheetManager(enforcer:SingletonEnforcer)
		{
			if (enforcer == null)
			{
				throw new Error("Error: Instantiation failed: Use GlobalDecalSheetManager.instance instead.");
			}
		}

		/**
		 *
		 * @return
		 *
		 */
		public static function get instance():DecalSheetManager
		{
			if (GlobalDecalSheetManager.__instance == null)
			{
				GlobalDecalSheetManager.__instance = new DecalSheetManager();
			}
			return GlobalDecalSheetManager.__instance;
		}

	}
}

internal class SingletonEnforcer{}
</pre>
<p>This should look familiar to you by now, so there isn&#8217;t much to go over. Let&#8217;s talk about how to load in DecalSheet XML and parse it.</p>
<h2>Step 17: Defining Decals</h2>
<p>We&#8217;re going to modify the DecalSheet xml in our htm-template folder. In order to create our decals we&#8217;ll need to know the x,y,width and height of each decal we want to use. Here is a quick mockup of our PSD with the coordinates.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/5_decals_coords.jpg" alt="5_decals_coords" width="600" height="391"/>
</div>
<p>Now that we have all the values we need, replace the contents of our decahsheet.xml in the html-template/xml folder with the following:</p>
<pre name="code" class="xml">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;decalsheet&gt;
	&lt;sheets baseURL="images/skins"&gt;
		&lt;sheet name="default" src="/default.png" preload="true" w="570" h="359"/&gt;
	&lt;/sheets&gt;
	&lt;decals&gt;
		&lt;decal name="head" sheet="default" x="433" y="181" w="136" h="138"/&gt;
		&lt;decal name="body" sheet="default" x="255" y="139" w="182" h="139"/&gt;
		&lt;decal name="leftArm" sheet="default" x="208" y="278" w="194" h="76"/&gt;
		&lt;decal name="leftFoot" sheet="default" x="4" y="172" w="125" h="78"/&gt;
		&lt;decal name="leftLeg" sheet="default" x="128" y="172" w="122" h="78"/&gt;
		&lt;decal name="rightArm" sheet="default" x="251" y="17" w="182" h="122"/&gt;
		&lt;decal name="rightLeg" sheet="default" x="3" y="6" w="216" h="168"/&gt;
	&lt;/decals&gt;
&lt;/decalsheet&gt;
</pre>
<p>This xml should be easy to follow, we&#8217;re defining our DecalSheet source then defining each decal and the sheet they belong to. Notice how the sheet has an attribute to preload, we&#8217;re going to use DecalSheetManager&#8217;s loader to prelaod all of our site&#8217;s images. This will play a more important role when we preload several DecalSheets later on.</p>
<h2>Step 18: Loading DecalSheets</h2>
<p>The DecalSheetManager uses xml to create DecalSheets and Decals. We&#8217;ll need to load in some XML first then we can pass it off to the GlobalDecalSheetManager&#8217;s DecalSheetManager (try saying that 3 times fast).</p>
<p>Let&#8217;s start by adding the following methods after our &quot;onPropertySheetLoad&quot; method in the Doc Class:</p>
<pre name="code" class="javascript">
private function loadDecalSheetData():void
{
	var urlLoader:URLLoader = new URLLoader();
	urlLoader.addEventListener(Event.COMPLETE, onDecalSheetDataLoad, false, 0, true);
	urlLoader.load(new URLRequest("xml/decalsheet.xml"));
}

private function onDecalSheetDataLoad(event:Event):void
{
	// Remove Event Listener
	URLLoader(event.target).removeEventListener(Event.COMPLETE, onDecalSheetDataLoad);

	//
	var xml:XML = XML(event.target.data);
	var decalSheetManager:DecalSheetManager = GlobalDecalSheetManager.instance;
	decalSheetManager.addEventListener(LoaderManagerEvent.PRELOAD_NEXT, onPreloadNext, false, 0, true);
	decalSheetManager.addEventListener(LoaderManagerEvent.PRELOAD_DONE, onDecalSheetsLoad, false, 0, true);
	decalSheetManager.parseXML(xml);
}

protected function onPreloadNext(event:LoaderManagerEvent):void
{
	trace("Loading DecalSheet " + event.data.totalPreloaded + " of " + event.data.totalPreloading);
}

private function onDecalSheetsLoad(event:LoaderManagerEvent):void
{
	var target:DecalSheetManager = event.target as DecalSheetManager;
	target.removeEventListener(LoaderManagerEvent.PRELOAD_DONE, onDecalSheetsLoad);
	init();
}
</pre>
<p>You will also need to import the following:</p>
<pre name="code" class="javascript">
import camo.core.managers.DecalSheetManager;
import com.jessefreeman.managers.GlobalDecalSheetManager;
import camo.core.events.LoaderManagerEvent;
</pre>
<p>We just added a lot of code so let&#8217;s take a second to go over what&#8217;s going on. First we define the &quot;loadDecalSheetData&quot; method. All we&#8217;re doing here is creating a new urlLoader and having it load our decalsheet.xml. When the load is completed we call &quot;onDecalSheetDataLoad&quot;. This method handles removing the event listener from our URL loader and passes off the XML to the instance of the DecalSheetManager obtained from our GlobalDecalSheetManager Singleton. We also added two listeners; one for the notification of the &quot;next&quot; preload initiation and the second is when the preload is completed. When we&#8217;re done loading we call &quot;onDecalSheetLoad&quot;, remove our listeners and call init.</p>
<p>Now we have to remove the &quot;init&quot; call from our &quot;onPropertySheetLoad&quot; method. Replace that function with the following: </p>
<pre name="code" class="javascript">
private function onPropertySheetLoad(event:Event):void
{
	var target:URLLoader = event.target as URLLoader;
	target.removeEventListener(Event.COMPLETE, onPropertySheetLoad);

	propSheet.parseCSS("global.properties", target.data);

	loadDecalSheetData();
}
</pre>
<p>If you compile, everything should look the same but we&#8217;re now loading in our DecalSheet xml along with the DecalSheet image.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/6_decal_xml_and_sheet_image.jpg" alt="6_decal_xml_and_sheet_image" width="580" height="272"/>
</div>
<h2>Step 19: Decal Display</h2>
<p>We&#8217;ll need a component to display our Decal in. Normally you can take advantage of the BoxModel&#8217;s background image property to automatically load in any image you would need, but since our body parts need to be centered we&#8217;ll have to position them by hand.</p>
<p>Let&#8217;s start by renaming our &quot;SimpleDisplay&quot; in &quot;com.jessefreeman.components&quot; to &quot;DecalDisplay&quot;.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/7_rename.jpg" alt="7_rename" width="551" height="291"/>
</div>
<p>Once you&#8217;ve done that, open the class up and replace its code with the following:</p>
<pre name="code" class="javascript">
package com.jessefreeman.components
{
	import camo.core.decal.Decal;
	import com.jessefreeman.managers.GlobalDecalSheetManager;
	import com.jessefreeman.components.AbstractComponent;

	public class DecalDisplay extends AbstractComponent
	{
		protected var decalInstance:Decal;

		public var pixelSnapping:String = "auto";

		public var smoothing:Boolean = true;

		public function DecalDisplay(id:String)
		{
			super(this, id);
		}

		public function set src(decalName:String):void
		{
			decalInstance = GlobalDecalSheetManager.instance.getDecal(decalName, pixelSnapping, smoothing);
			if (!contains(decalInstance))
				addChild(decalInstance);
		}
	}
}
</pre>
<p>As you can see, we have a few properties that we can use to style this class from a PropertySheet. Let&#8217;s take a look at the public variables, pixelSnapping and smoothing should look familiar if you have worked with the Bitmap Class before. These just help with making our Decals look smooth when they bobble around.</p>
<p>The main functionality of the class is the setter for src. As you can see it accepts a decal name, then requests the Decal from the GlobalDecalSHeetManager. If the decal exists we add it to the display. Let&#8217;s talk about Decals a little.</p>
<p>A <b>Decal</b> is a Bitmap that contains a reference to the DecalSheet it was cut out from. Now that you have seen how we get xml data into the DecalSheetManager, let&#8217;s talk about how to retrieve Decal instances. When you call &quot;getDecal&quot; on the DecalSheetManager or DecalSheet, you need to supply the name of a Decal. You can check if a Decal exists by looking through a DecalSheet&#8217;s &quot;decalName&quot; Array. Once a Decal is requested, the Decal&#8217;s name gets passed to the parent DecalSheet through the &quot;sample&quot; method and the Decal&#8217;s BitmapData is returned inside of a new Decal Instance.</p>
<p>Since all Decals contain a reference to the DecalSheet it was cut out from, this connection allows the Decal to receive updates from its parent DecalSheet. You can change a DecalSheet&#8217;s BitmapData at any time just as you would any other Bitmap instance. Decals listen for &quot;Event.CHANGE&quot; events from their parent Sheet and once an event is received, it resamples the DecalSheet and updates its own BitmapData. Later we&#8217;ll reskin an entire application on the fly by changing the BitmapData of our DecalSheet.</p>
<h2>Step 20: Using The Decal Display</h2>
<p>Now that we have our DecalDisplay we need to add it to our BobbleContainer. In BobbleContainer, add the following method after &quot;get active&quot;:</p>
<pre name="code" class="javascript">
public function set src(value:String):void
{
	decalDisplay = new DecalDisplay(id + "DecalDisplay");
	decalDisplay.src = value;
	addChildAt(decalDisplay, 0);
}
</pre>
<p>Also we&#8217;ll need to create the following property:</p>
<pre name="code" class="javascript">
protected var decalDisplay:DecalDisplay;
</pre>
<p>So all we&#8217;re doing is adding a setter for src that we can pass into a new instance of the DecalDisplay. Notice that we&#8217;re using &quot;addChildAt&quot;? Since we add our label,  we want to make sure that the DecalDisplay is at the lowest end of the display list. Now we have our DecalDisplay in place, we just need to set up some property styles.</p>
<h2>Step 21: Styling Decal Displays</h2>
<p>We have everything we need in place to start displaying our Decals. All we have to do is add some new properties to our PropertySheet. Take a look at this sample style for the DecalDisplay then we&#8217;ll update the entire property sheet:</p>
<pre name="code" class="css">
#body
{
	x: 355;
	y: 229;
	width: 181;
	height: 144;
	src: body;
}

#bodyDecalDisplay
{
	x: -84;
	y: -65;
}
</pre>
<p>As you may have noticed earlier when we create our DecalDisplays in the BobbleContainer, we pass in the BobbleContainer&#8217;s id and the string &quot;DecalDisplay&quot; so each instance has a unique id. In the above example we&#8217;ve added src to refer to the name of the Decal we want to use and then have a corresponding style with the x,y offset for the decal. Replace the contents of your &quot;main.properties.css&quot; with the following: </p>
<pre name="code" class="css">
/* CSS file */

.BobblePerson
{
	part-ids: head body leftArm rightArm leftLeg leftFoot rightLeg;
}

.Label
{
	font: Arial Black;
	size: 20px;
	embedFonts: true;
	color: #ffffff;
	anti-alias-type: advanced;
}

#siteLabel
{
	text: ANATOMY OF JESSE FREEMAN;
	x: 155;
	y: 60;
	size: 18px;
	rotation: 24px;
	letter-spacing: -2;
	text-height: 30px;
	alpha: .5;
}

.BobbleContainer
{
	active: true;
	rollOverForce: 1;
	roll-over-force: 1;
	nodding-force: 0;
	nodding-angle: 0;
	nodding-range: 10;
	nodding-hit: .7;
	nodding-damp: .985;
}

/* BobbleContainers */

#body
{
	x: 355;
	y: 229;
	src: body;
}

#head
{
	x: 449;
	y: 250;
	src: head;
}

#leftArm
{
	x: 381;
	y: 313;
	src: leftArm;
}

#leftFoot
{
	x: 145;
	y: 213;
	src: leftFoot;
}

#leftLeg
{
	x: 263;
	y: 235;
	src: leftLeg;
}

#rightArm
{
	x: 419;
	y: 176;
	src: rightArm;
}

#rightLeg
{
	x: 275;
	y: 176;
	src: rightLeg;
}

/* BobbleContainer Labels */

#bodyLabel
{
	alpha: 1;
	rotation: 20;
	x: -35;
	y: -30;
	text-align: center;
	auto-size: center;

}

#leftArmLabel
{
	text: bFreeDesign;
	x:  -90;
	y: 25;
	rotation: -9;
	size: 18;
	letter-spacing: -3;
}

#leftFootLabel
{
	text: eMail;
	x: -78;
	y: -13;
	rotation: 6;
}

#leftLegLabel
{
	text: FlashBum;
	x: -95;
	y: -40;
	rotation: 9;
}

#rightArmLabel
{
	text: FlashArtOfWar;
	x: -80;
	y: -75;
	rotation: 32;
	font-size: 16;
	letter-spacing: -1;
}

#rightLegLabel
{
	text: iLikeToDream;
	x: -157;
	y: -83;
	rotation: 27;
}

/* BobbleContainer Displays */

#bodyDecalDisplay
{
	x: -84;
	y: -65;
}

#headDecalDisplay
{
	x: -20;
	y: -18;
}

#leftArmDecalDisplay
{
	x: -162;
	y: -11;
}

#leftFootDecalDisplay
{
	x: -104;
	y: -20;
}

#leftLegDecalDisplay
{
	x: -103;
	y: -43;
}

#rightArmDecalDisplay
{
	x: -136;
	y: -104;
}

#rightLegDecalDisplay
{
	x: -192;
	y: -142;
}
</pre>
<p>Now you have a clean PropertySheet with our decals correctly connected. If you do a compile you should see all of the body parts in their correct place along with our labels.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/8_bobble_head_preview.jpg" alt="8_bobble_head_preview" width="571" height="382"/>
</div>
<h2>Step 22: Focus Event</h2>
<p>As we begin to add interactivity to our app we&#8217;ll need a custom event to track mouse interaction on the body parts. Let&#8217;s create a new class called &quot;FocusEvent&quot; in &quot;com.jessefreeman.events&quot;</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/9_create_focus_event.jpg" alt="9_create_focus_event" width="521" height="482"/>
</div>
<p>Here&#8217;s the code:</p>
<pre name="code" class="javascript">
package com.jessefreeman.events
{
	import flash.events.Event;

	public class FocusEvent extends Event
	{
		public static const IN_FOCUS:String = "inFocus";
		public static const LOST_FOCUS:String = "lostFocus";

		public var text : *;
		public var skinName : String;

		public function FocusEvent(type:String, text:String = "" , skinName:String = "default", bubbles:Boolean=false, cancelable:Boolean=false)
		{
			this.text = text;
			this.skinName = skinName;
			super(type, bubbles, cancelable);
		}

	}
}
</pre>
<p>So in this FocusEvent class we have added two new properties to the event&#8217;s default constructor, &quot;text&quot; and &quot;skinName&quot;. Text will be the label of the body part we roll over and skinName will be used later when we start to dynamically reskin our app. We also have two constants representing our states, &quot;inFocus&quot; and &quot;lostFocus&quot;.</p>
<p>Let&#8217;s dispatch this event by going into the BobbleContainer class and add the following line to the end of the &quot;onRollOver&quot; method:</p>
<pre name="code" class="javascript">
dispatchEvent( new FocusEvent( FocusEvent.IN_FOCUS, rollOverText, "default", true, true ) );
</pre>
<p>
Then add the following to the &quot;onRollOut&quot; method:
</p>
<pre name="code" class="javascript">
dispatchEvent( new FocusEvent( FocusEvent.LOST_FOCUS, rollOverText, "default", true, true ) );
</pre>
<p>Also make sure you import the FocusEvent:</p>
<pre name="code" class="javascript">
import com.jessefreeman.events.FocusEvent;
</pre>
<p>Now we have two events being dispatched letting us know the state of BobbleContainer. Before we&#8217;re done we need to add a new public variable to the BobbleContainer:</p>
<pre name="code" class="javascript">
public var rollOverText : String = "";
</pre>
<p>We pass this variable into the in focus event that gets dispatched. You will need to modify your css with the new rollOverText. Replace these styles found in the /* BobbleContainers */ comment block with the following:</p>
<pre name="code" class="css">
/* BobbleContainers */

#body
{
	x: 355;
	y: 229;
	rollOverLabel:;
	src: body;
}

#head
{
	x: 449;
	y: 250;
	src: head;
	rollOverText: RESUME;
}

#leftArm
{
	x: 381;
	y: 313;
	src: leftArm;
	rollOverText: HIRE;
}

#leftFoot
{
	x: 145;
	y: 213;
	src: leftFoot;
	rollOverText: CONTACT;
}

#leftLeg
{
	x: 263;
	y: 235;
	src: leftLeg;
	rollOverText: PORTFOLIO;
}

#rightArm
{
	x: 419;
	y: 176;
	src: rightArm;
	rollOverText: BLOG;
}

#rightLeg
{
	x: 275;
	y: 176;
	src: rightLeg;
	rollOverText: MY ART;
}
</pre>
<h2>Step 23: Updating Body Label</h2>
<p>Now we have all of the roll over text in place it&#8217;s time to display them. You may have noticed that the &quot;body&quot; part doesn&#8217;t have any rollOverText. We&#8217;re going to display the body part&#8217;s text here. Let&#8217;s go into the BobblePerson and make a few modifications.</p>
<p>At the end of the &quot;createParts&quot; method add the following two event listeners:</p>
<pre name="code" class="javascript">
display.addEventListener( FocusEvent.IN_FOCUS, onContainerRollOver );
display.addEventListener( FocusEvent.LOST_FOCUS, onContainerRollOut );
</pre>
<p>
Below the &quot;createParts&quot; method add the following:
</p>
<pre name="code" class="javascript">
public function onContainerRollOver(event:FocusEvent):void
{
	if (event.target != partDisplay)
	{
		partDisplay.label.text = event.text;
	}
}

public function onContainerRollOut(event:FocusEvent):void
{
	partDisplay.label.text = "";
}
</pre>
<p>We&#8217;ll need to add a new getter so put the following under get &quot;partIds&quot;.</p>
<pre name="code" class="javascript">
public function get partDisplay():BobbleContainer
{
	var index:int = _partIds.indexOf(partDisplayId);

	return (index != -1) ? partInstances[index] : null;
}
</pre>
<p>We&#8217;re almost there, now let&#8217;s make sure you have the following property:</p>
<pre name="code" class="javascript">
public var partDisplayId : String;
</pre>
<p>Then import the follow class:</p>
<pre name="code" class="javascript">
import com.jessefreeman.events.FocusEvent;
</pre>
<p>Before we test this, we just need to update our &quot;.BobblePerson&quot; css style to include the following property:</p>
<pre name="code" class="javascript">
part-display-id: body;
</pre>
<p>Now do a compile and roll over the body parts.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/10_roll_over_test.jpg" alt="10_roll_over_test" width="560" height="359"/>
</div>
<p>Notice how we can change the body part that will display the text at any time by modifying the part-display-id in our css. Let&#8217;s add in the final set of logic to our site.</p>
<h2>Step 24: Adding Click Logic</h2>
<p>Now we&#8217;re going to add some listeners to track when a BodyPart is clicked so we can open a corresponding url in a new window. Go into the BobbleContainer and replace &quot;addEventListeners&quot; and &quot;removeEventListeenrs&quot; with the following code:</p>
<pre name="code" class="javascript">
protected function addEventListeners(target : IEventDispatcher) : void
{
	target.addEventListener( MouseEvent.ROLL_OVER, onRollOver );
	target.addEventListener( MouseEvent.ROLL_OUT, onRollOut );
	target.addEventListener( MouseEvent.CLICK, onClick );
}

protected function removeEventListeners(target : IEventDispatcher) : void
{
	target.removeEventListener( MouseEvent.ROLL_OVER, onRollOver );
	target.removeEventListener( MouseEvent.ROLL_OUT, onRollOut );
	target.removeEventListener( MouseEvent.CLICK, onClick );
}
</pre>
<p>We&#8217;re simply adding a listener for Mouse Click. Add the following method below &quot;onRollOut&quot;:</p>
<pre name="code" class="javascript">
protected function onClick(event : MouseEvent) : void
{
	if(url)
    	navigateToURL( url, "_self" );
}
</pre>
<p>Let&#8217;s add a new public variable for our urls:</p>
<pre name="code" class="javascript">
public var url : URLRequest;
</pre>
<p>Import the following classes:</p>
<pre name="code" class="javascript">
import flash.net.URLRequest;
import flash.net.navigateToURL;
</pre>
<p>All we need to do is modify our PropertySheet to include urls for each part by replacing the &quot;/* BobbleContainers */&quot; comment block with the following:</p>
<pre name="code" class="css">
/* BobbleContainers */

#body
{
	x: 355;
	y: 229;
	rollOverLabel:;
	src: body;
}

#head
{
	x: 449;
	y: 250;
	src: head;
	rollOverText: RESUME;
	url: url("http://www.linkedin.com/in/jessefreeman");
}

#leftArm
{
	x: 381;
	y: 313;
	src: leftArm;
	rollOverText: HIRE;
	url: url("http://www.bfreedesign.com");
}

#leftFoot
{
	x: 145;
	y: 213;
	src: leftFoot;
	rollOverText: CONTACT;
	url: url("mailto:jessefreeman@gamil.com");
}

#leftLeg
{
	x: 263;
	y: 235;
	src: leftLeg;
	rollOverText: PORTFOLIO;
	url: url("http://www.flashbum.com");
}

#rightArm
{
	x: 419;
	y: 176;
	src: rightArm;
	rollOverText: BLOG;
	url: url("http://www.flashartofwar.com");
}

#rightLeg
{
	x: 275;
	y: 176;
	src: rightLeg;
	rollOverText: MY ART;
	url: url("http://www.iliketodream.com");
}
</pre>
<p>Notice how we have added url properties. This is how we tell Camo&#8217;s CSS parser to convert urls into URL Requests. Now when a user clicks on a body part we simply pass off the url request set by the PropertyStyleSheet to the &quot;navigateToURL&quot; class.</p>
<p>If you would like the Bobble Parts to act as buttons, simply add the following to the &quot;.BobbleContainer&quot; style:</p>
<pre name="code" class="css">
button-mode: true;
use-hand-cursor: true;
mouse-children: false;
</pre>
<p>Now all of the BobbleContainer classes will automatically act as buttons. You may want to change one more style, the &quot;#body&quot;, so it doesn&#8217;t have mouse interactivity. Simply add the following to the property selector:</p>
<pre name="code" class="css">
button-mode: false;
use-hand-cursor: false;
mouse-children: false;
</pre>
<p>Now it overrides the Class&#8217;s default settings and will not have mouse interactivity.</p>
<p>Let&#8217;s look into how to do some advanced skinning.</p>
<h2>Step 25: Advanced Skinning</h2>
<p>When you opened up the PSD you may have noticed a few extra &quot;skins&quot; in the Body Skin folder.</p>
<p>I have prepared the following skins for us to use. You can download the <a href="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/downloads/skins.zip" target="_blank">zip</a> here and put the skins in your html-template/images/skins folder.</p>
<p>Now you have each skin let&#8217;s look at how we can load them all in.</p>
<h2>Step 26: Loading Multiple DecalSheets</h2>
<p>Loading in multiple DecalSheet images is as easy as modifying out xml. Let&#8217;s replace our decalsheet.xml with the following:</p>
<pre name="code" class="xml">
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;decalsheet&gt;
	&lt;sheets baseURL="images/skins"&gt;
		&lt;sheet name="default" src="/default.png" preload="true" w="570" h="359"/&gt;
		&lt;sheet name="iliketodream" src="/iliketodream_skin.png" preload="true" w="570" h="359"/&gt;
		&lt;sheet name="flashbum" src="/flashbum_skin.png" preload="true" w="570" h="359"/&gt;
		&lt;sheet name="bfreedesign" src="/bfreedesign.png" preload="true" w="570" h="359"/&gt;
		&lt;sheet name="artofwar" src="/artofwar_skin.png" preload="true" w="570" h="359"/&gt;
	&lt;/sheets&gt;
	&lt;decals&gt;
		&lt;decal name="head" sheet="default" x="433" y="181" w="136" h="138"/&gt;
		&lt;decal name="body" sheet="default" x="255" y="139" w="182" h="139"/&gt;
		&lt;decal name="leftArm" sheet="default" x="208" y="278" w="194" h="76"/&gt;
		&lt;decal name="leftFoot" sheet="default" x="4" y="172" w="125" h="78"/&gt;
		&lt;decal name="leftLeg" sheet="default" x="128" y="172" w="122" h="78"/&gt;
		&lt;decal name="rightArm" sheet="default" x="251" y="17" w="182" h="122"/&gt;
		&lt;decal name="rightLeg" sheet="default" x="3" y="6" w="216" h="168"/&gt;
	&lt;/decals&gt;
&lt;/decalsheet&gt;
</pre>
<p>All we&#8217;ve done here is added four new DecalSheets to preload. Compile the site and check your connections to make sure they are being loaded.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/12_skins_being_loaded.jpg" alt="12_skins_being_loaded" width="553" height="313"/>
</div>
<h2>Step 27: Adding Reskin Logic</h2>
<p>Now that we&#8217;re loading in our skins, let&#8217;s add some logic to handle dynamically changing the skin bitmapdata. Let&#8217;s go into our BobblePerson class and add the following two functions:</p>
<pre name="code" class="javascript">
protected function saveDefaultBitmapData():void
{
	defaultSkin = GlobalDecalSheetManager.instance.getSheet("default");
	defaultSkinBMD = defaultSkin.bitmapData.clone();
}

protected function switchSkin(skinName:String = "default"):void
{
	var newSkinBitmapData:BitmapData;

	if (skinName == "default")
	{
		newSkinBitmapData = defaultSkinBMD.clone();
	}
	else
	{
		newSkinBitmapData = GlobalDecalSheetManager.instance.getSheet(skinName).bitmapData.clone();
	}

	if (newSkinBitmapData)
		defaultSkin.bitmapData = newSkinBitmapData;
}
</pre>
<p>Let&#8217;s talk about what&#8217;s going on here. We&#8217;re going to take advantage of a neat feature of Camo&#8217;s DecalSheet system by replacing the bitmap data of our default skin with BitmapData from other skins. In order to do this we need to have a reference to the default DecalSheet as well as its BitmapData. We do this in &quot;saveDefaultBitmapData&quot;. Next we need to add logic to switch skins. This happens in the &quot;switchSkin&quot; method. As you can see we set up a variable to hold our new BitmapData.</p>
<p>Next we test to see if the skin is &quot;default&quot; or something else. If it&#8217;s the default skin we get the BitmapData from &quot;defaultSkinBMD&quot;. If it&#8217;s another skin we&#8217;ll ask the GlobalDecalSheetManager&#8217;s instance for that sheet. Lastly, we make sure we have a valid BitmapData in our newSkinBitmapData variable then set the BitmapData of our default skin to the newSkinBitmapData.</p>
<p>We need to add the following variables:</p>
<pre name="code" class="javascript">
protected var defaultSkin:DecalSheet;
protected var defaultSkinBMD:BitmapData;
</pre>
<p>and make sure you&#8217;ve imported the BitmapData class:</p>
<pre name="code" class="javascript">
import flash.display.BitmapData;
import camo.core.decal.DecalSheet;
import com.jessefreeman.managers.GlobalDecalSheetManager;
</pre>
<p>Finally we&#8217;ll call &quot;saveDefaultBitmapData&quot; in the setter for &quot;partIds&quot;. Make sure your setter looks like this:</p>
<pre name="code" class="javascript">
public function set partIds(value:Array):void
{
	_partIds = value;
	saveDefaultBitmapData();
	createParts();
}
</pre>
<p>Now let&#8217;s go into our BobbleContainer class and add the following property:</p>
<pre name="code" class="javascript">
public var skin:String = "default";
</pre>
<p>Next you will need to modify the dispatchEvent in the &quot;onRollOver&quot; method to look like this:</p>
<pre name="code" class="javascript">
dispatchEvent(new FocusEvent(FocusEvent.IN_FOCUS, rollOverText, skin, true, true));
</pre>
<p>Notice how we&#8217;re now passing up the skin value through the event? This will tell the body the correct skin to use when there&#8217;s a roll over.</p>
<p>Let&#8217;s go back to our BobblePerson and modify the &quot;onContainerRollOver&quot; and &quot;onContainerRollOut&quot; methods to look like this:</p>
<pre name="code" class="javascript">
public function onContainerRollOver(event:FocusEvent):void
{
	if (event.target != partDisplay)
	{
		partDisplay.label.text = event.text;
		switchSkin(event.skinName);
	}
}

public function onContainerRollOut(event:FocusEvent):void
{
	partDisplay.label.text = "";
	switchSkin("default");
}
</pre>
<p>Now we just have to modify our PropertySheet to add a skin name to our body parts. Replace the /* BobbleContainers */ comment block with the following:</p>
<pre name="code" class="css">
/* BobbleContainers */

#body
{
	x: 355;
	y: 229;
	rollOverLabel:;
	src: body;
	button-mode: false;
	use-hand-cursor: false;
	mouse-children: false;
}

#head
{
	x: 449;
	y: 250;
	src: head;
	rollOverText: RESUME;
	url: url("http://www.linkedin.com/in/jessefreeman");
	skin: default;
}

#leftArm
{
	x: 381;
	y: 313;
	src: leftArm;
	rollOverText: HIRE;
	url: url("http://www.bfreedesign.com");
	skin: bfreedesign;
}

#leftFoot
{
	x: 145;
	y: 213;
	src: leftFoot;
	rollOverText: CONTACT;
	url: url("mailto:jessefreeman@gamil.com");
	skin: default;
}

#leftLeg
{
	x: 263;
	y: 235;
	src: leftLeg;
	rollOverText: PORTFOLIO;
	url: url("http://www.flashbum.com");
	skin: flashbum;
}

#rightArm
{
	x: 419;
	y: 176;
	src: rightArm;
	rollOverText: BLOG;
	url: url("http://www.flashartofwar.com");
	skin: artofwar;
}

#rightLeg
{
	x: 275;
	y: 176;
	src: rightLeg;
	rollOverText: MY ART;
	url: url("http://www.iliketodream.com");
	skin: iliketodream;
}
</pre>
<p>Now if you compile, you will see the skin of our bobble guy change depending on which body part you roll over.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/13_reskin_preview.jpg" alt="13_reskin_preview" width="539" height="365"/>
</div>
<p>Notice how quickly everything is reskined. This is why Decals are so powerful. You can change the look and feel of your entire application on the fly by changing the BitmapData of your DecalSheets at runtime.</p>
<h2>Step 28: Deploy</h2>
<p>Now our site is done and we&#8217;re ready to deploy it to a server. This is fairly easy to do in Flex builder and a step most people over look. Simply go to the Project menu and select Export Release Build.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/036_CamoPart2/images/14_bin_release.jpg" alt="14_bin_release" width="595" height="463"/>
</div>
<p>Once this runs you will have a new folder called bin-release along with your bin-debug. Everything looks the same, but if you check out the side of our BobbleHeadApp.swf you will notice that the release build is about 24k and the debug version is 36k. That is barely 66% of the original size. I know when you are only talking about a few k it&#8217;s not a major deal, but every k counts. Also, in larger projects this can be a significant saving.</p>
<p>Now you are ready to copy this bin-release folder over to your FTP server and make it live.</p>
<h2>Conclusion</h2>
<p>As you can see, we have created a simple Flash Site using Flash Camouflage in less then 30 steps. By now you should have a better understanding about the power of incorporating Decals and CSS in your next project. You have also seen how easy it is to build components that work with Flash Camo&#8217;s three main features. Like all frameworks there is a learning curve and this is only a small sample of what is possible. Also, Flash Camo is still in Beta so there may be small bugs or code cleanup as the project matures.</p>
<p>If you encounter any issues, please leave a comment or submit an issue to the <a href="http://code.google.com/p/flash-camouflage/issues/list" target="_blank">issue list</a>. Remember Flash Camo is completely open source, you should check out the code and see what is going on under the hood. A lot of advanced techniques are being used so it&#8217;s a great place to learn how a framework is put together. If you use Camo in one of your projects let please me know..</p>
<p>Thanks for following along!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/intro-to-flash-camo-part-2/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Intro to Flash Camo: Part 1</title>
		<link>http://active.tutsplus.com/tutorials/workflow/intro-to-flash-camo-part-1/</link>
		<comments>http://active.tutsplus.com/tutorials/workflow/intro-to-flash-camo-part-1/#comments</comments>
		<pubDate>Fri, 29 May 2009 12:00:33 +0000</pubDate>
		<dc:creator>Jesse Freeman</dc:creator>
				<category><![CDATA[Workflow]]></category>

		<guid isPermaLink="false">http://flash.tutsplus.com/?p=776</guid>
		<description><![CDATA[<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/preview_1.jpg" alt="">]]></description>
			<content:encoded><![CDATA[<p>Welcome to an introduction of the <a href="http://code.google.com/p/flash-camouflage/" target="_blank">Flash Camouflage Framework</a>. Flash Camo (for short) is a graphics framework that is broken down into 3 core areas: &quot;Decals&quot;, the &quot;CSS Parser&quot;, and the &quot;CamoDisplay&quot;. These systems can be used individually or combined to fit your needs. When used together they form a powerful set of tools to help skin and style any Flash application. With Camo&#8217;s modular approach, you can use as little or as much of the framework as you want.</p>
<p>In this two part tutorial we&#8217;re going to build a simple website to show how easy it is to incorporate Flash Camo into your next project.</p>
<p><span id="more-776"></span></p>
<div class="tutorial_image">
<a href="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/downloads/camo_tut_pt1_html-template.zip" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/source.jpg" alt="" style="border:none"></a><br />
<a href="http://jessefreeman.com" target="_blank"><br />
<img src="http://flashtuts.s3.cdn.plus.org/demo.jpg" alt="" style="border:none"></a>
</div>
<h2>Preview</h2>
<p>We&#8217;re going to recreate the &quot;Bobble Person Site Launcher&quot; from <a href="http://jessefreeman.com" target="_blank">http://jessefreeman.com</a>.</p>
<div class="tutorial_image">
<a href="http://www.jessefreeman.com/" target="_blank"><img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/1_bobblehead_preview.jpg" alt="1_bobblehead_preview" width="532" height="358"/></a>
</div>
<h2>Step 1: Checkout Flash Camo 2.2</h2>
<p>In this tutorial we&#8217;re going to use Flex Builder. If you haven&#8217;t worked in Flex Builder or need help getting a Flex Library project setup, take a look at my &quot;Flash Development Sandbox Tutorial&quot; (<a href="http://flash.tutsplus.com/tutorials/workflow/setting-up-a-flash-development-sandbox-part-1/" target="_blank">part 1</a> and <a href="http://flash.tutsplus.com/tutorials/workflow/setting-up-a-flash-development-sandbox-part-2/" target="_blank">part 2</a>). This tutorial will also walk you through downloading and setting up Flash Camo from SVN. For this project we&#8217;re going to be using version 2.2 of the framework, you can check it out here:</p>
<p>
<a href="http://flash-camouflage.googlecode.com/svn/tags/FlashCamo_2.2.0_beta">http://flash-camouflage.googlecode.com/svn/tags/FlashCamo_2.2.0_beta</a>
</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/2_flash_camo_svn.jpg" alt="2_flash_camo_svn" width="578" height="340"/>
</div>
<h2>Step 2: Setting Up Our Project</h2>
<p>Create a new project called BobbleHeadApp and make sure you link it to the Flash Camo SWC we checked out in step 1.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/3_new_project.jpg" alt="3_new_project" width="518" height="494"/>
</div>
<p>You will also need the following resource folders to get started. Download them from <a href="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/downloads/camo_tut_pt1_html-template.zip">here</a> and place them in your html-template folder. I&#8217;ve included an updated html-template file linked to swfObject along with the layout of our external resource folders.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/4_bobble_project.jpg" alt="4_bobble_project" width="247" height="342"/>
</div>
<h2>Step 3: Creating a Flash Camo Doc Class</h2>
<p>Now that we have our project and resources set up, let&#8217;s start with our Doc Class (BobbleHeadApp.as). You should replace your doc class with the following code:</p>
<pre name="code" class="javascript">
package
{
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.net.URLRequest;

	[SWF( width="600", height="400", backgroundColor="#3A3E4A", framerate="31" )]

	public class BobbleHeadApp extends Sprite
	{

		private var fontSWF : Loader;

		public function BobbleHeadApp()
		{
			configureStage( );
			loadFonts( );
		}

		private function configureStage() : void
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
		}

		private function loadFonts() : void
		{
			fontSWF = new Loader( );
			fontSWF.contentLoaderInfo.addEventListener( Event.COMPLETE, onFontsLoaded );
			fontSWF.load( new URLRequest( "swfs/fonts/FontLibrary.swf" ) );
		}

		private function onFontsLoaded(event : Event) : void
		{
			fontSWF.contentLoaderInfo.removeEventListener( Event.COMPLETE, onFontsLoaded );
			init( );
		}

		protected function init() : void
		{
			trace( "Hello World" );
		}
	}
}
</pre>
<p>Sometimes when testing local files you may see the following error:</p>
<p><em><br />
Error #2044: Unhandled SecurityErrorEvent:. text=Error #2140: Security sandbox violation: &#8230; Local-with-filesystem and local-with-networking SWF files cannot load each other.</em>
</p>
<p>If this happens to you, add the following &quot;-use-network=false&quot; in your projects compiler Arguments. This will circumvent any Security Sandbox issues you may get while locally testing.</p>
<p>Now you should be ready to compile the swf and take a look at the output window. You will see &quot;Hello World&quot;:</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/5_hello_world.jpg" alt="5_hello_world" width="600" height="94"/>
</div>
<p>If you check your browser&#8217;s connections the font swf should have been loaded:</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/6_connections.jpg" alt="6_connections" width="592" height="198"/>
</div>
<h2>Step 4: Creating a Global PropertySheet Manager</h2>
<p>We&#8217;re going to need a central place to store and access our css properties. Before we do this let&#8217;s talk about the CamoPropertySheet. You may have used CSS with Flash in the past but this is something completely new and unique to Flash Camo. Camo&#8217;s custom CSS parser, the &quot;CamoPropertySheet&quot; (found inside of the &quot;camo.core.property&quot; package), goes well beyond the native StyleSheet class by supporting style inheritance, pseudo selectors and merging styles on the fly. The goal of the CamoPropertySheet is to make styles something you can apply to any of your classes instead of just TextFields. CSS is a great way to define your class&#8217;s properties in an external file and Camo helps convert these css styles into property/value pairs you can apply to any Object. Camo also has a CamoPropertySheetManager (found inside of the &quot;camo.core.managers&quot; package) class for handling multiple CamoPropertySheets in one application.</p>
<p>Since we will need all of our classes to have access to the CamoPropertySheetManager we&#8217;re going to create a <a href="http://en.wikipedia.org/wiki/Singleton_pattern" target="_blank">Singleton</a>. This Singleton will enforce one instance of our CamoPropertySheetManager. I&#8217;m not a big fan of Singletons, but in situations like this they&#8217;re a necessary evil. We&#8217;ll need a single class instance in charge of managing and returning requested PropertySelectors. I will explain later what a ProperySelector is and how it will function in our application.</p>
<p>Let&#8217;s create a new class called &quot;GlobalPropertySheetManager&quot; and put it in the &quot;com.jessefreeman.managers&quot; package.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/7_create_global_pms.jpg" alt="7_create_global_pms" width="481" height="444"/>
</div>
<p>Here is the class&#8217;s code:</p>
<pre name="code" class="javascript">
package com.jessefreeman.managers
{
	import camo.core.managers.CamoPropertySheetManager;

	public class GlobalPropertySheetManager
	{

		public static const INIT : String = "init";
		private static var __instance : CamoPropertySheetManager;

		public function GlobalPropertySheetManager(enforcer : SingletonEnforcer)
		{
			if (enforcer == null)
			{
				throw new Error( "Error: Instantiation failed: Use GlobalDecalSheetManager.instance instead." );
			}
		}

		public static function get instance() : CamoPropertySheetManager
		{
			if(GlobalPropertySheetManager.__instance == null)
			{
				GlobalPropertySheetManager.__instance = new CamoPropertySheetManager( );
			}
			return GlobalPropertySheetManager.__instance;
		}
	}
}

internal class SingletonEnforcer
{
}
</pre>
<p>There are many ways to create a Singleton and the discussion is a little out of scope of this tutorial. Let&#8217;s quickly talk about what is happening here. Since ActionScript 3 classes are unable to have private constructors there is no way to hide the constructor of a class. Instead of allowing the class to be created through the usual &quot;new&quot; construction we will enforce calling the GlobalPropertySheetManager.instance to get a reference to the class. The instance getter checks to see if the class has already been created, if the class doesn&#8217;t exist it creates a new CamoPropertySheetManager. If the instance exists it will return a reference to that instance. This ensures that we only have 1 instance of the CamoPropertySheetManager in our entire application. Now we&#8217;re ready to start loading in our CSS.</p>
<h2>Step 5: Loading PropertySheet CSS</h2>
<p>The CamoPropertySheetManager has no way to load CSS, instead we&#8217;ll supply the load mechanism and tell it to parse the loaded data. We&#8217;ll start by creating our load method by making use of the URLLoader. Add the following methods to our Doc Class after the &quot;onFontsLoaded&quot; function:</p>
<pre name="code" class="javascript">
private function loadPropertySheet() : void
{
	trace( "Loading CSS" );

	propSheet = GlobalPropertySheetManager.instance;

	var loader : URLLoader = new URLLoader( );
	loader.addEventListener( Event.COMPLETE, onPropertySheetLoad );
	loader.load( new URLRequest( "css/main.properties.css" ) );
}

private function onPropertySheetLoad(event : Event) : void
{

	var target : URLLoader = event.target as URLLoader;
	target.removeEventListener( Event.COMPLETE, onPropertySheetLoad );

	propSheet.parseCSS( "global.properties", target.data );

	trace( "PropertySheetSelectors", propSheet.getPropertySheet( "global.properties" ).selectorNames );

	init( );
}
</pre>
<p>You will also need to add the following properties to the Doc Class:</p>
<pre name="code" class="javascript">
private var propSheet : CamoPropertySheetManager;
</pre>
<p>Then import the following classes:</p>
<pre name="code" class="javascript">
import flash.net.URLLoader;
import camo.core.managers.CamoPropertySheetManager;
import com.jessefreeman.managers.GlobalPropertySheetManager;
</pre>
<p>Finally, we&#8217;ll just alter our onFontsLoaded method to call loadPropertySheet by replacing:</p>
<pre name="code" class="javascript">init( );</pre>
<p>with:</p>
<pre name="code" class="javascript">loadPropertySheet();</pre>
<p>Since the URLLoader can load in any text file, we simply load in our own custom CSS then pass it off to the CamoPropertySheetManager instance that we got from the GlobalPropertySheetManager. Notice how we called &quot;parseCSS&quot; and passed in a name for our PropertySheet along with the string data we just loaded. That&#8217;s all you need to do in order to have Camo parse your css. Later we&#8217;ll talk about how we get our styles out, but here is a little more info on the PropertySheet system in camo.</p>
<p>Once the CSS is parsed, you can retrieve an Array of selector names by calling the &quot;selectedNames&quot; getter. A selector represents the name of the particular CSS style and its collection of values. The &quot;getSelector&quot; method will return the selector and its properties as a &quot;PropertySelector&quot;. New selectors can be added to the CamoPropertySheet by calling &quot;newSelector&quot; and passing a selector name and a PropertySelector instance. Finally, you can duplicate a CamoPropertySheet by calling the &quot;clone&quot;. We&#8217;ll cover this more as we start to build out our components.</p>
<h2>Step 6: Testing The CSS Parser</h2>
<p>Now is a good time to test that our CSS parser works. Let&#8217;s open up the css file in &quot;html-tempalte/css/main.properties.css&quot; and add the following style:</p>
<pre name="code" class="css">
.TestStyle
{
	x: 100px;
	y: 100px;
	width: 100px;
	height: 100px;
	background-color: #ff0000;
	border: 1px solid #000000;
}
</pre>
<p>If you&#8217;re working in Flex Builder and modify files in your html-template folder you will need clean the project. You can do this by going to Project &gt; Clean&#8230; and selecting the projects you want to clean. When you clean a project, it makes a fresh copy of the html-template folder over to the bin folder. Let&#8217;s say you modify something in html-template then add a new line of code. Flex Builder automatically preforms a clean. This situation only happens when you edit a file in html-template and do not do a clean. Trust me, this step will save you countless hours of frustration trying to figure out why your changes are not showing up in the browser. I usually map the clean project action to option + command + c since I use it so much.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/8_clean_menu.jpg" alt="8_clean_menu" width="242" height="197"/>
</div>
<p>Now if you recompile the swf and look at the output you should see the name &quot;.TestStyle&quot; selector name next to the &quot;PropertySheetSelectors&quot; trace.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/9_teststyle_trace.jpg" alt="9_teststyle_trace" width="290" height="149"/>
</div>
<p>Let&#8217;s try to retrieve our style and trace it out. Replace:</p>
<pre name="code" class="javascript">
trace( "PropertySheetSelectors", propSheet.getPropertySheet( "global.properties" ).selectorNames );
</pre>
<p>inside of onCSSLoad from our Doc Class with this:</p>
<pre name="code" class="javascript">
trace( "Test Selector", propSheet.getSelector(".TestStyle"));
</pre>
<p>Now when you compile you should see the following:</p>
<pre name="code" class="javascript">Test Selector .TestStyle{x:100;height:100background-color:#ff0000;border:1 solid #000000;selectorName:.TestStyle;y:100;width:100;}</pre>
<p>This is the string value of our PropertySelector. Looks like an object right? Well that&#8217;s because it is! Camo&#8217;s css parser converts css selectors into native objects. It is important to note that each value is still a string. Later we will talk about how to convert these strings into natively typed values so you can apply them to any object or class in your application. Let&#8217;s start building the foundation for our project.</p>
<h2>Step 7: Creating an AbstractComponent</h2>
<p>
Now we&#8217;re ready to start building our components. We want all of our components to inherit the ability to automatically find their own CSS style. If you&#8217;re not familiar with what an Abstract Class is, you may be surprised to hear that you might already be using them. </p>
<blockquote><p>
A simple explanation of an Abstract class is any class you create that has some core functions but has to be extended to added specific functionality.
</p></blockquote>
<p>Abstract Classes, much like our Singleton, should not be directly instantiated. Think of Abstract class as Interfaces but with code in them. We&#8217;re simply setting up a few functions all components will need and each component will add the additional logic they require. We&#8217;re going to call our Abstract Class &quot;AbstractComponent&quot; and put it in the &quot;com.jessefreeman.components&quot; package. </p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/10_create_abstract_comp.jpg" alt="10_create_abstract_comp" width="443" height="473"/>
</div>
<p>Let&#8217;s take a look at the code:</p>
<pre name="code" class="javascript">
package com.jessefreeman.components
{
	import camo.core.display.CamoDisplay;
	import camo.core.property.PropertySelector;

	import com.jessefreeman.managers.GlobalPropertySheetManager;

	import flash.errors.IllegalOperationError;

	public class AbstractComponent extends CamoDisplay
	{

		protected static const ID_DELIMITER : String = " ";
		protected var defaultSelectorNames : Array;

		public function AbstractComponent(self : AbstractComponent, id : String)
		{
			if(self != this)
			{
				//only a subclass can pass a valid reference to self
				throw new IllegalOperationError( "Abstract class did not receive reference to self. " + className + " cannot be instantiated directly." );
			}
			else
			{
				parseStyleNames( id );
				init( );
			}
		}

		protected function parseStyleNames(id : String) : void
		{
			defaultSelectorNames = id.split( ID_DELIMITER );
			this.id = defaultSelectorNames.pop( );
			// clean up selectors
			defaultSelectorNames.unshift( "." + className );
			defaultSelectorNames.push( "#" + this.id );
		}

		protected function init() : void
		{
			var prop : PropertySelector = GlobalPropertySheetManager.instance.getSelector.apply( null, defaultSelectorNames );

			applyProperties( prop );
		}
	}
}
</pre>
<p>Even though this is a small class there&#8217;s a lot going on. Let&#8217;s start with the fact that it&#8217;s extending the CamoDisplay. Normally we would extend Sprite or MovieClip for our display classes but because we want to take advantage of Flash Camo&#8217;s BoxModel we need to build off of the CamoDisplay. We&#8217;ll talk about the BoxModel and CamoDisplay a little later.</p>
<p>If you check out the constructor you will notice we&#8217;re requesting two items, self and id. As we go through the constructor we do a verification that the class can only be instantiated by passing a reference of itself back into the constructor. You will see how this works with our &quot;concrete&quot; components (a concrete class is any fully functional class that extends an Abstract class). The other property id is important because we will be using that to look up the component&#8217;s id from css. Once the Abstract validation has passed, we call the parseStyleName method.</p>
<p>
The parseStyleNames method is doing something special for us. If you have worked in html and css you may know that you can overload a ID or Class tag by supplying multiple CSS selector names separated by a space. In this method we allow you to add multiple IDs separated by a space and we parse them out into individual ids. The last ID becomes the main ID for the class and we add a &quot;#&quot; to it automatically. We also add the class&#8217;s name, from a getter of the CamoDisplay called &quot;className&quot;, to our list of selector names. Let&#8217;s look at the init function next to see how we use this.
</p>
<p> In the init function we&#8217;re doing two things; getting our selectors from the GlobalPropertySheetManager and then applying the css properties to the component itself through the applyProperties method. Take a look at how we&#8217;re calling the getSelector method on the GlobalPropertySheetManager. This part may make your head explode but don&#8217;t worry, I guarantee that at the end of the next few steps your code will compile and run fine whether or not you fully understand what&#8217;s going on.</p>
<p>First off, we want to get an instance of the CamoPropertySheetManager so we call the GlobalPropertySheetManager&#8217;s instance property. Remember this is a Singleton and we only have one instance of the CamoPropertySheetManager. Next we&#8217;re calling its function &quot;getSelector&quot; but instead of passing in the names of each selector we&#8217;re calling a function of the &quot;getSelector&quot; function. I know this is crazy but it is something built into the language. See &quot;getSelector&quot; is a rest function in Flash. This is a function that does not have a set number of parameters so you can pass in as many items as you want. Here is what the function actually looks like in the source code:</p>
<pre name="code" class="javascript">
public function getSelector( ... selectorNames) : PropertySelector
</pre>
<p>See the &quot;&#8230; selectorNames&quot;? That tells the function you will get any amount of selector names, so be prepared. Since we can&#8217;t just pass an array into the &quot;getSelector&quot; method (because it would simply see it as 1 array variable) we have to call a special function called &quot;apply&quot; to pass in an array of arguments. The moral of the story is that you can pass in as many selector names as you want into the &quot;getSelector&quot; function and the CSS parser will merge them all into a single PropertySelector. If you want to understand more about rest statements in Flash check <a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/Function.html" target="_blank">this</a> out.</p>
<p>Now that&#8217;s out of the way, let&#8217;s look at an example to illustrate what this class will do.</p>
<h2>Step 8: Testing The AbstractComponent</h2>
<p>We&#8217;re going to perform a quick test to show how the AbstractComponent and BoxModel inside of the CamoDisplay work. Create a class called &quot;SimpleDisplay&quot; in the &quot;com.jessefreeman.components&quot; package.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/11_create_simple_display.jpg" alt="11_create_simple_display" width="545" height="473"/>
</div>
<p>Here is the class&#8217;s code:</p>
<pre name="code" class="javascript">
package com.jessefreeman.components
{

	public class SimpleDisplay extends AbstractComponent
	{

		public function SimpleDisplay(id : String = "BoxModelDisplay")
		{
			super( this, id );
		}
	}
}
</pre>
<p>This is a very simple class, it just extends the AbstractComponent and passes a reference of itself up to super (in order to pass the AbstractComponent validation) and also passes up its id. Let&#8217;s test it out by going back to our Doc Class and adding the following after our Hello World trace inside of the &quot;init&quot; function:</p>
<pre name="code" class="javascript">
var component:SimpleDisplay = new SimpleDisplay("BoxModelDisplay");
addChild(component);
</pre>
<p>and import:</p>
<pre name="code" class="javascript">import com.jessefreeman.components.SimpleDisplay</pre>
<p>Now if you compile the swf, you won&#8217;t see anything, but the SimpleDisplay instance is there. Go into your CSS file and change the name of the &quot;.TestStyle&quot; to &quot;.SimpleDisplay&quot;. Now recompile and you should see your SimpleDisplay.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/12_boxmodel_test.jpg" alt="12_boxmodel_test" width="199" height="174"/>
</div>
<p>Amazing, right? The SimpleDisplay automatically found its CSS Class name and applied its values. Any instance of the SimpleDisplay will automatically apply the &quot;.SimpleDisplay&quot; CSS Style to itself now. Let&#8217;s add the following style to our CSS sheet:</p>
<pre name="code" class="css">
#BoxModelDisplay
{
	background-color: #00ff00;
	border-top: 10px;
}
</pre>
<p>Now when you compile you&#8217;ll see that the ID of the Component is overriding the base class style.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/13_boxmodel_test_2.jpg" alt="13_boxmodel_test_2" width="200" height="177"/>
</div>
<p>This is a very powerful way to customize the look and feel of your application. Now you can use CSS to style any class that extends the AbstractComponent. This is all made possible by Camo&#8217;s BoxModelDisplay. The &quot;BoxModelDisplay&quot; allows us to apply Margin, Padding, Border and a Background (Color/Image). Camo&#8217;s BoxModel works exactly like CSS&#8217;s. Here is a diagram:</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/14_box_model.jpg" alt="14_box_model" width="328" height="258"/>
</div>
<p>As you may recall, our AbstractComponent extended the CamoDisplay which in turn extends the BoxModel. Well, the CamoDisplay not only inherits all of the BoxModel&#8217;s layout but it also adds a few extra features. You can read about all of the BoxModel and CamoDisplay&#8217;s properties in the docs folder of your Flash Camo checkout.</p>
<h2>Step 9: LabelComponent</h2>
<p>We&#8217;re going to create a simple component that will handle all of the text labels we need in our application. This is also a good component to help illustrate how the ProperySelector works. To get started, create a new class called &quot;Label&quot; in &quot;com.jessefreeman.components&quot; package.
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/15_create_label.jpg" alt="15_create_label" width="552" height="481"/>
</div>
</p>
<p> Here is the code:</p>
<pre name="code" class="javascript">
package com.jessefreeman.components
{
	import camo.core.enum.CSSProperties;

	import flash.text.StyleSheet;
	import flash.text.TextField;
	import flash.text.TextFormat;

	public class Label extends AbstractComponent
	{

		protected var _styleSheet : StyleSheet;
		protected var textField : TextField = new TextField( );
		protected var proxyTextFormat : TextFormat = new TextFormat( );
		protected var _textAlign : String = CSSProperties.LEFT;

		public function set autoSize(value : String) : void
		{
			textField.autoSize = validateAutoSize( value );
			invalidate( );
		}

		public function set antiAliasType(value : String) : void
		{
			textField.antiAliasType = validateAntiAliasType( value );
			invalidate( );
		}

		public function set embedFonts(value : Boolean) : void
		{
			textField.embedFonts = value;
			invalidate( );
		}

		public function set sharpness(value : Number) : void
		{
			textField.sharpness = value;
			invalidate( );
		}

		public function get text() : String
		{
			return textField.text;
		}

		public function set text(value : String) : void
		{
			textField.text = value;
			invalidate( );
		}

		public function set textAlign(value : String) : void
		{
			_textAlign = value;
			invalidate( );
		}

		public function set textFieldWidth(value : Number) : void
		{
			textField.width = value;
			invalidate( );
		}

		public function set textFieldHeight(value : Number) : void
		{
			textField.height = value;
			invalidate( );
		}

		public function set textFieldAlign(value : String) : void
		{
			proxyTextFormat.align = value;
			invalidate( );
		}

		public function set fontFace(value : String) : void
		{
			font = value;
			invalidate( );
		}

		public function set fontSize(value : Number) : void
		{
			size = value;
			invalidate( );
		}

		public function set font(value : String) : void
		{
			proxyTextFormat.font = value;
			invalidate( );
		}

		public function set color(value : uint) : void
		{
			proxyTextFormat.color = value;
			invalidate( );
		}

		public function set size(value : Number) : void
		{
			proxyTextFormat.size = value;
			invalidate( );
		}

		public function set letterSpacing(value : Number) : void
		{
			proxyTextFormat.letterSpacing = value;
			invalidate( );
		}

		public function Label( id : String = "label" )
		{
			super( this, id );
		}

		override protected function init() : void
		{
			textField.selectable = false;
			textField.autoSize = "left";
			addChild( textField );
			super.init( );
		}

		override protected function draw() : void
		{
			proxyTextFormat.align = _textAlign;
			textField.defaultTextFormat = proxyTextFormat;
			textField.setTextFormat( proxyTextFormat );
			super.draw( );
		}

		public function setTextFormat(format : TextFormat, beginIndex : int = - 1, endIndex : int = - 1) : void
		{
			textField.setTextFormat( format, beginIndex, endIndex );
		} 

		public static function validateAntiAliasType(value : String) : String
		{
			switch (value)
			{
				case CSSProperties.ADVANCED:
					return value;
					break;
				default:
					return CSSProperties.NORMAL;
					break;
			}
		}

		public static function validateAutoSize(value : String) : String
		{
			switch (value)
			{
				case CSSProperties.LEFT:
				case CSSProperties.RIGHT:
				case CSSProperties.CENTER:
					return value;
					break;
				default:
					return CSSProperties.NONE;
					break;
			}
		}
	}
}</pre>
<p>As you can see, this label component functions like a TextField through <a href="http://www.adobe.com/devnet/actionscript/articles/oop_as3_03.html" target="_blank">composition</a>. I do this by creating a instance of a TextField and uses setters to update its values. This may seem like over-kill, but by doing things this way I take advantage of two features from Flash Camo. First off I extend the AbstractDisplay &gt; CamoDisplay &gt; BoxModelDisplay set of classes so I get CSS styling and BoxModel for &quot;free&quot;. Also, I no longer need to create a separate TextFormat to style the TextField and apply it each time there&#8217;s a change. This component allows me to simply apply TextFormat properties and it automatically updates the TextField instances properties. This is important when we look at how PropertySelectors are applied.</p>
<p>I have already shown you how our AbstractComponent automatically applies css styles to our components but let&#8217;s look at what goes on behind the scenes in the CamoDisplay when we call &quot;applyProperties&quot;. Here&#8217;s what the code looks like:</p>
<pre name="code" class="javascript">
public function applyProperties(style: PropertySelector):void
{
	clearProperties();

	PropertyApplierUtil.applyProperties(this, style);

	invalidate();
}
</pre>
<p>A few things are going on here. First, all properties are cleared from the CamoDisplay. Next, we use a utility class called PropertyApplierUtil to apply a PropertySelector to the CamoDisplay instance. I mentioned earlier that PropertySelectors are Objects created from CSS selectors. Well the values of the object are strings, but we will need a way to convert a font&#8217;s size to a number. This utility automates the process by analyzing the value types of a class&#8217;s public variables and getters, then converts the matching PropertySelector&#8217;s values to the correct type. Here is an example.</p>
<p>Let&#8217;s say you want to set the font size on our Label component. You may have a style that looks like this:</p>
<pre name="code" class="css">
.Label
{
	size: 30;
}
</pre>
<p>When you apply the &quot;.Label&quot; PropertySelector to the Label instance (remember this is done automatically for us) the PropertyApplierUtil looks for a property called &quot;size&quot; on the Label instance. Once it finds it, it checks the properties value. Since we have a getter called size that accepts a number value, the utility will automatically convert the PropertySelector&#8217;s size value into a number and set it on our component. You don&#8217;t have to do anything special, the utility natively handles Strings, Number, Arrays, Objects, Colors (units) and a few other types. As long as your public variable has a type the utility can convert, any matching properties will automatically be set. We will see this in action in the next step.</p>
<h2>Step 10: Using the Label Component</h2>
<p>Let&#8217;s go into our Doc Class and replace our SimpleDisplay demo by replacing the init function with the following:</p>
<pre name="code" class="javascript">
protected function init() : void
{
	trace( "Hello World" );
	createLabel();
}
</pre>
<p>Then create a new function under our init function:</p>
<pre name="code" class="javascript">
private function createLabel() : void
{
	label = new Label( "siteLabel" );
	addChild( label );
}
</pre>
<p>Don&#8217;t forget to add the following parameter:</p>
<pre name="code" class="javascript">
private var label : Label;
</pre>
<p>As well as our import:</p>
<pre name="code" class="javascript">
import com.jessefreeman.components.Label;
</pre>
<p>Finally, we&#8217;ll need to add the following styles to our css file:</p>
<pre name="code" class="css">
.Label
{
	font: Arial Black;
	size: 20px;
	embedFonts: true;
	color: #ffffff;
	anti-alias-type: advanced;
}

#siteLabel
{
	text: ANATOMY OF JESSE FREEMAN;
	x: 155;
	y: 60;
	size: 18px;
	rotation: 24px;
	letter-spacing: -2;
	text-height: 30px;
	alpha: .5;
}
</pre>
<p>Now if you compile the swf you should see your label with the text &quot;ANATOMY OF JESSE FREEMAN&quot;.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/16_label_preview.jpg" alt="16_label_preview" width="486" height="225"/>
</div>
<p>The label automatically used &quot;.Label&quot; along with &quot;#siteLabel&quot; and styled itself. See how easy that was? A few lines of code, some CSS and we&#8217;re up and running in no time.</p>
<p>Now you have a reusable Label Component that can by styled with css. This class is by no means finished. You can continue to add as many getters or setters as you need to make this Label fully customizable. I simply provided you a base to get started with. As you begin to extend off the framework it&#8217;s important to understand some of the underlying draw logic.</p>
<h2>Step 11: CamoDisplay Invalidation</h2>
<p>You may have noticed from our Label component that the &quot;invalidate()&quot; method is called after we change a value in any of the setters. Redrawing the BoxModel and display is very expensive so to help alleviate the burden of constantly refreshing the display, the CamoDisplay waits until the next frame to redraw itself. This technique is used in Adobe&#8217;s own components and is very efficient in cutting down on waisted cpu processes. It is something you should keep in mind when extending the CamoDisplay and using invalidate on your own custom setters.</p>
<p>The other important method you should know about is &quot;draw()&quot;. After the display has been invalidated and a new frame is being rendered by the Flash Player, draw gets called automatically by the CamoDisplay. If you have custom display logic this is the best place to put it. Once &quot;draw&quot; is called, the invalidate flag is reset and the CamoDisplay will not redraw itself until it is invalidated again.</p>
<p>If you are doing complex animations like changing the width and height or require constant updates, you can override the invalidation by calling &quot;refresh()&quot; at any time. This will immediately force the CamoDisplay to redraw. Use this when you need to have constant display updates since it can become very intensive to render.</p>
<h2>Step 12: Create A Bobble Container</h2>
<p>We&#8217;re going to create a class called &quot;BobbleContainer&quot; in &quot;com.jessefreeman.components&quot; package</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/17_create_bobble_container.jpg" alt="17_create_bobble_container" width="543" height="475"/>
</div>
<p>Here&#8217;s the code:</p>
<pre name="code" class="javascript">
package com.jessefreeman.components
{
	import com.jessefreeman.components.AbstractComponent;

	import flash.events.IEventDispatcher;
	import flash.events.MouseEvent;

	public class BobbleContainer extends AbstractComponent
	{

		protected var _active : Boolean;
		public var rollOverForce : Number = 1;
		public var noddingForce : Number = 0;
		public var noddingAngle : Number = 0;
		public var noddingRange : Number = 30;
		public var noddingHit : Number = .7;
		public var noddingDamp : Number = .985;

		public function BobbleContainer(id : String = "bobbleContainer")
		{
			super( this, id );
		}

		public function set active(value : Boolean) : void
		{
			_active = value;
			if(_active)
				addEventListeners( this );
			else
				removeEventListeners( this );
		}

		public function get active() : Boolean
		{
			return _active;
		}

		override protected function init() : void
		{
			super.init( );
		}

		protected function addEventListeners(target : IEventDispatcher) : void
		{
			target.addEventListener( MouseEvent.ROLL_OVER, onRollOver );
			target.addEventListener( MouseEvent.ROLL_OUT, onRollOut );
		}

		protected function removeEventListeners(target : IEventDispatcher) : void
		{
			target.removeEventListener( MouseEvent.ROLL_OVER, onRollOver );
			target.removeEventListener( MouseEvent.ROLL_OUT, onRollOut );
		}

		public function calculateBobble() : void
		{
			if (noddingForce)
			{
				if(noddingForce < .05)
					noddingForce = 0;
				rotation = Math.sin( noddingAngle ) * noddingForce * (noddingRange * .5);

				noddingAngle += noddingHit * noddingForce;
				noddingForce *= noddingDamp;
			}
		}

		protected function onRollOver(event : MouseEvent) : void
		{
			if(noddingForce < (rollOverForce * .5))
			{
				noddingAngle = 0;
				noddingForce = rollOverForce;
			}
		}

		protected function onRollOut(event : MouseEvent) : void
		{
		}
	}
}
</pre>
<p>In our Doc Class, let's create a BobbleContainer instance to test our code with. Let's add the following function below createLabel:</p>
<pre name="code" class="javascript">
protected function createPerson() : void
{
	bobbleTest = new BobbleContainer("TestContainer");
	addChild(bobbleTest);
}
</pre>
<p>You will need the following property:</p>
<pre name="code" class="javascript">
private var bobbleTest : BobbleContainer;
</pre>
<p>then import:</p>
<pre name="code" class="javascript">
import com.jessefreeman.components.BobbleContainer;
</pre>
<p>In order to get this to work we will need to add a few more things. In our init function add the following:</p>
<pre name="code" class="javascript">
createPerson();
addEventListener( Event.ENTER_FRAME, onEnterFrame );
</pre>
<p>Below the init function add:</p>
<pre name="code" class="javascript">
private function onEnterFrame(event : Event) : void
{
	bobbleTest.calculateBobble();
}
</pre>
<p>We're almost done. Add the following to your CSS file and hit compile:</p>
<pre name="code" class="css">
.BobbleContainer
{
	active: true;
	rollOverForce: 1;
	roll-over-force: 1;
	nodding-force: 0;
	nodding-angle: 0;
	nodding-range: 10;
	nodding-hit: .7;
	nodding-damp: .985;
}

.SimpleDisplay #TestContainer
{
	border: 4 solid white;
}
</pre>
<p>You should now be looking at a red box with a white border which bobbles when you move your mouse cursor over it.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/18_bobble_test.jpg" alt="18_bobble_test" width="377" height="230"/>
</div>
<p>Now that I've fully introduced Flash Camo's CSS parser I'm going to refer to it as Properties/Property Sheet instead of CSS from this point on. You're encouraged to think of Camo's PropertySheets as a natural extension of configuring the property values of your classes. Go ahead and change the values of the &quot;nodding-range&quot; or the &quot;nodding-hit&quot; to see how it works. Imagine configuring your entire application without having to recompile! Not only that but you can simply restyle an app by pointing it to a new PropertySheet.</p>
<p>Before we go, let's take a look at one last thing. Notice in our PropertySheet the &quot;.SimpleDisplay #TestContainer&quot; selector. Flash Camo supports selector inheritance. We refer to &quot;#TestContainer&quot; as the subject and &quot;.SimpleDisplay&quot; would be an ancestor element. If you were to call &quot;getSelector&quot; for &quot; #TestContainer&quot; the parser will automatically return a PropertySelector with properties from &quot;.SimpleDisplay&quot; and &quot;#TestContainer&quot; merged together. Any conflicting properties will be overridden by the subject style. Pretty cool right?</p>
<h2>Step 13: Bobble Person</h2>
<p>Now we're ready to create a class that will manage our BobbleContainer body parts. Let's create a Class called &quot;BobblePerson&quot; in the &quot;com.jesseFreeman.components&quot; package.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/19_create_bobble_person.jpg" alt="19_create_bobble_person" width="549" height="479"/>
</div>
<p>Here's the code:</p>
<pre name="code" class="javascript">
package com.jessefreeman.components
{
	import com.jessefreeman.components.AbstractComponent;

	public class BobblePerson extends AbstractComponent
	{

		protected var _partIds : Array = new Array( );
		protected var partInstances : Array = new Array( );
		public var partDisplayId : String;

		public function set partIds(value : Array) : void
		{
			_partIds = value;
			createParts( );
		}

		public function BobblePerson(id : String = "BobblePerson")
		{
			super( this, id );
		}

		public function get partDisplay() : BobbleContainer
		{
			var index : int = _partIds.indexOf( partDisplayId );

			return (index != - 1) ? partInstances[index] : null;
		}

		override protected function init() : void
		{
			super.init( );
		}

		public function createParts() : void
		{
			var total : int = _partIds.length;
			var i : int;
			var part : BobbleContainer;
			var partID : String;

			for (i = 0; i < total ; i ++)
			{
				partID = _partIds[i];
				part = new BobbleContainer( partID );
				addChild( part );
				partInstances.push( part );
			}
		}

		public function calculateBobble() : void
		{
			var total : int = partInstances.length;
			for (var i : int = 0; i < total ; i ++)
			{
				BobbleContainer( partInstances[i] ).calculateBobble( );
			}
		}
	}
}
</pre>
<p>As you can see here, we have a few methods revolving around setting up, creating and updating body parts. This class creates parts once the partIds setter is given a value. We're doing this through a setter because we will be using our PropertySheet to pass in the array of parts. Once we have a list of parts the createParts method is called. It loops through the partIds Array and creates new instances of the BobbleContainer. Each container is given an ID then pushed into an array called partInstances so we can keep track of all of the parts.</p>
<p>Our final function is for updating the parts. Remember the enter frame loop we set up in the Doc Class that updated the demo BobbleContainer? We'll connect that loop to the BobblePerson's calculateBobble method and it will manage calling calculateBobble on each of our parts. This way we only have one enter frame loop running in our app at any time.</p>
<p>Now we're ready to set this class up. Let's replace a few things in our Doc Class in order get our BobblePerson up and running. Start by replacing your &quot;createPerson&quot; method with the following:</p>
<pre name="code" class="javascript">
protected function createPerson() : void
{
	bobblePerson = new BobblePerson( "BobblePerson" );
	addChild( bobblePerson );
}
</pre>
<p>Next do a find and replace for &quot;bobbleTest&quot; with &quot;bobblePerson&quot;.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/20_find_and_replace.jpg" alt="20_find_and_replace" width="353" height="462"/>
</div>
<p>Then replace:</p>
<pre name="code" class="javascript">private var bobblePerson : BobbleContainer;</pre>
<p>with:</p>
<pre name="code" class="javascript">private var bobblePerson : BobblePerson;</pre>
<p>Make sure you also import:</p>
<pre name="code" class="javascript">
import com.jessefreeman.components.BobblePerson;
</pre>
<p>Finally, you'll need to replace your entire PropertySheet file with the following:</p>
<pre name="code" class="css">
/* CSS file */

.BobblePerson
{
	part-ids: head body leftArm rightArm leftLeg leftFoot rightLeg;
	part-display-id: body;
}

.Label
{
	font: Arial Black;
	size: 20px;
	embedFonts: true;
	color: #ffffff;
	anti-alias-type: advanced;
}

#siteLabel
{
	text: ANATOMY OF JESSE FREEMAN;
	x: 155;
	y: 60;
	size: 18px;
	rotation: 24px;
	letter-spacing: -2;
	text-height: 30px;
	alpha: .5;
}

.BobbleContainer
{
	active: true;
	rollOverForce: 1;
	roll-over-force: 1;
	nodding-force: 0;
	nodding-angle: 0;
	nodding-range: 10;
	nodding-hit: .7;
	nodding-damp: .985;
	background-color: silver;
	background-color-alpha: .5;
}

#body
{
	x: 355;
	y: 229;
	width: 181;
	height: 144;
}

#head
{
	x: 449;
	y: 250;
	width: 139;
	height: 143;
}

#leftArm
{
	x: 381;
	y: 313;
	width: 195;
	height: 80;
}

#leftFoot
{
	x: 145;
	y: 213;
	width: 127;
	height: 80;
}

#leftLeg
{
	x: 263;
	y: 235;
	width: 125;
	height: 80;
}

#rightArm
{
	x: 419;
	y: 176;
	width: 184;
	height: 125;
}

#rightLeg
{
	x: 275;
	y: 176;
	width: 218;
	height: 171;
}
</pre>
<p>If you do a quick compile you'll see a bunch of semi-transparent boxes overlapping each other, which bounce when you roll your mouse over them.</p>
<div class="tutorial_image">
<img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/21_body_demo.jpg" alt="21_body_demo" width="552" height="384"/>
</div>
<p>We have the beginnings of our website. Next up we'll add Labels to each of the parts so we can keep track of them.</p>
<h2>Step 14: Adding Labels to BobbleContainers</h2>
<p>Let's go into our BobbleContainer class and add the following function after init:</p>
<pre name="code" class="javascript">
protected function createLabel() : void
{
	label = new Label( id + "Label" );
	addChild( label );
}
</pre>
<p>Next modify the init function by adding the following:</p>
<pre name="code" class="javascript">
createLabel( );
</pre>
<p>above :</p>
<pre name="code" class="javascript">
super.init( );
</pre>
<p>You'll also need to create the following property:</p>
<pre name="code" class="javascript">
public var label : Label;
</pre>
<p>And import our Label class:</p>
<pre name="code" class="javascript">
import com.jessefreeman.components.Label;
</pre>
<p>As you can see we're creating our new label and using the parent class's &quot;id + &ldquo;Label&rdquo;&quot; for the id. This allows us to give a unique id to each label created, yet still allows us to style each one via its Class Name. Let's add the following to our PropertySheet:</p>
<pre name="code" class="css">
/* BobbleContainer Labels */

#bodyLabel
{
	alpha: 1;
	rotation: 20;
	x: -35;
	y: -30;
	text-align: center;
	auto-size: center;

}

#leftArmLabel
{
	text: bFreeDesign;
	x:  -90;
	y: 25;
	rotation: -9;
	size: 18;
	letter-spacing: -3;
}

#leftFootLabel
{
	text: eMail;
	x: -78;
	y: -13;
	rotation: 6;
}

#leftLegLabel
{
	text: FlashBum;
	x: -95;
	y: -40;
	rotation: 9;
}

#rightArmLabel
{
	text: FlashArtOfWar;
	x: -80;
	y: -75;
	rotation: 32;
	font-size: 16;
	letter-spacing: -1;
}

#rightLegLabel
{
	text: iLikeToDream;
	x: -157;
	y: -83;
	rotation: 27;
}
</pre>
<p>Now if you compile you'll see that all of our Labels are working and are getting configured by CSS!</p>
<p><img src="http://flashtuts.s3.cdn.plus.org/032_CamoPart1/images/22_body_demo_2.jpg" alt="22_body_demo_2" width="591" height="394"/></p>
<h2>To Be Continued..</h2>
<p>We've gone over a lot of stuff in this first tutorial. It's best that we take a break and let it all soak in. Next we'll go over how to skin our BobbleContainer using Decals, add some interactivity, optimize/clean up the code and talk about deployment. Stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://active.tutsplus.com/tutorials/workflow/intro-to-flash-camo-part-1/feed/</wfw:commentRss>
		<slash:comments>21</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 0.900 seconds -->
