Categories Displayed in Flash

Archive for August, 2007

AS3 and Serialization, Memento Pattern

Starting to work on porting the persistence aspect of Prevayler to Flash/AS3. It's a perfect fit with Flash, as Prevaylence assumes that everthing can fit into RAM (which flash does, aside from loading new things in), and changes have to be synchronized, which seeing as it's a primarily a single thread doesn't have to worry about synchronizing multiple writes.
Prevaylence relies heavily on understanding the serialization of objects, both the commands and the business object state should be save and restoreable. Since ByteArray supports AMF packets (as does shared object) this means that private vars and Class definitions, functions should be able to be written to disk and brought back from dead...but this leaves the larger question, just like the dinosaurs ...should they be brought back?
It's certainly tempting.  Java has faced this for years in it's serialization routines. In general built in serializing is good, but doing it across version is bad, as it's inevitable that the Class definition will change, adding, removing variables and methods ...even changing types, during refactoring. When reconstituting things may not serialize properly much as you don't fit into your GI Joe pajamas from kindergarden (well hopefully). It's unpredictable what the Flash player will do when forced to put version 1.2 into 1.3 shoes, or potentially version 1.4 into 1.2.  So it's important to know exactly what is being saved and how flexible it is.

Since I was working on Trace.me this week, and private, protected, etc variables didn't show up in the output, (which is proper Object encapsulation), I was curious as to if the variables were invisible or lost. I remembered  hitting similar things when working with and on openAMF, so I dug a bit, and just found a document I wrote a few years ago, on openAMF, ah good times...

http://openamf.cvs.sourceforge.net/*checkout*/openamf/openamf/docs/understanding.htm?revision=1.1

There the issue there was different, was actually whether java's accessors e.g. get someValue and set someValue translated across the wire. The serialization in Java openAMF calls the accessors and puts them into a hashmap, before sending across the wire. Flash does something similar when sending back to the server, skipping the accessors as back then it didn't really know what those were. But I wasn't sure if this was the case when targetting ByteArray and Shared Local Object for output.

I have an dummy object called IntrospectableObject, it has all manner of public, private, protected etc vars of all different types (well at least enough to test), I've been using to test. I've added a few accessors and a toString method which outputs everything.

The code to test ByteArray as a serialization is simple

import flash.net.SharedObject;
import com.troyworks.prevayler.*;
import flash.utils.ByteArray;
import flash.net.registerClassAlias;
import flash.utils.describeType;

////////////// BYTE ARRAY TESTS ////////////////

var bA:ByteArray = new ByteArray();
//registerClassAlias("com.troyworks.prevayler.IntrospectableObj", IntrospectableObj);
var iObj:IntrospectableObj = new IntrospectableObj();

bA.writeObject(iObj);
bA.position = 0;
var aObj:Object = bA.readObject();
trace("aObj " + aObj.toString());

trace("XML " + describeType(iObj).toXMLString());
trace("attempting to introspect ");
for (var i:String in aObj){
trace( i + " " + aObj[i]);
}

It outputs:

new Introspectable //consturctor of source
aObj [object Object]
attempting to introspect
pubStrVar public testString
pubBooTrueVar true
pubVar undefined
pubUIntVar 1
pubIntVar -1
pubNumVar 0.5
pubBooFalseVar false
pubDateVar Wed Aug 29 02:40:48 GMT-0700 2007

which reveals no accessors are called, and nothing but public vars are called, which is to be expected. Uncommenting:

registerClassAlias("com.troyworks.prevayler.IntrospectableObj", IntrospectableObj);

We get something completely different. As it's creating a new class upon reconstitution, and then calling it's toString() which has access to the private/internal so can see more. This means that ByteArray does get the whole picture even if it doesn't share all of it.

