views:

118

answers:

3

Hello,

I am using the frames in the timeline of a .swf as pages in a flash app. The user can advance to the next page by clicking a button that takes her to the next frame. Similarly, it is possible to navigate to the previous frame/page as well.

Most of the content is placed on the stage (i.e. created by dragging an instance of a library symbol to the stage) but properties of those instances, such as .visible might be changed via actionscript. Also, some objects are loaded from external flash files and displayed programmatically with addChild / addChildAt.

The problem is, if I am on Frame N+1 and there is an object displayed on the stage programmatically (i.e. with addChild, not by having it placed on the stage) and navigate to Frame N where there is an object that is placed on the stage (i.e. dragged from the library), then the instance of that object is undefined/null and throws an error if I try to set its properties (like .visible).

The error does not occur if I am moving to the NEXT frame, only if I am moving to the PREVIOUS one. Therefore I assume that some kind of initialization is not getting called while going one frame back.

I was also thinking that the objects would just not "live" to the next timeframe, that is, their value would be lost and re-initialized because of scope, but if there is no dynamically created object on the stage, I can navigate back and forth just fine.

Is there a way to ensure that the objects created on the stage do not disappear while navigating back to the previous frame?

Cheers,
Zoltan

A: 

I'm not sure I got your question right, but as3 does not instantiate elements on the timeline as soon as you gotoAndSomething, but later that frame. That is, you can't

this.gotoAndPlay(10)
this.elementOnTimelineFrame10.DoSomething()

without errors.

ptor
Exactly, that is what I am trying to do. Is there a way to delay execution of the rest of the code (that is, this.elementOnTimelineFrame10.DoSomething() in your example)until after the elements get instantiated? For example, with an event?Zoltan
Zoli2xa
never had luck with that. I resorted to always create/manage via AS and leave timeline empty. You might want to try via callback: on the child element's first frame call a parent.childready() (where childready is a function you dynamically declare), or something like that
ptor
+1  A: 

The first, and more useful, part of the answer is this: timeline keyframes and scripts can give conflicting information about display objects - whether they should exist, where they should be, and so on. For example, when you add an item by playing into its frame, and then delete it with script, and then play into its frame again. When this happens, there's no unambiguously correct thing for Flash to do, so it tends to be unpredictable. I believe what generally happens is that once you fiddle with a given object via script, it's considered to no longer pay attention to the timeline - but your mileage will vary.

Having said that, the reason things are different when you play backwards is the second and more arcane part of the answer. Internally Flash functions differently when seeking forward and backwards on the timeline. Flash internally treats keyframes as changes to be applied in the forward direction, so as you play forward, it applies those changes in sequence. When you move backwards, however, from frame N+X to frame N, it doesn't scan through the intervening X frames reversing those changes - it jumps back to frame 1 and fast-forwards along to frame N. Normally, it amounts to the same thing and you don't need to worry about it, but when you get into the twitchy area where scripts and the timeline have a different idea of what should be on the stage, you're liable to see things behave differently depending on which way you jump (as you are now).

The super-short version is, for things to work predictably, try to ensure that any given object gets added, updated, and removed the same way - either all via script, or all via the timeline. When that seems impossible, fiddle with your content structure - usually, the best solution is to change your object into two nested ones, so that the things you want to do with script occur one level higher or lower than the things you want to do with the timeline.

fenomas
A: 

Hi, I remember using this chunk of code in the past to work around this problem. It uses the Stage.Invalidate() function to wait for an Event.RENDER before trying to access and children, more info (although vague as hell) is here

private function init():void
{
 stage.addEventListener(Event.RENDER, stage_renderHandler);
}

private function stage_renderHandler(evt:Event):void
{
 // Run your code here
 updateChildren();
}


private function enterFrameHandler(evt:Event):void
{
 // triggers the RENDER event
 stage.invalidate();
}

This also might me very costly (performance wise). I would strongly advise against dynamically adding/removing objects to an existing timeline, is there any way in which you can place an empty Sprite above the timeline animation and use that for all your dynamic content?

Hope this helps