Categories Displayed in Flash

Archive for the 'view' Category

Flash: Fast Prototyping and Sketching UI with FlowControl

While I enjoy the new power of Flash9/AS3.0, one of the things I really dislike about the AS3, is how much extra work to do basic things like setup buttons to do simple timeline control, this is especially hard on designers and animators who don't code. I agree with 5etdemi post 4 years ago, the basics have ironically gotten harder to do.

What wrong with ECMAScript/Actionscript? Well, it is not especially well suited for certain tasks, the worst of which is time-based/timeline-oriented animation and declarative drawing. I mean, it seems pretty ironic that ActionScript is derived from ECMAScript which was primarily oriented at scripting in a text-based environment, HTML and the DOM. Simply put, ActionScript has leaned more and more towards heavy lifting text operations (like RegEx and the new XML implementation) and less towards building programmatically what Flash was originally meant for, animation.

While there are useful utilities like Lee Brimelow's nice event generator utility, I wanted less, as even if being good with actionscript, when you have a few minutes to put together something for (or during!) a client/skype meeting, scripting isn't really an option. Thankfully AS3 has some tricks to help!

(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.) ( press RIGHT arrow key to advance)

One tennant of Sketch is using the type and instance names to do most the event binding work, largely this is to allow Designers to stay on the timeline, but the same could apply to objects created in actionscript as well. So in the above example there are 2 scenes, and a bunch of empty frames, and a nav control. What's special is the buttons you see are actually just semi-transparent buttons (I call InvisiButtons) that have instance names like 'next', 'prev', (shown in the button names) there is no other script on the timeline for them. That via the FlowControl listening to ADDED event are autowired up to call 'nextFrame()' , 'prevFrame()' etc. These InvisiButtonscould be used as a hotspot over a comped image or basic text and wireframe graphics, allowing low to high fidelity comps to be created.

