<Head> Conference is rocking! and thoughts about the past and future of webconferences
It's all about getting ... <head>
Dude, this is the way conference presentations should be. Hella fun. No messy travel plans, No standing in lines at airports, No rental car misadventures with wrong MapQuest printouts. No need to dressup. No consuming bad closest-restaurant-to-hotel food+coffee. No worrying about hooking up the projectors, no worrying about having enough battery power, or being close to an outlet, or being able to read the slides clearly behind the head of the person in front of you, all the while juggling the cup of coffee and danish and laptop in the lap. No trying to rush get to the session conveniently located the opposite end of the convention center, only to find the room already at capacity. No staying up late nights adding last minute details to presentations... well okay that's tradition.
I'll be presenting in a few minutes in room 2 (schedule changed) on 'One SWF' to rule them all on what I think is a very cool approach to maintaining swf portability between web and AIR runtimes, which wasn't possible in Flash9, not sure about the Flash10. I'll be showing an app that when running in AIR can create, update, read and delete images from a webcam to the desktop, and when running the same swf running from the server, can create, read, update, and delete those images on the appropriately configured server via a PHP All with only a few paragraphs of code. Try that with C++!
It's day2 at if you're not "there", you should definitely check it out, I'm loving it. It's a distinctly different flavor than the traditional conferences I've been to so far like Max, Flex|360. Also if your in San Fran, London. you might be able to still attend one of the live hubs. Even Second Life.
Having helped run a few conferences and presented a few times, I know how challenging and rewarding putting on an event like this can be, I've been on all sides of the podium, IT, organizer and presenters. This conference (like all) has had some significant technical issues. But really the problems are expected, it's how the team recovers, and managing expectations. So far Aral and his team are doing a great job rolling with the punches. In the end as disappointing as it is for all when a presentation doesn't work right, the chat always works so in some ways it's more collaborative than the normal conferences.
It's my first time attending a conference via Connect, counter intuitively I find it's pretty intimate, a buzz of chat, the low threshold in which anybody can join the fray. the live face of a person talking, and well miced, bandwidth permitting.
The Past of Online Presentations
Waxing philosophical. It's funny how life can take you round full circle. Back in 2000 right, right after the first wave of dot-com-fallout. I joined a small company called Presedia who had the same goals I mentioned in the first paragraph. At the time, somewhat at the start of the first internet bubble, the web was in it's first golden age. Presedia's target was the corporate market, where as R&D turned into commercialization, routine "Road Shows" would be organized to put gobs of salespeople in the same room, up to date on what they would soon be selling. Getting 1000's of people across the country into the same room with enough donuts wasn't cheap.. gas wasn't $3-4/gallon either at the time.
So Presedia had the simple idea, make PowerPoint web friendly, add a plugin to the desktop to narrate, it, and upload it, share it, have it play in the webbrowser. As an aside, I think that Microsoft's failure to make the office suite web friendly has spurred countless competition like this.
The first client for Presedia, was...Sun Microsystems, which had just 3 years earlier created the Java programming language. Java was the darling of the day, applets were going places that html and even Flash just couldn't touch. As at the time Flash 4, just turned to Flash 5, scripting was still mostly timeline hacks, like instead of a function, it used gotoAndPlay("doSomething") !!! for loops were gotoAndPlay, then gotoAndPlay! (and we had to walk uphills both ways, with dialup).
After getting a reliable presentation narration, and conversion. Ironically, Java as the front end on the network (in particular sun) was very finicky about streaming through corporate firewalls and after months of headbanging. I in a bold move told the CEO and President that we should explore using Flash for the presentations and player, at the time I was a server side engineer working in Java. I was the only person in the team with any design ability, or any particular care for what is now the IxD field, and could put up with Flash's extremely quirky nature. So I was asked to come up with a prototype which I built by hand, and the CTO started investigating rendering PowerPoint to Flash instead of Java. This was a rather significant and positive step for both Presedia and myself.
Turns out for me, that working with visual components made me far happier than working purely server side, and my intuitions that Flash > Java for the presentations were correct. We had far fewer problems, and the presentations streamed and started better. Fast Forward... Presedia became Macromedia Breeze, and Breeze became Adobe Connect which is the technology, that powers the conference. And I've been preparing yet another PowerPoint to get converted to Flash. Deja Vu!
Given that was 10 years ago, makes me wonder, did Dinosaurs have PowerPoint?
Another strange connection, is one of the conferences I helped organize was largely Singularity oriented, and in it's recent incarnation has turned into "SingularitySummit". The original name of the conference was Singularity, which confused me for the longest period of time.
The other amusing bits, at the time PowerPoint to Flash was a very proprietary and expensive thing to purchase. Now PowerPoint to Flash conversion is in the commodity camp. There are $50-$100 stand alone tools with unlimited, and Open Office will do it for free. I'm actually using Open Office (built in Java) to create the presentation for the talk, that will be converted to Flash.
The Future of Online Presentations + Conferences
I think that <head> is a good example of how conferences are going to go. In many ways is a parallel to the way home theater is competing with traditional movie sales. With the ubiquity in highspeed bandwidth, the sensory impact between online and physical conferences is less, and in some cases opposite, online can have higher fidelity than live. Like I'm watching on a big screen perfectly setup, I have headphones, the speakers have headphones rather than drifting in and out of the mic.
In head's level, the convenience overshadows other. As the technology get's more solid with tools like Connect, the barrier to entry drops, it takes less skill, costs less for all, takes less time. Soon kids will be throwing conferences for kids.
Having participated in 'unconferences' and 'conferences'. <head> took a nice middle ground. It was scheduled so I knew what I was going in for, but the sessions were 30minutes, which like TED talks reminds me that brevity is a powerful ally. As since we are on the web, further details are only a few clicks away. It felt very different more like a group of friends piled into the living room vrs attending church. It felt more community oriented than hierarchical. With the chat window on the bottom, and back channel communication with other speakers, it felt very much like a dashboard...it was reassuring where as live presentations, sometimes no audio man, just a bunch of people sitting quietly it often feels a bit exposed.
There is a qualitative difference in the stress levels of the speakers. I'll call it the "home turf" advantage. Most of the presenters presented as they lived, either at home, or at work, a few like myself rolling out of bed, walking into the home office a few feet away. relaxed. Some taking beer breaks in the presentation! (hey it's the weekend). One was even presenting in a car, via a community wireless she just found, where she parked.
This is to me a success of the web, taking the best that people have to offer, of the people across the world, without taking them out of their normal elements. The presentations are a bit rougher, more improvised, briefer, but what they don't offer in 'performance' they more than make up in charm, and commradarie. Especially in today's rapid moving times, the nature of a presentation being a dialog than a narrative feels appropriate. With the audience at all levels, a dialog is also the best way to ensure that people at all skill levels are at the same page. Rather than stilted, they feel more honest, more philosophical, more heartfelt, less of a corporate agenda, many of the goals weren't at a tech level, but rather increasingly purpose driven. In each presentation the person's personality showed through. All a very positive experience.
I missed most of Friday's sessions, (partly due to work) now I'm sorry I missed them, I suspect that this is one of the challenges for virtual conferences, it's harder to cleanly separate the time for a conference as when it's a trip. Though at least for me, I end up finding conferences filled with work anyway.
With the upcoming tide of virtual conferences, one thing I think this all means to presenters, are you should get used to having:
- a decent webcamera, ideally a decent backdrop (unless you've got a green screen like Aral) $20-30
- decent light, as webcams suck on low-light. A window nearby will do, but at night time I was practically invisible until I pointed some lights on me. Aral in the excellent speaker orientation recommended a firewire plus conventional DV cam, which is a good though far less portable
- a good headset mic - knowing how to set it up, adjust levels $30 at Radio Shack
- have a few subjects you could contribute to the community, in your backpocket you can present easily. Note you don't have to be a super genius, the community exists at all levels.
- that the number of conferences is increasing to a steady dialog. So in some cases picking.This reminds me over burningman, in that you won't be able to experience everything, so you have to prudent in what makes it and not. Even though many of these conferences will be recorded and later made public, there is something about being there able to see it unfold that makes it more special, perhaps it's just the allocation of time and attention.
Here are some other pics and reviews.
Jeremy Adactio (with pics!)
Mark Grossnickle attendee, )
Flash: Detecting the end of an animation
Say you have an animated character in a game, that others need to know when they are through playing their animation. Here are a few approaches:
Let's first assume we have a generic object named 'player_mc' that is our animation. We also have a centralized controller script closer to the root, that has a function like:
-
function onAnimationComplete(evt:Event = null):void{
-
//do something
-
currentPlayer = evt.target as MovieClip;
-
currentPlayer.gotoAndStop("still");
-
}
Note that we use evt = null just in case we want to use call the function without passing it an event.
1) Using addFrameScript
-
var init:Boolean;
-
if(!init){
-
/// !init check, this block is only needed when pasting on timeline
-
// to keep it from activating more than once when the movieClip recycles
-
addFrameScript(totalFrames -1, onAnimationComplete);
-
init = true;
-
}
-
-
Just remember if doing that approach, addFrameScript uses a frame number one less that what you see in Flash.
This approach is safer when indexing frame labels prior (e.g. with UIUtil) to map say a frame label of "AnimationFinishedFrame" to the frame number for addFrameScript to use.
-
addFrameScript(com.troyworks.ui.UIUtil.getNumberOfFrameLabel("AnimationFinishedFrame", onAnimationComplete);
-
2) Using Event Bubbling
Just communicate up the display list.
-
player.addEventListener("ANIMATION_COMPLETE", onAnimationComplete);
Then
-
//inside the player on last frame of the player animation
-
-
stop();
-
dispatchEvent(new Event("ANIMATION_COMPLETE", true, true));
For more info see here.
3) Use Singleton/Static or Stage as a message bus.
like 2 but using the stage or some other easy to access to communicate without bubbling.
4) Poll for Progress
This is a bit more work, but get's you the ability to find out more about the progress, eg. showing a progress bar for percentage played.
-
player.addEventListener(Event.ENTER_FRAME, onENTER_FRAME
-
-
function onENTER_FRAME(evt:Event):void{
-
var playermc:MovieClip = evt.target as MovieClip;
-
-
if(playermc.currentFrame == playermc.totalFrames){
-
onAnimationComplete();
-
}
-
}
Hope that helps.
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!
( 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: Working with Events: Get on the bus..Bubbling is your friend.
One of the great changes in AS3 is the DisplayList. It when used appropriately, dramatically eases many things, one of my favorite is decoupling clip intercommunication, as the display list or any clip on it can act as a message bus.
Approach 1 : Display list heirarchy as message bus.
Say you have a monkey button shaped as a deep in a forest of tree graphics that you want to find out when it's been clicked on, even while it's jumping around from branch to branch (at different depths). If a event setup on the click is set to bubble it doesn't matter where or how deep it is, it will eventually bubble up to the parent class so you can do something with it.
Similarly say you have a animated figure that you want to fire off when it's completed with it's animation, to do something else. While one possibility is the 'controller' reaching down to watch (e.g. using ENTER_FRAME, or addFrameScript(totalFrames-1..), or the clip reaching up and telling the main timeline to do something. A much cleaner approach is listening for the event closer to the root (e.g. a document level class), and dispatching an event on the last frame like:
dispatchEvent( new Event("FINISHED_ANIMATION", true, true)); //last help it bubble
Approach 2: Stage as message bus.
Third is using a stage as a message bus, since every clip has access to it. Especially when used with the ADDED_TO_STAGE event and dynamically loaded assets that have to perform some functions before being ready or passing a set of values to a caring class, when using an event that can carry a generic message, like EventWithArgs.
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.
-
package {
-
-
import flash.display.MovieClip;
-
-
import flash.display.Sprite;
-
-
import flash.display.StageAlign;
-
-
import flash.display.StageScaleMode;
-
-
import flash.events.Event;
-
-
import flash.text.TextField;
-
-
public class StageExample extends MovieClip {
-
-
public var sizeMe:MovieClip;
-
-
public var output_txt:TextField;
-
-
public var textLog:Array = new Array();
-
-
public function StageExample() {
-
-
super();
-
-
stage.scaleMode = StageScaleMode.NO_SCALE;
-
-
stage.align = StageAlign.TOP_LEFT;
-
-
stage.addEventListener(Event.ACTIVATE, activateHandler);
-
-
stage.addEventListener(Event.RESIZE, resizeHandler);
-
-
addEventListener(Event.ENTER_FRAME, onFirstFrameRender);
-
-
addEventListener(Event.RENDER, renderHandler);
-
-
addToLog("constructor: w " + stage.stageWidth + " h " + stage.stageHeight);
-
-
addFrameScript(0, onFrame1);
-
-
stage.invalidate();
-
-
}
-
-
private function onFrame1():void {
-
-
addToLog("onFrame1: w " + stage.stageWidth + " h " + stage.stageHeight);
-
-
//resizeHandler(event);
-
-
}
-
-
private function activateHandler(event:Event):void {
-
-
trace("onFirstFrameRender: " + event);
-
-
addToLog("activateHandler: w " + stage.stageWidth + " h " + stage.stageHeight);
-
-
//resizeHandler(event);
-
-
}
-
-
private function onFirstFrameRender(event:Event):void {
-
-
trace("onFirstFrameRender: " + event);
-
-
addToLog("onFirstFrameRender: w " + stage.stageWidth + " h " + stage.stageHeight);
-
-
// resizeHandler(event);
-
-
removeEventListener(Event.ENTER_FRAME, onFirstFrameRender);
-
-
}
-
-
private function renderHandler(event:Event):void {
-
-
trace("renderHandler: " + event);
-
-
addToLog("renderHandler: w " + stage.stageWidth + " h " + stage.stageHeight);
-
-
}
-
-
///////////////////////////////////////////////////////////////////
-
-
private function resizeHandler(event:Event):void {
-
-
trace("resizeHandler: " + event);
-
-
trace("stageWidth: " + stage.stageWidth + " stageHeight: " + stage.stageHeight);
-
-
addToLog("resize: w " + stage.stageWidth + " h " + stage.stageHeight);
-
-
sizeMe.width = stage.stageWidth;
-
-
sizeMe.height = stage.stageHeight;
-
-
}
-
-
private function addToLog(str:String):void
-
-
{
-
-
textLog.unshift(str);
-
-
output_txt.text = textLog.join("\r");
-
-
}
-
-
}
-
-
}
Flash: 4 Tricks for using MovieClips as Buttons
So here are 4 tricks I've found useful:
- Use actionscript to create the Button behavior (enlarging etc), centralizing it in one place.
- Use clips styled in the IDE, and copy their style/filters for mouse over, down, disabled state.
- Use mouseEnabled (and alpha/brightness) to temporarily disable a button
- Use the instance
nameas the label, and in the event parsing.
Styling MOUSE_OVER, MOUSE_DOWN States
Similar to CSS centralizing style, centralizing behavioral style offers the same maintenance advantages. Using clips on the stage for style allows the designer to visually see what's desired, rather than spending countless iterations tweaking actionscript to get it right, it's a good handoff in team based approach. I also sometimes use describeType 'autowire' any buttons of particular classes. For the disabled state I stacked two brightness filters ontop of each other.
Styling it to send all the events to a central controller (MVC UCM style), allows things to be debugged far easier than when events are going everywhere, and the controller has internal state, respond appropriately, say ignoring all clicks during loading, without having to rewire all the various components.
For 1 and 2 here's the underlying code. Notice I use mouseChildren = false to keep the label textfield from generating events.
-
-
function configureMC_Button(ary:Array, addL:Boolean = true):void {var a:MovieClip;
-
-
var i:int = 0;
-
-
var n:int =ary.length;
-
-
for (true; i < n; ++i) {
-
-
a = ary[i];
-
-
if (addL) {
-
-
a.addEventListener(MouseEvent.MOUSE_OVER, onMouseOverHandler);
-
-
a.addEventListener(MouseEvent.MOUSE_OUT, onMouseOutHandler);
-
-
a.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
-
-
a.addEventListener(MouseEvent.MOUSE_UP, onMouseOverHandler);a.addEventListener(MouseEvent.CLICK, onMouseClickHandler);
-
-
a.mouseChildren =false;
-
-
} else {
-
-
a.removeEventListener(MouseEvent.MOUSE_OVER, onMouseOverHandler);
-
-
a.removeEventListener(MouseEvent.MOUSE_OUT, onMouseOutHandler);
-
-
a.removeEventListener(MouseEvent.MOUSE_DOWN, onMouseDownHandler);
-
-
a.removeEventListener(MouseEvent.MOUSE_UP, onMouseOverHandler);
-
-
a.removeEventListener(MouseEvent.CLICK, onMouseClickHandler);
-
-
}
-
-
}
-
-
}
-
-
function onMouseClickHandler(evt:Event):void {
-
-
var mc:MovieClip = MovieClip(evt.target);
-
-
output_txt.text =(" \r"+ mc.label_txt.text + "**Clicked **");
-
-
}
-
-
function onMouseDownHandler(evt:Event):void {
-
-
var mc:MovieClip = MovieClip(evt.target);
-
-
mc.filters = downTreatment.filters;
-
-
}
-
-
function onMouseOverHandler(evt:Event):void {
-
-
var mc:MovieClip = MovieClip(evt.target);
-
-
mc.scaleX = mc.scaleY = 1.2;
-
-
mc.filters = overTreatment.filters;
-
-
}
-
-
function onMouseOutHandler(evt:Event):void {
-
-
var mc:MovieClip = MovieClip(evt.target);
-
-
mc.scaleX = mc.scaleY = 1;
-
-
mc.filters = [];
-
-
}
-
-
overTreatment.visible = downTreatment.visible = disabledTreatment.visible = false;
-
-
configureMC_Button([a_btn, b_btn, c_btn, d_btn, e_btn, f_btn, g_btn]);
Enabling and Disabling via ActionScript
You can disable/enable a clip simply by using the mouseEnabled field which will turn on or off mouse events. Contrast this with the approach of adding/removing listeners to enable or disable a button, which may have multiple listeners for different classes, you can't see, so you never know if you got them all.
-
-
function setEnabled( ary:Array, enable:Boolean = true):void {var a:MovieClip;
-
-
var i:int = 0;
-
-
var n:int =ary.length;
-
-
for (true; i < n; ++i) {
-
-
a = ary[i];
-
-
if (enable) {
-
-
a.mouseEnabled = false;
-
-
a.filters =[];
-
-
} else {
-
-
a.mouseEnabled = false;
-
-
a.filters = disabledTreatment.filters;
-
-
}
-
-
}
-
-
}
-
-
setEnabled([d_btn, e_btn], false);
Using the instance name as id.
Using the instance as the basis for identification, saying parsing it for use the label, and in the event, can make things more uniform than having buttons dispatching events,. In internationalized apps where the label changes based on whatever language is present, the instance name can serve as a key to finding the appropriate text in some multilanguage dictionary, or even show when a label is missing.
In Closing
Using a single movieClip has many advantages, only one skin has to be created instead of 4-5 for a SimpleButton. When handled in the way outlined above it has many of the advantages of being a component, without the work of being a full blown one. It minimizes the number of classes/library items when each button is created with a unique label hard coded into it.
In conjunction with a tweening engine, it allows for what I call momentum styled buttons. Buttons that don't have crisp state changes like SimpleButton attempts on the mouse up/over/down. Things that fade up, and down, like real world lightbulbs, cars. When used with ColorTransform this can allow for adaptively styled UI, like that of CSS.
There are also safety benefits. In AS3.0 the timeline is purely script driven, there are still bugs when using multiple frames to manage state on particular versions of the flash player. I've had odd issues with sound not firing or not stopping firing, components blowing up when in tweens or in timelines.
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.
- imports are only needed once in a timeline
- variables declared on a frame, end up as class variables,
- you can't redeclare variables on multiple frames.
- 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,
- 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(){
}
- 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
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.
