What is FlashFirst?
Let's define an RIA as a stew of tasty graphics, sounds, business logic, script assets, controls etc. The end product might be a game, might be a traditional website with non-page based navigation, might be serious application like Photoshop or Word. Across all of these, separating the UI elements from the underlying logic leads to easier to maintain applications.
FlashFirst describes the workflow of using Flash CS3 output to ignite the experience, much as in normal 'test movie' or 'publish' outputting say "UI.swf" with the key difference that all the script is in a second swf file (e.g.
script.swf) , which may be built from Flash or Flex. This is the opposite of most Flex workflows where Flex compiling has control and loads up the appropriate graphical assets from Flash.
FlashFirst in it's best incarnation, follows MVC design patterns near perfectly, the User interface is from flash (e.g. UI.swf) the controller loaded up by UI is a separate swf (e.g. controller.swf) with no/minimal User Interface, and the model is often from XML, jpg, CSS, AMF.
The two patterns for FlashFirst
The default way it works is UI.swf->Engine.swf->assets... So in detail user starts up the UI.swf, which pauses itself, loads up the controller Engine.swf into itself, which takes over the preloading of assets, fonts, internationalization, configuration. Once through preloading the engine tells the swf to resume playing, as things are added and removed from stage and via the magic of addFrameScript to well defined contracts in the form of instance names, class types, and framelabels. The UI elements are enhanced with interactivity, possibly based on configuration on stage.
Say in a jigsaw puzzle, you have a MovieClip on stage, with instance name 'game1_jigsawpuzzle_mc', inside that clip on a frame script might be something like
var config:Object = new Object();
config.numPiecesVertical = 4;
config.numPiecesHorizonatl = 4;
Which the listening game engine (e.g. jigsawpuzzle_engine.swf) would be listening for scene requiring it's services (e.g th instance name of the clip "game#_jigsaw") to be loaded, and then using to slice up the image on stage into 16 pieces.
A second case is a Starter.swf loads in the UI and passes it some initial configuration settings that override the defaults, say jump to level2,. So in that case Starter.swf->UI.swf->Engine.swf->assets... This is similar to using FlashVars passed into a swf running inside a webpage.
Why FlashFirst?
The clean separation between UI and Logic, allows for easy maintenance, both in reskinning and feature enhancement. Say you have a game, that you want to be rethemed for every season, one logic, clone the Skin file a few times, adjust the graphics to fit each season. Sometime later it's decided that there is a bug to be fixed in that game, but the UI Files and fonts were lost in the great harddrive crash of 2007, and the primary designer (on a Mac) was killed in a bizarre velcro wall accident. Despite these horrible occurances, provided the contracts are the same, a new engine can be deployed just by dropping in a new file, without finding and republishing the UI. Even better, if the UI is generic enough, new products can be created by different engine features not known at the time of developing the original UI. e.g. for a math game, simple, intermediate, and advanced addition, a new series on multiplication is added.
Adobe is pushing Flex hard, as they should, it's a great ...if heavy handed tool/framework. One of the things that have always appealed to me is Flash's ability to push beyond standard UI and work on high experience quickly, prototyping, new components, and historically Flex starts to break down. Most of the projects I work on, it's really the Flash Designer hitting compile a billion times tweaking the graphics and tweens that is pushing that creative edge, often in constraints that Flex can't squeeze in either size or framework.
Another gripe is many apps produced with Flex look, "Flexy", and while generally superior in UX to RIA's DHTML+Javascript, Flexy doesn't represent the brand and experience that most client and designers want.
Flash is awesome rapid prototyping application. I've creating essentially functional (meaning only the bare essence) mockups and prototypes *while sitting in meetings with the client* given the ability to draw, drag and drop, work on a timeline and integrate photos from whiteboards or video.
The Creative First frequently has designers designing in a vacuum outside of IA and Useability, miss critical things or overshoot on experience resulting in overbudget catastrophies that aren't useable.... like reinventing scrollbars, and creating obnoxious keyholes everywhere, as they haven't mastered fluid layout yet, and in the Flash world it has to be built by hand.
Why AMF Rocks and beats XML
Ted made a great summary of why AMF is Flash's file format of choice.
http://www.onflex.org/ted/2007/11/abcs-of-amf.php
While I've touted the benefits about persistence and serialization of native classes in previous posts (see persistance or serialization categories). Often XML is preferred for data interchange with servers or text editor compatible configuration. Here Ted had a gem in the comments, comparing why using XML inside of AMF over XML in a text file, rocks!
E4X is super handy for querying the data and returning collections after parsing to xml. That said XML is a native object and can be included in AMF3. The data is stored as a string zlib compressed and when deserialized becomes an XML object again.
bytes.writeBytes( new XML('') );
This gives you zlib compression and benefits of e4x in one go. zlib is very effective on xml and can compress documents as much as 20X, I have seen 300Kb XML files become 7K given tag redundency in the ASCII text.
The XML human readable is important as often for games and such that I build, but frequently it's doesn't make sense to build a configurator given the many excellent XML editors out there. In addition it's very easy for most servers to generate, where they can't generate AMF as easily. But there are two compelling benefits to going that route:
1) As the XML grows, compressing things by up to 20x can improve the responsiveness of the application (like startup of a website), and reduce network costs.
2) XML stored this way is native data type to Flash not a string...meaning it's already an XML accessible to E4X instead of a random string that has to be parsed into XMLNodes. Reconstituting the data out of the AMF stream still takes overhead, but it should be much faster than parsing it from interpreting tags and attributes from the plain text, as most the marshalling code is in C inside the player instead of actionscript. Read better experience for end users.
What occurs to me now is that either a very simple AIR app act in a similar fashion to Winzip for compressing/decompressing text for consumption by flash, or act as a simple text editor, just using a text field.
I'm sure that Adobe will open up the AMF API so that servers can generate raw AMF without using remoting or RMTP. This will open up the possibilities for CMS driven websites to prerender sites daily out of database requests.
Flash CS3: Drop Shadow Filter dissapearing on art Bug +MovieExplorer rescue
Took me a bit to find this. We are importing several characters drawn in Illustrator, adding any Filter, while the filter appears fine on the timeline, it dissapears when published.
After some digging errant empty TextFields are getting inserted into the art with no name and no text, and removing them fixes the issue. Though getting to them can be tricky.
Open up Window>Movie Explorer, make sure the first button at the top with "A" is depressed but nothing else, and in the far right icon, press it and make sure symbol definitions is turned on. Then start looking for TextFields that look like "--A (empty)" in the display. Double click on it and insert a long string like "AAAAAAAAAAAAAAAAAAAAAAA" as soon as you click off you should start seeing the text start poking out of the art. If you need help, look at the bottom path on the MovieExplorer "Scene 1-> Layer 1-> Frame 1->" what may be happening is the TextField isn't on the first frame so right-click 'go to location' won't actually get you to it.
I'm unsure what is causing them, it could be the designers just clicking the Text creation tool by accident, or an Illustrator to Flash import bug. I'm pretty sure it's a bug in Flash not to render the filters, but at present I'm too busy to dig deeper.
First Learning Flash for experienced programmers.
> Can you suggest a good basic book that I should read to start learning Flash? I already know C, C++
First there are multiple parts all called "Flash". there is the Authoring Environment (Flash CS3), the Flash Source Files (*.FLA ) the compiled output (*.swf) actually run, and the virtual machine (The Flash Player).
Flash is an large ecosystem from mobile phones to web apps, to desktop applications, with whole books dedicated to those niches. As for basic books, I'd recommend going down to Barnes and Noble or Borders and checking out which book appeals to you most. Look for "Flash CS3" - the authoring environment.
One of the great things about flash is the strong community of development, the web is filled with tutorials and blogs and communities. Just about any question plus the "Flash" keyword you'll find answers and sample files for.
http://www.adobe.com/designcenter/flash/articles/flash_resources.html
For more programming oriented topics I recommend these books:
Actionscript Cookbook, most common things e.g. 'how do I load an image?'
http://www.amazon.com/ActionScript-3-0-Cookbook-Application-Developers/dp/0596526954/ref=pd_bbs_sr_1/002-4323525-9615269?ie=UTF8&s=books&qid=1194986914&sr=8-1
Making things Move (how to use script to animate, create particle simulations)
http://www.amazon.com/Foundation-Actionscript-3-0-Animation-Making/dp/1590597915/ref=sr_1_5/002-4323525-9615269?ie=UTF8&s=books&qid=1194986703&sr=8-5
Essential Actionscript -the nuts and bolts
http://www.amazon.com/Essential-ActionScript-3-0-Colin-Moock/dp/0596526946/ref=pd_sim_b_title_2/002-4323525-9615269
Actionscript 3 with Design Patterns
http://www.amazon.com/Advanced-ActionScript-3-Design-Patterns/dp/0321426568/ref=pd_bbs_sr_1/002-4323525-9615269?ie=UTF8&s=books&qid=1194986703&sr=8-1
Some of the major differences from traditional programming languages you'll need to understand: Flash has a built in 'stage' (container for that which you can see) and multiple timeline(s) for visual state/animation, which can be edited in the authoring environment. To be successful in Flash is often knowing when to use the timeline and when to use script.
Like multiple transparencies on an overhead projector, each timeline is composed of a layers that can move independently . Timelines can be nested, say an animation of a car, might have wheel rotating animation duplicated inside it, so when the car moves the wheels move with it.
Like addresses on a street, timeline have 'keyframes' that can be labels one can navigate to. Simple commands like stop(), play(), and gotoAndStop("LosAngeles") allow you to navigate and animate from place to place, and keyframes can have actions performed when the 'playhead' renders them.
The whole script and ui is essentially a single thread redrawing at 2-31 frames per second. Flash was designed to stream across the web, so parts can be playing while other parts are still loading. Flash can load, other swfs, mp3, jpg, png, gif, xml, plain txt, and flv video easily, even binary data in Flash 9. Instead of dll's there is built in resource managment, so say a bouncing ball component once loaded, but not currently visible can be duplicated 100 times on the stage after it's loaded.
FlashCS3: Tip to speed compilation
Flash CS3 has improved compiling speed over Flash8, however seemingly innocent use fonts can still bring compile times to a halt. with a font like Futura, an missed 'embed All' can turn your compile times to 30-45 seconds, as every compiler requires Flash to copy every character in the entire world...every time. Needless to say 15-30 seconds doesn't seem like much, but if your compiling often, this can reduce
Going through and removing font embedding from every textfield is somewhat tedious. But you can use the MovieExplorer to help drill down, you may even find text fields you've missed. I'm sure somebody has a JSFL to help.
The other tips are when using Flash CS3 and blessed with a timeline, put a temporary script (gotoAndPlay) to skip the intros and tutorials to delve into the heart of the what your working on at any given time. When using Cogs you can do similar things by passing a non-default initial state in the constructor.
Using ByteArray to Serialize AS3 Classes for AIR, Web and Everywhere!
When using AIR's FileStream to write AS3 classes to ByteArray, I've found that the same file format works for loading in via URLLoader, as well as what's uploaded using FTP. This isn't surprising, but wanted to test anyway.
What this means is that ByteArray is a groovy ubiquitous format for storing full classes and dependencies and references, via ByteArray.writeObject and ByteArray.readObject (provided registerClass is used), without nececessarily having to parse them manually though that is still suggested for versioning and class evolution. Meaning you can create a file using AIR , send that file to a friend in email, and have them open it up in a flash based webpage, and they operating in a webpage could Http POST the change back to you. The ByteArray can have rich complexity, classes, self references, collections, etc. This could be used to save whole game states (even massive multiplayer, NPC brains, etc). Or in my target case debugging outside other non-AIR runtimes to speed development.
How to save to the same directory the swf AIR is running from
This took me a bit to figure out. Primarily as I'm using AIR to write the files in Flash CS3 and it's not immediately apparent in the docs, how to target the 'self' directory of the swf. This isn't recommended in the docs (which I agree) but in the case I'm using it for it makes sense to do so. The API for AIR is here
-
-
// this is in url path
-
var file:File = File.applicationDirectory.resolvePath( "example.jpg" );
-
trace("file " + file.url + " " +file.nativePath ); //outputs app:/example.jpg, and "C:\SomeDirectory\Somepath\example.jpg"
-
-
var wr:File = new File(file.nativePath);
-
// Create a stream and open the file for asynchronous reading
-
var stream:FileStream = new FileStream();
-
stream.open( wr, FileMode.WRITE );
-
stream.write.....
-
stream.close();
-
This would be swf._url in AS2, or in AS3 DisplayObject.loaderInfo.url , as when using relative links in URLLoader to load whatever you're saving this will resolve properly in AIR. Turns out flash.filesystem.File.applicationDirectory is the droid you are looking for. It's not fully qualified (e.g. file:C:\somedirectory...) when traced it looks like:
"app-resource:/yourSwfNameGoesHere.swf"
unless you use the file.nativePath which is required in order to actually write to the directory. So you can use still this in old school string name parsing the swf name out, so you don't have to use File.applicationResourceDirectory if your looking to make a single swf for both AIR and Web use, and on the web, the AIR libraries won't be accessible.
Here's two handy scripts to help inspect ByteArray's, the first looks at the 1's an 0's, the other looks at the objects in the stream, using the getQualifiedClassName, and if it finds an Array or sub ByteArray attempts to inspect it.
/* converts byteArray to binary like
TraceBits--------------------
0 = 110
1 = 1011
2 = 1001000
3 = 1100101
*/
-
-
function traceBits(bA:ByteArray) {
-
trace("TraceBits--------------------");
-
for (var i:int = 0; i < bA.length; i++) {
-
bA.position = i;
-
-
var inte:uint = bA.readByte();
-
trace(i+ " = " + inte.toString(2));
-
}
-
}
-
-
function traceByteArray(bA:ByteArray) {
-
var o;
-
var cnt:int = 0;
-
var cnm:String;
-
-
var o2;
-
var cnt2:int = 0;
-
var cnm2:String;
-
try {
-
while (true) {
-
o = bA.readObject();
-
cnm = getQualifiedClassName(o);
-
trace( cnt++ + " " + o + " : " + cnm);
-
if (cnm == "flash.utils::ByteArray") {
-
try {
-
cnt2 = 0;
-
cnm2 = "";
-
while (true) {
-
o2 = o.readObject();
-
trace(" " + cnt2++ + " " + o2 + " : " + getQualifiedClassName(o2));
-
-
}
-
} catch (err:Error) {
-
}
-
} else if (cnm == "Array") {
-
trace("array contents...");
-
try {
-
var ar:Array = o as Array;
-
trace("ar " + ar);
-
trace(ar.join("\r"));
-
} catch (err:Error) {
-
trace(err.toString());
-
}
-
}
-
}
-
} catch (err:Error) {
-
}
-
}