In this example a ENTER_FRAME event updates the TextField off to the right to show the current scene, frame et, to show where you are.
FlowControl has some other nifty features.

  • optional features is the fadein, fadeout effect, with configureable color, so while there is a normal timeline, the fade effect is free and ads a bit of polish IMHO.
  • tooltips telling you where the buttons go/do.
  • keypress for left/right arrow to go to the next previous frame, escape to goto first frame-useful for slide shows
  • XXX_autoBtn. If it sees this pattern that button will generate an XXX event (e.g. sayHi_autoBtn generates a new Event("sayHi"), which anybody is free to listen to.

All these are in the example (as well as all the code for FlowControl) on code.google.
Flow Control can be used 'embedded' as the document level class (or extending from it) or loaded as an external swf, and I'll be demoing that in the future. That latter feature is more targetted to creating highly skinnable games which I'll be covering in future blog posts.

Flash: View Controller binding

When using actionscript to turn a MovieClip , Sprite etc into a component. There are several points that can be used to introspect the children to bind the displayObject, whatever configuration is on stage, with the ActionScript class. Different binding points allow different things, here's the order and

OUTPUT:

  • constructor: // displayObject children are already on stage in the displayList but haven' t been drawn yet. the Actionscript class for it is just getting instantiated.
  • onFrame1: // actionscript on or associated with frame1 has fired
  • activateHandler: //not always called
  • onFirstFrameRender: //first time ENTER_FRAME has hit the frame1, meaning it's script has fired, and everything is already visible.
  • renderHandler: //only if the stage.invalidate() is called.
  1. package {
  2.  
  3.  import flash.display.MovieClip;
  4.  
  5.     import flash.display.Sprite;
  6.  
  7.     import flash.display.StageAlign;
  8.  
  9.     import flash.display.StageScaleMode;
  10.  
  11.     import flash.events.Event;
  12.  
  13.  import flash.text.TextField;
  14.  
  15. public class StageExample extends MovieClip {
  16.  
  17. public var sizeMe:MovieClip;
  18.  
  19.         public var output_txt:TextField;
  20.  
  21.         public var textLog:Array = new Array();
  22.  
  23. public function StageExample() {
  24.  
  25.                 super();
  26.  
  27.             stage.scaleMode = StageScaleMode.NO_SCALE;
  28.  
  29.             stage.align = StageAlign.TOP_LEFT;
  30.  
  31. stage.addEventListener(Event.ACTIVATE, activateHandler);
  32.  
  33.             stage.addEventListener(Event.RESIZE, resizeHandler);
  34.  
  35. addEventListener(Event.ENTER_FRAME, onFirstFrameRender);
  36.  
  37.                 addEventListener(Event.RENDER, renderHandler);
  38.  
  39. addToLog("constructor: w " + stage.stageWidth + " h " + stage.stageHeight);
  40.  
  41.                 addFrameScript(0, onFrame1);
  42.  
  43.                 stage.invalidate();
  44.  
  45. }
  46.  
  47.         private function onFrame1():void {
  48.  
  49. addToLog("onFrame1: w " + stage.stageWidth + " h " + stage.stageHeight);
  50.  
  51.                 //resizeHandler(event);
  52.  
  53.         }
  54.  
  55.         private function activateHandler(event:Event):void {
  56.  
  57.             trace("onFirstFrameRender: " + event);
  58.  
  59.                 addToLog("activateHandler: w " + stage.stageWidth + " h " + stage.stageHeight);
  60.  
  61.                 //resizeHandler(event);
  62.  
  63.         }
  64.  
  65. private function onFirstFrameRender(event:Event):void {
  66.  
  67.             trace("onFirstFrameRender: " + event);
  68.  
  69.                 addToLog("onFirstFrameRender: w " + stage.stageWidth + " h " + stage.stageHeight);
  70.  
  71.         //      resizeHandler(event);
  72.  
  73.                 removeEventListener(Event.ENTER_FRAME, onFirstFrameRender);
  74.  
  75.         }
  76.  
  77.         private function renderHandler(event:Event):void {
  78.  
  79.         trace("renderHandler: " + event);
  80.  
  81.         addToLog("renderHandler: w " + stage.stageWidth + " h " + stage.stageHeight);
  82.  
  83.     }
  84.  
  85.  ///////////////////////////////////////////////////////////////////
  86.  
  87. private function resizeHandler(event:Event):void {
  88.  
  89.             trace("resizeHandler: " + event);
  90.  
  91.             trace("stageWidth: " + stage.stageWidth + " stageHeight: " + stage.stageHeight);
  92.  
  93. addToLog("resize: w " + stage.stageWidth + " h " + stage.stageHeight);
  94.  
  95.                 sizeMe.width = stage.stageWidth;
  96.  
  97.                 sizeMe.height = stage.stageHeight;
  98.  
  99.         }
  100.  
  101.         private function addToLog(str:String):void
  102.  
  103.         {
  104.  
  105.                 textLog.unshift(str);
  106.  
  107.                 output_txt.text = textLog.join("\r");
  108.  
  109.         }
  110.  
  111.     }
  112.  
  113. }

AS3: Prelude to Tweeny, a fast and flexible Tweening engine

So I've been working over the weekend on the Tweening engine based on Cogs affectionately called Tweeny. I find it highly amusing as I've been working in Flash since Flash 4, I have built so many presentation engines it borders on comical when every new client inevitably asks for a powerpoint lite clone, and consider myself relatively advanced,..yet how much of a loop this one threw me for.

WhileI had an AS2.0 class already working, it's taken me 3 days to get the basics working in AS3.0. This is because yesterday I totally got schooled on Matrixes with Senocular's most excellent tutorial, (my brain still hurts) and then excited by Penner's lurking MatrixTransform and ended up scrapping several paragraphs that comprise most the standard tween engines. I find myself building this next presentation engine in a way that bears no resemblence to most engines I've used or seen, partly due on the architecture difference between AS3.0 and prior, and partly expanding the role of Tweening beyond the simple display classes. Every time I added a new feature or solved a bug, I found a way to make things simpler.
Matrixes are cool, as you can get away with just easing the Begin and End matrixes rather than doing every calculation, plus you get the ability to offset the registration point and skew, features both very useful for the Authoring type interfaces and kids content I'm creating. More power and more speed to boot! In running performance tests, it's about 2x faster than setting DisplayObject.rotate, DisplayObject.width, scale etc as most tween engines do. Not that running those scripts are typically the limiting factor relative to the overhead in rendering, but still it's nice to know that the underlying code isn't a bottle neck.
Like most Tween engines, Tweeny supports a pluggable easing that affects multiple properties (x, y, width etc) with individual ranges (x[-5, 100], pan[-1,1]). But something my math-whiz girlfriend help me realize was that since duration is fixed, the easing equasion (often filled with expensive Math operations) can be calculated once as the 'normal' and then scaled to the others ranges, cheaply with simple * + . This should significantly reduce tweening calculation overhead,...and dammit I like smart particles flying at 60fps!

To further that I realized that the normalized calculation, is easy to broadcast, so that other listeners keep in synch, and can conceivably modularize or patchwork tweens. One of the things that I've wanted to try for awhlie was a way to balance out top-down easing approaches with bottom up physics routine. This usually involves Euler or Verlet accumulation and integration of forces, but most tweening engines are rather possessive when it comes to updating display objects...only one at a time else they start overwriting, where's the fun in that?
Some other features I like, Sound or SoundChannel volume and pan, colorTransform tweening (which I use a lot for configuration dynamically styled UI's) easier constructors for Bounce and Elastic's extra params which I use with kids games.

One thing that I'm not currently planning on supporting soon is a JSON or XML based interface. I find it poor programming practice to do

TweenEngine.create(target, duration, {x:1,y:2, ....})

in AS3.0 when you can do:

var t:Tweeny = new Tweeny();
t.initFrom(target,duration);
t.x = 1;
t.y = 2;

t.addEventListener(...)

t.startFromBeginning();

Because using fully typed classes allow for autocomplete to help fill out the values, offer stricter type checking and setting of defaults. When they are on a line by line they are easy to comment out to turn on and off. There isn't any overhead to parse XML or JSON into useable values. Since it's part of the Class definition it should also be significantly faster than dynamically allocated Object properties on the prototype.
Keeping a tween around, keeps memory and garbage collection from churning, especially for most applications where the tween is reused over and over again to put thing back and forth. I realize why many tween engines opt not to go this route as managing transitions on top of other transitions can get tricky. But know that I know about these issues I'm glad I spent the extra time. Since Tweeny uses the Playhead API, it supports stop, rewind, play, playbackward etc, it's not really different than keeping an mp3 or swf around.
So far it's about 10K, so 3x larger than say Tweenlite, but much of that is the inclusion of the framework/Cogs is useful for many other things, websites and games especially, and I'm still working on it.
The morning had an epiphany and I was able to tie together many of the related ideas into a cohesive model, so I have a roadmap for the next few months, and even a relatively simple Authoring UI for all the features exposed. Looking at the one pager of noteobook, probably 7 boxes, and only a few UI elements, in that largely what I'm working on is creating much of the same metaphors (e.g. timeline) of Flash inside of Flash...just like Web 2.0 is largely recreating the OS inside of the WebBrowser. And Virtualization is recreating the connectivity of electronics. One that note, if your looking for good book on self-referentiality check out Gödel, Escher, Bach .

AS3: recreating onLoad, MovieClip.addFrameScript part duex

Recreating onLoad with MovieClip.addFrameScript

AS2 had an onLoad event, called after the frame's children had been created, which is largely how custom components were able to manipulate the visual state for useful things like:

  • register listeners.
  • hiding and showing clips (especially when multiple clips are stacked on top of each other for different error messages)
  • jumping to a frame,
  • setting up modal dialogs/mouse opaque areas

In AS3 this doesn't work the same, and this bites you on the occassion you have an actionscript class is registered to a class via the linkageID, like that of the "Document class.
If you try it you get the warning:

Warning: 1090: Migration issue: The onLoad event handler is not triggered automatically by Flash Player at run time in ActionScript 3.0. You must first register this handler for the event using addEventListener ( 'load', callback_handler).

So you think, ok, easy enough. Just add an eventListener to load. Test movie and then nothing happens. Search the help docs, and you find zero references to 'load' event. Check DisplayObject and you find every other event (render, added, etc) than the one we are looking for. Leads to one of two possibilities. One the load event doesn't exist... or second the load event has already been called prior to the class constructor being called, so adding a reference to it won't actually do anything. I can't really tell, I've tried searching and running some tests, and can't get it to work... which leads me to the question, just how do I accomplish all those in items above?

Thankfully the fix is easy: addFrameScript in the constructor.

addFrameScript(0,onLoadHandler); //works!!!
// addEventListener("load", onLoadHandler); // doesn't work

While on the subject,  in order to access clips on the  timeline from the *.as they should be public variables like this:

  • public var my_btn:SimpleButton
  • public var my_playerControls:MovieClip

and your class should be dynamic e.g

dynamic public class MyView extends MovieClip

Keeping the scripts already on the timeline.

Since your replacing the script call when it hits frame0, whatever is on the timeline won't be called. Thankfully since MovieClip is a dynamic class, scripts on the timeline are appended to the prototype, thus available by this which refers to the prototype chain instead of the class inheritance (Flash is multiple inheritance!). This is useful when the timeline has some configuration data/setup on it, and this approach allows you to call it prior or after your onLoadHandler

public function MyMovieClipClass(){

super();
addFrameScript(0,onLoadHandler);
// addEventListener("load", onLoadHandler); //doesn't work
trace(" AAAA CONSTRUCTOR AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
}
function onLoadHandler():void{
trace("BBBBB onLoadHandler BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB");
trace("onLoadHandler " + currentFrame);

///pre frameactions

if(!this["frame1"]){
this["frame1"]();
}

//post frameactions

my_btn.addEventListener(.....

my_playerControls.gotoAndStop("buffering");

}

OUTPUTS

  • AAAA CONSTRUCTOR
  • BBBB onLoadHandler
  • CCCC frame1TimelineScripts

AS3: MovieClip.addFrameScript

MovieClip.addFrameScript is a very powerful way to decouple script from the timeline. This post help you understand how it works.

When movies are compiled (including the top level swf), if no class is provided. Flash creates one for you behind the scenes. 1 Class is created per 1 MovieClip, typically sharing the same name. It helps to understand how the conversion happens, to make best use of it, and writing code on the timeline in general.

  1. imports are only needed once in a timeline
  2. variables declared on a frame, end up as class variables,
  3. you can't redeclare variables on multiple frames.
  4. only one function is called per frame, this can be tweaked, overridden or amended with addFrameScript

You can't redeclare variables,

on frame1 and frame2 put:
var aName:String = "A";
will give you the following error:
1151: A conflict exists with definition aFrame in namespace internal.

however putting on Frame 1

var aName:String ="A"; //frame1

and on Frame2

aName = "B" //frame2

works fine.

MovieClip.addFrameScript

Is the undocumented glue between the timeline frame and the class's function ( if bound). There can only be one script/function bound to a frame using the built in addFrameScript, though an alternative approach is to poll currentFrame changing (via Event.ENTER_FRAME).

This binding happens via addFrameScript(frameNumber-1, functionToCall...); Note that the first argument is ZERO BASED (while normally the timeline is 1 based)
During the Fla.compilation our script gets put into a function like:

Class Test_fla{

function frame1():*{

var aName:String = "A";

}

function frame2():*{

aName = "B";
}
}

The important thing to note is the frame1...frameN naming, where N is the frame number 1-whatever, We can validate this by decompiling the swf, using the AbcDump utility, which takes our test.swf and outputs:

function Test_fla::frame1():* /* disp_id 0*/
{
// local_count=1 max_scope=1 max_stack=2 code_len=16
0 getlocal0
1 pushscope
2 findpropstrict trace
4 pushstring "onFrame1"
6 callpropvoid trace (1)
9 findproperty aFrame
11 pushstring "aFrame"
13 initproperty aFrame
15 returnvoid
}

So the end will be a frame to function mapping (which we can't see) like:

  • [0]= frame1()
  • [1]= frame2()

Note again the frameNumber is zero based, while the script is 1 based.

Consequences

which has 2 consequences,

  1. you can't name your own functions frameN if one already exists. This is the same error as compiling in the same *.as:
    function frame1(){

    }

    function frame1(){

    }

  2. you can call and over ride these functions,
    addFrameScript(0, overrideFrame1);
    function overrideFrame1():*{

    //do something before
    frame1();
    //do something after
    }

In addition the top level Class, will be shared across different scenes, but these can have on the timeline different configuration values (say which language to use), and when used with jsfl to publish all scenes, create a handful of starter files.

Conclusion

This is kick ass for completely separating a UI.swf from a Controller.swf Keeping designers working on the timeline, and coders out of the design.

For the coders, and others working in Flash, is the ability to use addFrameScript to perform actions when a frame is fully initialized and children are on stage, similar to onLoad() in AS2, where-as use of ENTER_FRAME gets called prior to children in that movieclip getting called...this is similar to onInit() in AS2. So for example you can have a button only on a particular frame and setup it's event listener to call your controller...in another swf, regardless of what the playhead is doing.

In someways I find this cleaner than watching using addedToStage, rendered etc.

REFERENCES:

[1] Senoculars post
[2] FlashGurus info as Senocular
[3] BIG SPACESHIP, Extending addFrameScript to use the frame labels instead of framenumbers... the same glue I'm using as well, though I'm more interested in events being generated, than script.

[4] an alternate approach on evilzug's journal using ENTER_FRAME


You should be aware if using that approach that when the framescript is called via the ENTER_FRAME, items in the frame may have not been added yet, so this approach can't be used to bind to objects on the timeline (e.g. to registerListeners to buttons), this the addFrameScript does not suffer from.

Here's an output with one on the timeline the other added via oizys's frameScript approach:


entered frame 3
onReachedInstructions instructions null <- no button yet, via modified addFrameScript
timeline reached instructions [object SimpleButton] <- normal addFrameScript
onReachedInstructions instructions [object SimpleButton] <- now the button exists

Mouse Click Lifecycle

Events are broadcast in exactly this order:

  1. MouseDown
  2. MouseUP
  3. MouseClick

If you play with it, note that MouseClick is triggered without a regard to time. The user could hold down the button for a year, drag it over and out of the clip, and as long as it's released over the same clip it was over, it registers a click.  Often in gestural UI's this is not the desired behavior, as that's not really click like, say like Double Click, two Press/Release event within a window of time. This is pretty easy to solve just do something like:

public function onPress(event:MouseEvent= null):void{
isPressed = true;
clickTime = getTimer();
}

public function onClick(event:MouseEvent= null):void{
var exitTime = (clickTime + 200); //200MS is reasonable click time.
var curTime = getTimer();
trace("mouse Click " + clickTime + " " + exitTime);
if( curTime < exitTime){
//do something with the click tim
}

}

Handling releaseOutside

Another gotcha, was the removal of releaseOutside. The comments here somewhat cover it. Though for my own solution I ended up using rollOver and rollOut to register the off stage release/click listener, that when back over the interested clip, remove it.

public function onRollOut(event:MouseEvent= null):void{
trace("onRollOut**************************************" + _clip);
//onReleaseOutside();
_clip.stage.addEventListener(MouseEvent.MOUSE_UP, onReleaseOutside);//, true); //recommended didn't work
}
public function onRollOver(event:MouseEvent= null):void{
trace("onRollOver******************************************");
_clip.stage.removeEventListener(MouseEvent.MOUSE_UP, onReleaseOutside);}

Sketch: View Controller separation, MovieClip.addFrameScript

There are several approaches to using Flash assets in Flex, as assets. Predominately centered around using getDefinitionByName(), e.g. here we are going to pull from a library of 5 possible graphics and attach it to stage.

var dc:String ="missle"+num+"_MC";
var classRef:Class = getDefinitionByName(dc) as Class
var mcMissleGraphic:* = new classRef(); //might be a movieclip, shape or sprite)
addChild(mc); //similar to attachMovie of old

or extending this example to make it a user-defined class, by passing it into the constructor (using composition)

var missleMC:Sprite = new Missle(mcGraphic);

addChild(missleMC);

In this example the visual tree will be

  • Child
    • MissleController (has a graphic)
      • MissleGraphic
        • FlameAnimation
        • BlinkingLight
          • RedBlinkClip
          • GreenBlinkClip

The downside is that if something ever needs to access the MissleGraphic or child clips (like hiding red or green blink clips) it must go through an additional layer. When coding it's easy to get these out of synch, and the layer is one more thing to keep track off. It's the difference between IS A and HAS A, and also doesn't faciliate timeline control of the user experience.
But it's a useful approach, and Grant Skinner even has a library to help deal with the loading of external swfs. That must be fully initialized prior to attempting this.
http://www.gskinner.com/blog/archives/2007/03/using_flash_sym.html

and if your going to be embedding it you can also follow this

http://www.digitalflipbook.com/archives/2007/03/associating_cus.php

Sketch's approach Designers First, Script later
Sketch differs from this as these all imply the script has control first and is pulling from the library of assets designed in Flash IDE. Sketch prefers that designers can lay things out on stage, working on the timeline to process, and then later load up script and have it embue them with life, primarily as placing and sizing things laying out things is best for visual tools, when outside of grid layout controls for data driven components. This is not to say that you can't have AS code generate all manner of things, just that most approaches don't give you the option for the first. In the mini-game industry, and animated content this is far more acceptable to smooth production and good users experiences.

UI and Controller synchronization via MovieClip.addFrameScript
So I was looking through the old paperwork when I was a part of the Flash8/9 beta. Since it's been released, and out for awhile it's interesting to compare what made it where and what's changed. It's also much easier to read having gotten up to speed on AS3. One of the things I've rediscovered is MovieClip.addFrameScript, which totally fits into the Sketch way separating UI from controller synchronization, though I hadn't seen it before. Of course I wasn't the first to discover this:
http://www.flashguru.co.uk/undocumented-actionscript-3/

http://www.kirupa.com/forum/showthread.php?p=2098268

BigSpaceShip in particular is on a similar approach, he has an interesting take of introspecting the movieClip labels and attaching a script to when they are fired. This fits into the Sketch philosophy of using minimal or no code in the view to indicate state.
http://labs.bigspaceship.com/blog/?p=43
Though Sketch again differs in it's approach, while it too introspects the framelables, creates a registry of sorts, it treats changes of the playhead, as an event to broadcast so more than one party can listen, addFrameScript is like removing that intermediate event and directly calling a script instead. The downside to the addFrameScript approach is it will override any script inside inside the timeline, so in some ways polling based on EnterFrame events is less prone to breaking something the designer is doing (e.g. play/stop or configuration);

Generate UI Class Linkage via ByteArray?
The other cool thing I found which is a lower level hack is the Tag in byteCode that the Flash Player that binds the library symbol with the actionscript class, in a streaming fashion so that not everything has to be put on frame1. Looking through the source code documentation it's still in, and seems similar to the Object.registerClass.
I'm unsure if the security model will permit a loaded swf to append to the parent, but it seems likely given we are already doing that with getClassDefinition etc.. It's also possible that something similar may be done via getClassDefinition, if however the linking mechanism in the player can be called. This would be a huge advantage to Sketch as currently the conversion of instances one stage to classes is via addChild/removeChild on the displayList. Not horrible but not clean, in particular keyframes can break some things as a new reference will be on stage but if it keeps the same name the displayList doesn't get notified.

Ideally this can be via ByteArray it's possible to read and write swfs at a binary level. So generation of the linkage might be possible via AS3, without the need for composition.
In Object.registerClass, an library item IS a user defined class. With AS3, it's similar but the linking is defined at compile time in the IDE, thus we have to use composition instead for late/lazy view binding. So Object class HAS a view. It's possible to use Proxy to make this more seamless but then we lose the typing of MovieClip/Sprite. e.g. a Ball clip is a ball, is also a MovieClip.

Some work on dumping the tags is already being done, so it might not be too hard to find it out.

http://www.5etdemi.com/blog/archives/2007/01/as3-decompiler/

http://joeberkovitz.com/blog/2007/04/08/secret-life-of-swfs/

Sketch: Advantages of using.

Since the UI/Skin is one swf and the code in a separate, loosely coupled. It provides many benefits in team development. Here's a short list.

  • For Design teams, Reskinning games is drop in replacement. Just the Fla, no code, compiler, SVN and dependencies to set up for a designer, no worries about changing a piece of code that they should have.
  • For a coder, no fonts, cross platform issues pop up, no worries about bumping things.
  • It helps enforce good boundaries/interfaces between teams. frameLabels can be checked to conform to an API and script complain on compile.
  • Facilitates reuse. Code "engines" become easier to maintain as they can only be changed by developers, preferably thorough a unit testing framework. Similarly Existing skins can be turned into completely different games if the new logic uses the same view/controller API.
  • Working with contractors/outsources allows you to send just the compiled file instead of the source tree.
  • bug fixes and new features can be rolled out by dropping in new files. Say a puzzle whose boards are generated purely by script, gets new levels or features. This is very useful when you have multiple skins, or versions (if configuration controlled) for the same engine in production, an Ant script can just update the folders with the new file rather than needing to recompile all of them. One one project we have close to 30 minigames, each about 5 minutes long, just different assets and configuration files. So it's compile once, copy 30, rather than compile 30.

Sketch: Working on the Timeline, with currentFrame, currentLabel, and FrameTracker

Sketch is a way for letting designers work on the timeline with essentially no code, and coders in pure code no visuals, where they are happiest, typically in separate swfs. Which introduces the key questions, how does they talk to each other? and coordinate actions?

There are two methods one is lateViewBinding which turns MovieClips into components at runtime via composition, which I'll cover in a future post, the other is using the frameLabel as a contract. Current 'active' framelabels as events indicating when the playhead has changed.

Things to be aware of when using currentFrame and currentLabel
There are few things that one should be aware of when working in this fashion.

  • currentFrame changes when hitting a new frameLabel, regardless of which way the playhead is going. It's essentially a rendered a frame named this event, not a box indicating the framelabel is valid from say it's start's Frame to some other frame as it's often intended to mean when looking at the timeline. This maps onto a finite state machine one labelled frame == one active State, only one active at a time.
  • New frames with no frame labels don't change the currentLabel So if you have an empty keyframe after a labelled keyframe, it will keep the value until it's changed to something not empty. So if your looking to clear out a frame label, you should use something like " " (which is a valid if somewhat odd frame label)
  • FrameLabels are intended to be used one at a time. While the FlashIDE allows for multiple layers, each potentially having overlapping frame labels, this isn't easily accessible in script. So if you hit a particular frame with multiple layers on it, each having a label, it will choose as the currentLable whatever the level load order is. So say you had frameA on layer 1 and frameB on layer 2. currentLabel only reflects frameB. Most the time this isn't an issue. But there are times when using changes as events.
  • you'll have to roll your own change event to deal with frameLabel changes. This strikes me a bit wierd given all the other changeEvents. But so be it, it's only 2 paragraphs of code.

Creating and Using FrameChangedEvents

All Labels of a given are known via the currentLabels array property. which gives you a list of frame labels, each having a name and a frame number. As enterFrame events happen, changes to the currentFrame and currentLabel can be dectected by comparing them to what they were on the last onEnterFrame event. Querying this collection when the frameNumber changes is how we can get access to multiple frame labels being active or not, and then by keeping a history of when they are active or not, broadcast events to the controller/model.
Using a FrameTracker MovieClip

An alternate approach for frame Enter and frameLeave events is using a frameTracker, basically a special basically empty MovieClip that is put on the timeline and based on when it loads and when it's unloaded it generates the appropriate events. The adding and removal of this is watching the DisplayObject for add and removal, and using the instance name as the base of the event. e.g. myFrameTracker becomes "myFrameTracker_ENTER", "myFrameTracker_LEAVE"

The detection of adding and removal of the FrameTracker from the stage is the basis of LateViewBinding.

Introduction to ActiveFrame, Cogs, Chain, Score, Sketch, fXperience

Intro to StateMachines

The good news is if your in team development, you've been diagramming them for years, as flowcharts and bubble diagrams. Bubbles are states, arrows are transitions. This is one of the keys to their usefulness in teams. The diagrams can be understood and modified by anybody, and can represent anything from a users interaction with the whole application, a game's AI, or the graphical transitions in a button rollover. Any Animator who has done keyframes and tweens knows has been unwittingly using states and transitions, but what about developers?
Most any application developer is familiar with OOP, and many design patterns like the State Pattern. Some may have heard of the term finite state machine (FSM) with a possible vague understanding of what one is/does, most are probably not familiar with Hierarchical state machines (HSM), which are especially powerful, especially in experience driven, Flash
and AIR content working with asynchorous network requests, and large media upload/downloads, long timeline, all of which have complicated life cycles with asynchronous call/callback.

I started using them in projects after first learning about them in software from Jonathan Kaye. After using a few different versions in a few different projects, and developing my own, I have been on a quest to spread the word ever since. OOP and SM's foundational aspects. They are orthogonal and complimentary, OOP describes the nouns of the system StateMachines's the behavior over time. An example the cat is meowing, cat is the noun, meowing is the current state, and it will change over time.

Intro to Cogs
Cogs is the AS3 library of statemachines, and common patterns that people can extend/plugin similar to how people reuse design patterns, to avoid reinventing the wheel. Just as in Design patterns, there are fundamental patterns, from simple toggleable button, to synchronized media players.

It's named Cogs first after the tiny teeth that compose gears, that when meshing properly make up engines which power most the mechanical world, and secondly Cognition as the meshing of neurons make up the engines of intelligence. Cogs primary use is increasing the intelligence of components, games, game AI, and applications, by several approaches:

Cogs allows you to ask where you are, where you can go, and automate chains of execution between two states. Often event driven components are black box event generators, identical events broadcast at different times mean completely different things (like NetConnection) this is far from simple.

The FSM and HSM are based on Miro Samek's approach of using functions instead of classes to represent states, this very low level implementation has several advantages, one of the first is being less code to understand and write. It also enables behavioral inheritance, similar to. Cogs is different in several ways from Miro's inspiring work in his book. First all possible transitions are supported instead of just the common ones, and are validated by the unit tests..and the testing framework itself being an FSM and supporting Asynchronous testing easily.

Ongoing I'm working on API's for deep history, serialization/deserialization a graphical visualizer, among other things.

ActiveFrame

Cogs is part/foundation of a larger framework named ActiveFrame. Which strives reduce commmon architectural decays, largely by decoupling.

  • A message bus enabling event decoupling,
  • Java Spring 'Dependency Injection' for Implementor Interface decoupling,
  • plus a decoupling of the UI and controller..which can live in completely different swfs, similar to AS2.0's Object registerClass.

It's reasonably small for all these features, allowing it to be used for components, games, game AI or full blown applications.Sketch

is the visual extension of the Cogs, to deal with the View/UI world (e.g. movieclips/timelines, sprites), common layout, and UI/controller decoupling communication. While Sketch can be used whereever Flash can go, it's strong points are design and script heavy projects, in teams that have strong separations between design and scripting... they don't even have to be working on the same file.

Since it's based on Cogs, it's very easy to prototype and if flow diagrams (state diagrams) are used in the IA and Creative phases, it can act as a common language between design, IA, and engineering, as diagrams can easily be translated to code and back, and reworked easily. It supports what I call "introspectable UI's", in that the statemachine can act as the model, and summarize all the active states supported options to generate an appropriate "where can I go from here" UI.

Chain

is the workflow component, it's coordinates dependent parallel and sequential and nested tasks, with asynchrous call/callbacks, providing status along the way. Some uses for this are preloading assets, playlists, unit testing, easing and tweens, build out and tear down of UI's.
Score

is the the parallel timeline orchestration component, similar to a Orchestral score for coordinating multiple instances with a single virtual playhead. Useful for overlapping events. It's similar to an actionscript version of the Flash IDE timeline.
fXperience

is the visual components library. This is based off Cogs/Sketch, components have a wider lifecycle than those built into Flash and Flex., e.g. a button transitioning in, transitioning to up, transitioning to over etc. They support easy and iteratible skinning, so projects can start out simply as a graphic than graduate to more complicated ones as need requires.

Misc

All are a part of the TroyWorks AS3 code library that is MIT licensed on google (but isn't finished/uploaded yet, API isn't stable) There are many other useful utilities, datastructures and components of interest I'll be covering in more detail as they get more fully flushed out and converted to AS3 from AS2, I'm trying to make sure I don't add something already in AS3, and take full advantage of AS3's architecture.