new Introspectable //constructor of source
new Introspectable  //constructor of reconstructed
aObj pubStrVar public testString
pubNumVar 0.5
pubIntVar -1
pubUIntVar 1
pubBooFalseVar false
pubBooTrueVar true
pubDateVar Wed Aug 29 03:00:12 GMT-0700 2007
priStrVar priTestString
priNumVar 0.2
priIntVar 2
priUIntVar 2
priBooFalseVar false
priBooTrueVar true
pritDateVar Wed Aug 29 03:00:12 GMT-0700 2007
attempting to introspect
--none--- //can't see anything as it's now class based.

What interesting is simliar to AMF, the constructor is called by Flash/AS3, but the values of the items as serialzed overwrite, bypassing the encapsulation layer (and thus any events). This is good if sometimes tricky to remember. It's resetting the snapshot of the object's state. Which compared to broadcasting a dozen+ change events makes sense, as it really hasn't changed, it's just been restored. This is basically what we want but as prior this may hit the shoes don't fit problem, break on newer swfs with different code coming out.

What this indicates to me is that serialization for Prevayler like approaches, should be done via the memento pattern, and only the mementos should be serialized. Wikipedia has a good article on it.
http://en.wikipedia.org/wiki/Memento_pattern  which interestingly links to a large page on finite state machines. which uses the memento pattern to save state/shallow history, with extended variables.
http://en.wikipedia.org/wiki/Finite_state_machine

