Is AS3 Ready For Prime-Time? (part 1)

– taterboy | July 8th, 2008

Filed under: Flash, Flash AS2 to AS3, Tips

This is the first in a series of posts about some issues with Flash, ActionScript 3 and current work-arounds.

1. Timeline Animation and Scripting:
I could not believe this issue when I ran across it for the first time. I really hope it is a bug. If you have code on the first frame of a timeline, then advance the timeline, the objects on the next frame are not available to your code until the frame after.

This simple code does not work: (place code on frame 1 and place mc_clip on frame 2)
gotoAndStop(2);
mc_Clip.visible = false;

You get an error that says mc_Clip equals null if it did not exist on the first frame.

The rendering sequence has the script run before the items are added to the display list, so they do not actually exist on that frame until the next render sequence runs. With all of ActionScript 3′s benefits, I can not believe this oversight. After all Flash is a timeline based app right? Even Flex has a frame-rate.

I guess the correct Open Object Oriented approach is to have everything on each frame wrapped into a class? That way it could handle itself and all its children on initiation. But, it is still a time-line based app! To tell an object to do something on a particular frame used to only take 1 line of code, now, not so much.

The best work-around I could come up with after hours of experimenting is to do a frame loop to wait two frames. One interesting approach was to make a list of objects you need to interact with, then use the ADDED event to check for each item. Once they all come back as true, then proceed. This approach was not a consistent as the frame loop method. I built a not so simple class that handles the advance frame, waits until the objects on that fame are available to scripting, then calls a predefined method.

?View Code ACTIONSCRIPT
package com.hdi.utils{
	import flash.display.MovieClip;
	import flash.events.Event;
 
	public class FrameAdvance extends MovieClip{
		private var target:Object;
		private var frameNumber:int;
		private var frameLabel:String;
		private var callType:String; //_play,_stop
		private var endFunction:Function;
		private var childNum:int;
		private var countDown:int;
 
		public function FrameAdvance(targ:Object,frameNum:int,frameLab:String,type:String,endFun:Function):void{
			target = targ;
			frameNumber = frameNum;
			frameLabel = frameLab;
			endFunction = endFun;
			callType = type;
			countDown = 1;
			init();
		}
		private function init():void{
			if(frameNumber > 0){
				callType == "_stop" ? target.gotoAndStop(frameNumber): target.gotoAndPlay(frameNumber);
			}
			else{
				callType == "_stop" ? target.gotoAndStop(frameLabel): target.gotoAndPlay(frameLabel);
			}
			childNum = target.numChildren;
			this.addEventListener(Event.ENTER_FRAME,childAdded);
		}
		private function childAdded(ev:Event):void{
			if(countDown == 0){
				if(this.hasEventListener(Event.ENTER_FRAME)){
					this.removeEventListener(Event.ENTER_FRAME,childAdded);
				}
				endFunction();
			}
			countDown --;
 
		}
	}
}



source here

Technorati Tags: , , , , , ,

| 10 Comments » | facebook:

