Say you have a Flash document with a MovieClip symbol in the library and assign it the base class ThingOne, and ThingOne.as looks like this:
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class ThingOne extends MovieClip{
private var thingTwo:ThingTwo;
public function ThingOne(){
graphics.beginFill(0xff0000);
graphics.drawRect(0,0,100,100);
graphics.endFill();
addEventListener(MouseEvent.CLICK, onMouseClick, false, 0, true);
addEventListener(Event.ADDED_TO_STAGE, onAddedToStage, false, 0, true);
addEventListener(Event.REMOVED_FROM_STAGE, onRemovedFromStage, false, 0, true);
}
private function onMouseClick(e:MouseEvent):void{
(parent as MovieClip).gotoAndStop(1);
}
private function onAddedToStage(e:Event):void{
thingTwo = new ThingTwo();
parent.addChild(thingTwo);
}
private function onRemovedFromStage(e:Event):void{
if (parent.contains(thingTwo)) parent.removeChild(thingTwo);
}
}
}
Frame 1 of the timeline is empty, and you put a ThingOne symbol in frame 2, let it span three frames, so frames 5 and on are empty.
When you run it, why would you get a 2025 error (“The supplied DisplayObject must be a child of the caller.”) when you click the ThingOne, but if you change the gotoAndStop to an empty frame after the MovieClip (say 5), no problem, both objects are removed?
If I trace out the whether parent.contains(thingTwo), it does! And yet…
The generic answer is that you really shouldn’t ever have more than one frame on the main timeline.
Otherwise its adding and removing children and new instances for you.
So inevitably at some point you try to access a child that is not there at the time of the call.
Whoa, I saw this answer appear in real time. Yeah, I agree that frames could be the issue. I think it’s called… puppeting? Wherein messing with timeline objects forces them to stay around forever until AS dismisses them.
Well, it sounds like you might have duplicates of ThingTwo, or something similar to that. As @tbo mentioned, frames can be fairly tricky in the way they automatically instantiate objects, because they kind of assume that you aren’t messing with those objects in code. If you do mess with them, then they give up and stop managing those objects altogether, so interesting situations can arise.
Thank you both for responding. I could see if I were trying to access ThingOne (placed “manually” on the main timeline) and do something with it, but in this case I’m only trying to manage the ThingTwo that is added “dynamically”. Is it because I have a reference to the ThingTwo in ThingOne? What gets me is that in a single line of code Flash is saying, yep, it’s there and then psych! no it’s not. And the removal behavior is consistent for me: works if we go some frame after ThingOne, doesn’t if we go before.
Usually I wouldn’t be messing with a timeline at all. In this case I have timelines with animation synched to streaming voiceover and hundreds of these interactive objects that need to come and go in synch with the narration, with properties that the animator can set. If anyone has any ideas how that can happen, please let me know. At this point, I’m thinking my best bet might be to have an empty, named MC that spans the entire timeline, and add/remove the objects from that.
I just skimmed through the thread but I think krilnon is probably on target. Looking at the code, it looks like you’re not only combining timeline with dynamic instantiation, but you’re also interacting with parent timelines from within a child timeline which can make for some headaches.
A good rule of thumb is to not branch out - not letting things further down a hierarchy directly interact with things higher up the hierarchy. This improves encapsulation and portability. This is also why events bubble up instead of down. Directly interact down all you want, but if you need to inform a parent (or something up), send an event that code higher up can respond to.
Your code seems to be trying to match thing 2’s lifetime to thing 1. If that’s the case, then I would suggest making a thing clip that contains both 1 and 2 and just remove that instead of thing 1. Alternatively keep the management code in whatever parent is and use that to handle both 1 and 2 at the same time.
As far as animations go, it can also help (if you’re working with dynamically adding things to the stage too) to keep those encapsulated in individual movie clips which can exist in a single frame and still play. This isn’t always easy, depending on your situation, but it can make management between code and animations easier. In fact, it may be in your case that you’re trying to add dynamic content to the animation itself. In that case, this suggestion wouldn’t help much.
I can’t remember if I go into puppeting much in that tutorial, but there are definitely some weird things with object handling in the timeline during navigation, especially going backwards - and a complicated order of operations when handling that process. In this, sometimes you can’t depend on introspection operations (like contains()) because you’re in the middle of something thats mutating the collection that you’re looking into. Its like looping through an array and calling shift which removes the first element, shifting all other elements and screwing up your loop. Not quite the same thing, but the same idea.
The tutorial is pretty heavy, so don’t feel compelled to read it all if you don’t want to. Normally, no one has to know about how all that works. And, as the tutorial indicates, its been a bit of a moving target (which you can largely thank me and Thibault Imbert for, in our attempts to fix a lot of the problems around these things)
Thank you, senocular. I tried adding the secondary object (ThingTwo in my stripped-down example) as a child to the first, and ran into what I must have run into initially: the second object needs to be tab-able (the whole project has to be accessible that way), and it wasn’t when it’s a child of the MovieClip. And yes, I’m trying to mix these interactive elements with animation and streaming narration audio. It’s a mess.
That’s the feeling I was getting, that there was something like that going on, something to do with the order of operations, like maybe the removal of a child doesn’t actually happen until a frame later, or whatever (I haven’t read your tutorial yet, but I will when I have more time – thank you).
Again, thank you for giving my issue your time and attention.
I just have to say that this had a happy ending, and at the risk of making anyone feel like he wasted his time (which is not the case because I learned something), the tabbing of “ThingTwo” as a child of “ThingOne” was working; it’s just that I was unaware of an x/y offset that was pushing the focusRect off stage where I couldn’t see its little yellow rectangly self.
Creating engaging and entertaining content for designers and developers since 1998.