Both the business logic and the commands should implement the pattern.  Mementos immutable read-only ideally, with all values passed into the constructor and only accessible via getters. But if the number of attributes are large, I could see a Object/struct with purely public variables may be better for useability and performance, as Mementos shouldn't do anything. In addition, Mementos should have a version number of the 'file format', and preferrably some mechanism can faciliate putting the data in via calling getters on the originator object, if they aren't marked as non-serializable (e.g. calculated results like totals shouldn't be serialized). Which I often like to put into a separate class, as the serialization/deserialization may be for different formats, XML, and they aren't really 'business object' concerns. One could even use the namespace feature to manage which one is being used.
This is exciting to me as Shared Local Object is cheap and fast and shared..a great place for multiple flash movies potentially in different web pages, maintaining a common log. Inside AIR's using it's DB, is another good place to store offline/online commands that get synched back up..potentially against other users making changes at one, when connected again.
This would take Flash RIA's closer to conventional applications, even if they are microcontent. It's always annoyed me how long running flash games how some don't remember where you are, using cheat codes so you can jump to a particular level, and that undo is so problematic, so it's either being petrified to explore for fear of making a mistake or having to do the same thing over and over again. There are many games I'd play longer if these capabilities existed. Flash makes these features easy,  it's just that most applications aren't written to support.
Since ByteArray can be compressed and written to Strings, this means they can be files, and thus to disk somewhere, be it SaveAs in AIR,  POST, XML. Sockets, meaning that a saving a application and then logging into another machine and getting everything back would be easy, or potentially opening and saving multiple versions so people can try things or create things easily.

Agile vrs Model Driven Design

Here's another vote for where Cogs and the related framwork comes in handy

http://joeberkovitz.com/blog/2007/05/17/software-modelling-soft-focus-or-hard-edges/#more-55

I don’t think of MDA ("Model Driven Architecture") and “agile” methods as necessarily opposed to each other. Modelling, whether it’s UML or some other system, can serve several good (and potentially agile) purposes:

snip..

2. Some models are far simpler than the corresponding structures in the target programming language, in which case code generation from a model may save a lot of needless work. Complex state machines are an example.

This I totally agree with, and Cogs (or any decently written FSM/HSM engine) will allow this from the boardroom to the code room, to testing and most importantly back, even with new teammembers, without huge impedences. It allows the two strategies, plan ahead, or discover along the way to be used in tandem and at different times.
The basics are that modelling if known ahead of time can save huge amounts of work provided the models actually correspond to the problem domain..provided they are known, frequently they aren't precisely and that's where the devils in the details come in. When properly used, they bypass the expensive rediscovery process, rebuilding from first principals, and facilitate communication. Design patterns is all about this, a library of frequent solutions. Cogs and the use of state machine libraries just extends this to the time domain.

Some things are truly novel, but common application behavior like registering and logging in to quitting the service, or all the possible states of a media player have been done a million times or more, some have tricky aspects that one doesn't discover until one is chin deep in the mire, and like the wheel don't really have any benefit from rediscovering..with a chisel how long will it take you to make a wheel that is perfectly round?. State charts are design patterns for behavior over time and they transcend any particular language, and useage be it parsers, game AI, components or web applications. These patterns are a good place to start in the Information Architecture phase, by considering how the application you're developing is different, it can expose the unknown rollercoaster you are about to code for...and reveal states that may be important you didn't even know you needed to know.
While these patterns could be implemented in a number of ways, at a code level, Cogs (and any HSM) and related libraries are just the most compact representation of the problem in code, much as compression of data finds common patterns in a file and compacts them. Less code leads to less issues, faster development, and less bugs to track, and a better idea of where to fit them in.

Back to the architecture phase, excess modelling can be *superevil*, it's an evil of preoptimization in projects, and arrogance on the behalf. Designing optimizations before actual use is known, which frequently requires dramatic rethinking when this is discovered (this is especially true for projects not grounded by user testing in how end users...not the design and tech geeks building the app will actually interact with it). Such ungrounded, it's easy to ask silly questions that seem important and design around imaginary concerns (let's design sunglasses to protect against the evil green sun!), as many projects aren't chess matches with a known winnning position, once released into the wild the game changes to checkers: same board, different strategies and pieces.
This swings back to the advantages of using agile development approaches: test first, design to fit the test, be ameniable to change, iterate lots. Which using Cogs, ActiveFrame, Sketch do as they are based on years in the trenches looking at how and why applications fail to scale, providing a bridge between rapid prototypes to build team consensus (both inhouse and clients) to compelling usable end-user oriented end products. But here, testing first can lead to taking as long as evolution did to get things useable, let alone right. So the solution is somewhere inbetween.

Flow charts and statecharts are good place to start or pause along the way, because being visual language, anybody can participate, from domain experts to designers to tech. in addition, because modelling an application without considering state and behavior over time is pretty fool hardy, kinda like saying your planning a trip that requires a car, anda single tank of gas, but no idea of where your going. Since COGS uses very few words to descibe a state, and it's actions, there is almost a 1 to 1 representation between the diagram (minus layout aspects) and the underlying code and documentation. More detail of course in the code since it reflect the actual path, rather than just the map. But compared to classes based approach with tons of files scattered, it's generally easier to read, and thus pass the torch as needed when projects are handed off.

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/

ByteArray brings back for…in, and Trace.me

Neato!

one of the useful utilities for AS2 for me was util.Trace.me which basically iterated over an object and gave you an output similar to (apologies WordPress is mangling my indentation, this is 3 layers deep):

[[[[ MyObject.displayObjmeAsArray() START nested: true ]]]]
+- a4:string = test
+- a2:Array = ,[object Object]
+-- 1:object = [object Object]
+- a5:object = [object Object]
+- a6:string = test
+- a8:string = test
+- a3:string = test
+- a10:object = [object Object]
+-- b1:object = [object Object]
+- a13:object = [object Object]
+-- a4:string = test
+-- a2:Array = ,[object Object]
+-- a5:object = [object Object]
+-- a6:string = test
+-- a8:string = test
+-- a3:string = test

this was invaluable when using SOS for getting to the bottom of an issue when the normal flash debugger wasn't an option. But of course with AS3 this really doesn't help as things are class based and you get pretty much nothing (or whatever describeType gives). But I figured out a workaround.
util.Trace.me has moved to com.troyworks.util.Trace, pass it a class and you will get a introspected view like:

+- pubUIntVar:uint = 1
+- pubNumVar:number = 0.5
+- pubIntVar:int = -1
+- pubBooTrueVar:boolean = true
+- pubStrVar:string = testString
+- pubBooFalseVar:boolean = false
+- pubDateVar:Date = Tue Aug 28 00:56:59 GMT-0700 2007
+- $$_id_:uint = 0

This is similar to for...in over normal objects/structs in AS2.

Note: only public vars (not static, const) are retrieved via this.

Note: $$_id_ isn't a part of the object, it's a remnant tag, is used to prevent circular infinite loops, marking the chain, since it's clone of the object, be it class or object based shouldn't be an issue, but not entirely sure how clone works with circular references/dependencies.

How it works is ByteArray to clone an Class which strips out the class definition, leaving it easy to traverse Object with a for...in loop.

What confuses me is how AMF serializes private data, yet ByteArray when back and forth doesn't. I can't tell if this is just security or a limitation.

Prevayler and AS3, ByteArray

Since I have a background in Java Server side architecture, and web app scalability. One of the areas that interests me is applying the many tools that made Java serverside so easy/power (that is when correctly used) into the Flash world.
I have used RDMBS: Oracle, MYSQL, PostGress, SQLServer, XML, OODBs: Versant, Poet and ObjectStore. The latter being a large departure in working with after working with RDBMs for so many years, as there wasn't any brittle Java<->SQL mapping code, just more complicated serialziation/deserialization.

The easiest way to think about Object Oriented databases is if your familiar with Virtual Memory Management, but when applied across multiple machines. Virtual Memory Management makes it appear to the Operating System that there is far more RAM in the system than there actually is, so you can open up that 500MB photofile, and photoshop and Windows all in 512MB or RAM and tack on that brittney spears head..though it might be sluggish, unless you have enough memory. Relatedly this sluggishness is also what happens to web apps, as they are constantly going back to disk to return a few values to the pipe. What happens is and the programs unaware are constantly saved to disk (paging) when they aren't being used and reloaded into memory when they are needed. In some cases the ENTIRE ram is written to disk, this is how hibernate works in Windows when you have a laptop. Or in the case of virtual machines, the entire PC and hardware state is written to a file/disk. Generally this process is transparent to the end users and the application inside. What an OODB does is act like a multiple machine memory manager, with gargantuan virtual memory space, where the RAM is actually on multiple remote machines. If you imagine the alphabet as our database, and say that each server could only hold 3 letter of it, that our servers might have this in memory:

  1. ABC
  2. ABC
  3. ABC
  4. ABC
  5. ME
  6. THE

One of the key to performance is keeping frequently used items like ABC in memory (in this case being popular we've saturated several machines with them) and things not used (like Z) on disk. Almost all application and network accelerators use a variant of this memory first, caching routine. RAM access times for reads and changes are 1000x or more that of the fastest harddrives. RAM has gotten so cheap that this becomes the predominate web scaling strategy, and now it's quite easy to hold 16GB of ram on a single pc. Couple this with decreased processing as there is less mapping code...if any, plus 'pointer' navigation instead of expensive table joins, it's easy to see how OODB's can be order of magnitudes faster than RDBM's on disk. That said OODB's are expensive to use, and skillsets familiar with using them hard to find. With updates to the object model you have to migrate the version 1.0 stored on disk to the version 1.2. The virtual memory just like a harddrive can get fragmented.
Anyway, A year or so later I discovered Prevayler, and it made sense for many if not most applications. It's a one machine 'poor man's OODB. This is a good article on using it.
http://www.onjava.com/pub/a/onjava/2005/06/08/prevayler.html

So what's this to do with Flash? With AS3, and the ability to clone items deeply, I think there is the ability to apply the paradigm and thus benefits to Flash.
http://www.kirupa.com/forum/showthread.php?p=1897368

http://www.richapps.de/?p=34

http://www.stimuli.com.br/trane/2007/may/09/as3-sad-bits-1-deep-copying-or-cloning/

http://niko.informatif.org/blog/2007_07_20_clone_an_object_in_as3
Prevalyer, is the Command Design Pattern, with a command log allowing undo/redo, with the addition snapshots of entire application state periodically. This is similar to tweening in flash when you have keyframe (snapshots) and between frames. Except in this case we are dealing with data instead of visual asset state.

The command log could be stored locally via sharedObject, AIR's ability to write to the file system, or on the server, AMF/Remoting, or XML. In addition if the commands share a similar value to the server they could be used on multi-user applications, that have group editing, replication/failover and undo at a reasonable price. Which would be really cool!

This has a good graph on how it works architecturally.

http://www.ibm.com/developerworks/library/wa-objprev/

Using Namespaces Issues

This article on Kirupa is good example on how Namespaces are normally used both in the 'use namespace' and "::" syntax

Namespaces and inheritance
So after beating my head for a full day. Namespaces + inheritance + describeType don't play together, this sucks as now I have to make everything public which breaks encapsulization. Take this:

public class NameSpaceTest extends IntrospectableObj{
public function NameSpaceTest(){
super();
use namespace COG;
var desc:XML = describeType( this);
// var desc:XML = flash.utils.describeType( hsm);
trace(" RESULT TREE2 \r" +desc.toString().split(">").join("").split("<").join(""));
}
COG function s_COGS_INTROSPECTABLE():void{
trace("Hello World from introspectable::s_introspectable");
}
public function NAME_SPACE_TEST_FUNCTION():void{

}
}

DESCRIBE TYPE OUTPUTS:

method name="NAME_SPACE_TEST_FUNCTION" declaredBy="com.troyworks.cogs::NameSpaceTest" returnType="void"/
method name="s_COGS_INTROSPECTABLE" declaredBy="com.troyworks.cogs::NameSpaceTest" returnType="void" uri="COGS"/

All good. You can see it's outputting a customname spaced item. As soon as you extend from any other class that also uses that namespace your custom namespaced items drop off of describeType, though public functions still show up:

type name="com.troyworks.cogs::NameSpaceTest" base="com.troyworks.cogs::IntrospectableObj" isDynamic="false" isFinal="false" isStatic="false"
extendsClass type="com.troyworks.cogs::IntrospectableObj"/
extendsClass type="Object"/
method name="NAME_SPACE_TEST_FUNCTION" declaredBy="com.troyworks.cogs::NameSpaceTest" returnType="void"/
variable name="pubVar" type="Function"/
method name="s_public" declaredBy="com.troyworks.cogs::IntrospectableObj" returnType="void"/
method name="getNS" declaredBy="com.troyworks.cogs::IntrospectableObj" returnType="Namespace"/

You can inherit from non-namespace users (e.g. Array). I would classify this as a bug, so I've logged it.

Function Pointers and Namespaces
for public non-namespaced items you can call a function via

var methodName:String = "someFunction";

this[ methodName]();

for namespaced functions this will throw a runtime error, you'll need to specify the namespace like

this:COG[methodName]();

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.

ArrayX and ArrayWeighting

com.troyworks.datastructures has a few useful collection types. One of the more frequently used is ArrayX, a drop in replacement for Array. ArrayX for eXtended. It has common used features in many collection management, media and game applications:

  • swapPlaces
  • shift (relative, absolute, number of positions) - useful for playlist
  • shuffle - useful for cards and playlist
  • remove (obj) - searches through and removes the item
  • getFirstIndexOf(item, fromIdx, toIdx) - similar to String's use
  • getLastIndexOf(item, fromIdx, toIdx) - similar to String's use
  • getFilteredSet (fromIdx, toIdx, thatsNot, thatIsOneOf), this allows simple database querying of the collection, from a start position to an end position. With a filterout and filter in.
  • getFilteredRandom - same as above, of the valid values in the collection return a random
  • snapToClosest - useful for sorted number collections, gets the closest value in the collection.
  • contains(item) -
  • isBefore(itemA, itemB, inRange) - is itemA before itemB within inRange elements
  • isAfter(itemA,itemB, inRange)- is itemA before itemB within inRange elements

Also paired with it is ArrayWeighting , a series of weights is paired with an array, that get's random elements based on the weighting/distribution. Imagine the source array represents group of pipe organ pipes, the element at [0] being one note, [1] being another, behind it is a bellows pushing air infinitely, but no sound is emitted until the valve is opened. A monkey is randomly jumping on the keyboard getting one peep at a time, if he's jumping fast enough there is a random chord, creating this random cacophony. However we can make this haromincally pleasing by weighting the notes. The weighting array is an array the same length of the pipes array, with a value inside of it that can be whatever, but it will get normalized relative to the other. Let's use 0-1 being 0% to 100%

  • wts[0] = 1; //whatever is at pipes[0] will get called 100% of the time.
  • wts[1] = 0; //whatever is at pipes[1] will get called 0% of the time.

Getting a stream of them would be

0,0,0,0,0,0,0, which might represent whistling the same note over and over again.
Setting the weights to

  • 0 = .5
  • 1 = .5

Getting a stream of them might be

0,1,0,1,1,0,0 which might be the jaws theme, or a two note chord depending on how fast they are played back.
The percentage of values gotten will get close to the weighting set. The weighting can be reset, so one can imagine a music game teaching the kid chords, at first one note at a time, then the weights being reset to teach them together, then the next section teaching a new chord, and after a review game, perhaps the valve will be stuck partly open to handle notes the kid is hard at hearing. Cogs is a good approach to managing these score sections.
The contents can be anything from quiz problems, particle, to enemies on a battlefield. The number of elements included can be arbitrary large, representing the game from beginning to end. The random ensures some variance, and replayability. Say we have a 100 different types of enemies that cover a game. The weights can be reset over time, their weights even tweened. The distribution might be

Level1: 1, .5, 0, 0...

Level2: .1, .7, .2, 0...

Level3: .1, .2, .5, .2 ...

Which graphically looks like a ripple moving from left to right, and from the users experience can be a smooth progression of difficulty. But it might not be exact from one replay to the other.

Last night I was able to get it and it's unit test converted to AS3 ( which took some wrangling, thankfully Array can be extended unlike most other types). Coming soon is CollectionManager which adds event management for collection changed, and toXML to present XML views (like used for TreeComponents)

AS2 to AS3 Conversion Annoyances

After using FDT and MTASC both with strict compilation, I was thinking that converting to AS3 would be straightfoward. Alas.. no.

Some of it is syntax, but frequently in the pursuit of performance or architectural benefits, I had to take advantage of tricks or in the language, and many of these hacks are breaking, or rather even some of the core features no longer work on the AS3 architecture.

Nullable types bye..

For all the type strict typing in AS3, one of the biggest annoyances is the removal of nullable types. This has had profound impacts on migrating code.

what used to be

public function doSomething(var aNum:Number):void{
if(aNum == null){

aNum = DEFAULT_NUM

}

}

Now I have to use   aNum:*  which makes it harder to read, and now I have to introduce argument type checking in the method body, quickly adding to the size. Grr.  What's silly is you can still create without initializing vars e.g.

var numA:Number;

//sometime later, what is numA before this?
numA = -1;

in addition, var obj:Object = numA is a legal call. So.

I'd be happy if they make a separate nullable type e..g NullableNumber that extends Number and that NullableNumber is itself finalized.

Initialization  

The intialization into the function signatures is neat and increases readability, but totally flummoxes collections when your defaulting to the length of the array, here again we have to use the wildcard, which defeats type checking during compilation.

For in...Goodbye 

For in was a useful tool to introspect values and interate over collections. Of course since this uses the prototype chain which is slow it's been relagated to only looking at the prototype chain, as most the variables and method have been moved to the fixed class inheritance, many uses of introspection have been broken, all over the place.

« Previous Entries