10 Comments »

  1. Flash has always behaved this way. I personally don’t consider it wrong. If you want total OO approach, you can always create movieclips programatically… Even if they were created in the authoring environment.

    Comment by Ante Vrli — July 13, 2008 @ 2:24 am

  2. I agree with Ante, I don’t see any change between AS2 and AS3 in this respect, except wih AS3 you’re correctly warned about your error at runtime rather than failing silently. Why would you want to access an object before it exists? That doesn’t make sense.

    Comment by pault107 — July 13, 2008 @ 12:22 pm

  3. This isn’t a bug, your code is constructed on the first frame (would you prefer the code created after your first frame??!) – so it cannot access something on the second frame. Scope of timeline + scope of code, sounds reasonable.

    Comment by Yan — July 13, 2008 @ 7:50 pm

  4. Great comments. let me try to clarify.
    Say I build a simple app. On the first frame is a loader, on the second I have an image and a button. I place all my loader code on frame one, then a handler on frame one that could look something like this.

    function imLoaded(ev:Event):void{
    gotoAndStop(2);
    someBtn.visible =false;
    }

    The code advances the playhead to frame 2, now does the button exist? I have not called the btn until the playhead advanced

    In AS2 this works fine. It is does not error out, because the button does go invisible. In AS3, this code works fine once the Display Object List updates. My solution above is basically says after a frame event, execute this code, the code on frame one. Maybe I am wrong, but It seems that the display list is updated before code execution in AS2 and reverse in AS3.

    I agree with your comments above, that is this probably not the correct way to do this, but it is practical and has worked in the past. The object would not require using code on every frame, maybe in a document class or neatly condensed on frame one.

    Thanks all for the interest in the blog and your comments. They are helpful to me as a designer and hopefully others in the same boat.

    Comment by taterboy — July 14, 2008 @ 7:17 am

  5. Hey Taterboy

    The example you give in your above reply wouldn’t work in AS2 or AS3. All code is executed *before* the frame moves forward, so even though you code gotoAndStop(2) before setting the button visibility, you don’t hit frame two until all of the code on frame one is executed. So, when setting someBtn.visible to false the button wouldn’t exist and would remain visible when advancing to frame 2. With AS2 this would fail silently, AS3 will throw a run time error – I just tried it to make sure.

    Comment by pault107 — July 16, 2008 @ 1:14 am

  6. EDIT: I take it back – your example does work in AS2 – I forgot to change the .visible to ._visible for the AS2 version. Hmm, that’s not what I expected. Now I see your point, but I would say it’s something you’ll just have to get used to a it’s not a bug, AS3 just enforces best practices more stringently.

    Comment by pault107 — July 16, 2008 @ 4:48 am

  7. Hmm, it looks like I misunderstood the issue. I just did a quick Google and I can see that many people are having issues with this.

    E.g – http://www.richardleggett.co.uk/blog/index.php/2008/02/18/enabling_access_to_timeline_items_in_as3

    It’s interesting that I’ve been using AS3 daily for the last year, have coded many apps and games and I haven’t come across this issue. I’m guessing that’s because I rarely use the timeline.

    Sounds like the issue is a bit of a nasty one though if it affects you. Why haven’t Adobe issued a patch for player 9? Seems a bit odd, unless the fix isn’t possible without a major overhaul of the code.

    Comment by pault107 — July 25, 2008 @ 7:34 am

  8. That is a great discussion. I found that when I was looking for a solution. It was past midnight and I was knee deep in a game conversion from AS2 to AS3, but neither stage.invalidate() or frameScript tips worked in my case. I would definitely do something different if I was building something from scratch. Now that I know.

    Comment by taterboy — July 25, 2008 @ 8:00 am

  9. The problem Aodbe has created with this bug is that they’ve completely screwed up the workflow for many people approaching Flash from the design side.

    My preferred workflwohas me setting up game states – title, game, win, lose, high scores – on labelled frames. i’d put all my code in the first frame and say stuff like

    initGame = function():Void
    {
    gotoAndStop(“game”);
    someJunkOnTheStage.doStuff();
    }

    This does not work in Actionscript 3. Instead, i have to set up my game states in separate movieclips and instantiate them, and then add them to the display list. This is already a lot more work. And what it prevents me from doing is DESIGNING my game. Codeheads are happy just throwing elements at the stage from the library and positioning them in code, but for those of us born with EYEBALLS, we like to actually see how things are going to look before our work is compiled.

    If a button is sitting too far to the left, i’d much rather grab it with the mouse and move it over, seeing the result instantly, than to adjust a line of code from myBtn.x = 300 to myBtn.x = 310 (or 320 or 330 or 331.5 or who the Hell knows?)

    My current workaround, and i’m not happy about it, is to lay out the game states with comments instead of frame labels. Then i put my game screens into movieclips, and put those movieclips on the stage in a guided layer. This way, everything’s laid out the same way, and i can futz with stuff the way i used to, but am forced to program and use a GameScreenManager class to add and remove the screens and prompts to and from the stage.

    So, in a word, “GRR”.

    Comment by Ryan Henson Creighton — November 7, 2008 @ 6:04 pm

  10. I am totally a hands on developer, I am an artist first. I want to see how everything looks on screen and tweak it till it is perfect.

    One idea I have been messing with lately is using includes (include “actionScriptFile.as”;) on the different frames/states of my project. This way I can keep all my code organized and have my objects on different frames just like I did in AS2.

    The code runs when the frame loads and I do not have to look all over the place for code. This is also an alternative to making everything into a class and exporting all your MovieClips to Action Script which screws up your loading screen. I am not advocating this as a total and only solution, just another tool or method of working on the timeline, which I am still very partial to.

    Comment by taterboy — November 14, 2008 @ 1:55 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

*