AS3 - What happens when an object that is executing code is removed? - actionscript-3

What happens when an object which has a function currently being executed has all its references removed?
I want to have a dialog box type object held in an array by the main class for my program, and when the dialog needs to be closed, I want it to be removed from the array during that close-screen function. My question is, assuming the dialog box object is in all other ways eligible for garbage collection, what happens to the code it's supposed to be executing?
Edit for clarification:
The array is a layer of visual elements in my program, of which the dialog box is one. The idea is that the "OK" button (or whatever) that closes the box will also remove it from the array of objects being displayed at the same time.

Your object won't be eligible for garbage collection if there is something referencing it (in your case to call a method within it).
If you want to make your Dialogue Box eligible for garbage collection from within itself, you'll need to add a method that deals with self-removal from arrays that it may be within, etc.
Yours may look like this.
public function destroy():void
{
var ix:int = someArray.indexOf(this);
someArray.splice(ix, 1);
if(parent)
parent.removeChild(this);
// ...remove event listeners, etc
}

If all references to the object have been removed while a function of this object is being executed, the rest of the function will keep executing. When it's done, the object will be removed during the next garbage collection cycle.

Related

as3 how can i prevent that a new instance is created by entering a frame?

i am working with several nested movieclip objects in a project. but i get into trouble with the buttons i created and implemented in the nested movieclips:
to describe it in a simple way:
I have a main movieclip with five frames, including two buttons with listeners to browse between the frames. Then inside of one Frame I have another movieclip with its own buttons. i instanciated it by hand not through code and gave it a specific name like "nestedMc".
Now I dont want to build the Listeners for those buttons inside the class of the nested movieclip class but in its parent class, which works fine until i then goto another frame in the main movieclips timeline and come back.
obviously every time flash enters a frame its contents get created anew (and therefore get new instance names). I could now try solve this through filling the frames via code.
But maybe there is another way to make sure the frame contains the same instance everytime i enter?
Timeline scripting is a dirty business, and really, a carry-over compatibility layer for Actionscript 2 projects. Whenever possible, I highly recommend not doing it, and simply keeping all of your code in your document class. As you're experiencing, timeline code causes headaches.
Consider instead just creating both states of your Stage (it sounds like that's what your two buttons are jumping between) and simply hiding them offstage or setting their alpha to zero and their mouseEnabled state to false. Furthermore, if the purpose of your frames is to play animation (a tween), consider instead switching to a much more powerful suite such as TweenLite. Moving an object over a hundred pixels (smoothly) can be as easy as:
TweenLite.to(redBall, 3, {x:100});
Now, if you're manually adding these items to the stage, as long as the object is a dynamic one, you can assign an instance name to it which will be saved between frame loads. Be aware the object name is not the same as the instanced name. For example:
var redBall:Ball = new Ball();
redBall.name = "bubbles";
The object's name is Ball, but it's represented as a variable called redBall. Its actual DisplayList name will likely be ambiguous (such as "Instance71"), and I can manually define it as "bubbles". 3 different names for the same object, all very different and necessary.
Even if you give the object a displayList name, you may not be able to reference it through code unless you enable Automatically declare stage instances, which basically creates on each object a pointer to the displayList object.
That said, you can always fetch the object by other means. Obviously, your buttons are always appearing, but you're trying to find a very specific object on the stage. At this point, we can use getChildByName() or getChildAt().
Hope that helps.
-Cheers

Removing movieclip in timeline - really gone?

I want a explosion to play when a object hits another object. I do this so that when hitTestObject is true, I run this function
function createExplosion():void {
var explosion:Explosion = new Explosion(enemy.x, enemy.y);
this.parent.addChild(explosion);
}
Explosion class only consists of setting the input to it's x and y values. Then in explosion movieclip I have a few frames of a animation. It ends in a keyframe (i.e., as an action in that frame) with the following code:
stop();
this.parent.removeChild(this);
My question is. Is it really gone now? I had to add stop() to not get error 1009. That makes me suspect some event timer is still running around?
Removing a display object from the display list, doesn't stop the animation or remove it from memory. It just removes it from the display list. Yes, you need to stop the animation and remove any event listeners that might be active for that object.
A display object is never truly gone until it is garbage collected. But that will not happen until no references to that object remain. So if you have a variable called explosion that references your display object, you need to set it to null after removing it from the display list :
explosion.stop(); // stop the animation
removeChild(explosion); // remove from display list
explosion = null; // remove variable reference
// explosion now qualifies for garbage collection.
Keep in mind that this doesn't immediately remove the object from memory, it just makes it fair game for the garbage collector. You can google "AS3 Garbage Collection" to get more information on that process.

AS3 case statement value access of undefined property

I have a class that I made to control all my buttons from a centralized location. The buttons are pushed into an array on load and a for loop adds a MouseEvent.CLICK event listener to all the buttons in the array.
Now my problem comes in with the function tied to this event listener. I have created a switch statement
function btnclick(e:MouseEvent):void
{
switch (e.currentTarget)
{
case Profile_btn_63 :
removearrayreference(this);
e.currentTarget.parent.gotoAndStop("profile");
break;
}
}
but the problem is when I test the game it states Profile_btn_63 is undefined. Which is actually true at the very beginning(first frame) as the button hasn't been added to the button array yet nor has an event listener been placed on it. So to get to the point I need help with making flash ignore that Profile_btn_63 is undefined until it eventually does get defined.
Finally this may be somewhat off topic but does anyone know why _63 is added to the end of Profile_btn when it is pushed into my button array?
If you're going to have a "magic switch statement" that does everything in your program - which is a horrible idea in more than one way, but that is a different matter - then you should make the case decisions based on the instance name: switch( e.currentTarget.name )
While a button instance may be null or undefined, a constant String never is.

ActionScript 3 Removing All RESIZE Event Listeners

I'm working on a Flash project which is separated into separate scenes.
In Scene 1 I have multiple MovieClips (which include event listeners for RESIZE (and others) inside them).
In Scene 2 I have a few common MovieClips and new ones (which also include event listeners for RESIZE (and others) inside them).
After clicking a button from Scene 1 to go to Scene 2, it's fine, except for if I resize the stage and then I get the following error:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
I know it's related to the event listeners, but it would be unrealistic to remove them each individually as it's expected there will be many.
If I undertand your situation correctly, I think you will in the end need to remove each listener individually, or add the resize listener only once. Since you mentioned scenes, am I right to assume you are working on the timeline? I also am assuming the null object reference error comes from a scene that has been removed from the stage, making reference to a display object that is no more, a ref to the stage after the scene has been removed, or just calling a function (the resize handler) on an object that no longer exists.
Some way to deal with this are:
Add some checking in the listener handler functions
if (!this.stage) return
To avoid the errors, but will not help if the object the function is a method of has been removed.
To avoid needing remember to remove hundreds of listeners, create removeAllListeners and addCustomEventListener functions. Instead of the usual addEventListener, call you addCustomEventListener which in turn will call addEventListener. Have addCustomListener store the target, listener function and event string in a dictionary or array of objects. removeAllListeners can loop through the dictionary or array and remove all your listeners. It is a bit like setting up an event hub, but does not go quite that far.
Instead of adding the RESIZE event listener to each scene, add it only once. Then in the listener function call a function on whichever scene is the active scene or view.
This last one is the approach I have seen most often, and is the most bullet proof. It may be tricky to implement on the time line, I have always been a little hazy on timeline variable scope.
Yes, so far as I know there is no good automated way to do this, however it would be a good practice to create a registerAllListeners and a removeAllListeners methods that manually add and remove the appropriate listeners to your object.

MovieClip on Flash stage does not re-instantiate when leaving keyframe and returning

I've been debugging the following issue for quite awhile now and have hit a wall.
I've set up a project in Flash (CS4, btw) that has a set of keyframes that I move between to represent the various screens of a game. One of them has a MovieClip defined (with children inside it) representing an option menu, that appears on a couple of different keyframes.
The problem I'm having is that this MovieClip reference seems to be accessible when I first enter the keyframe (using "gotoAndStop"), and occassionally when I move to other frames and back. But in at least one case, when I exit the frame and come back, I get a null reference error (TypeError: Error #1009: Cannot access a property or method of a null object reference). when I try and access it (getChildByName("optionMenuTitle")). I've even tried having the system iterate from 0 to numChildren and print out the name of each object, but it returns NULL at position 7 despite returning numChildren as 9. Does anyone have any idea why this particular MovieClip reference is NULL only in this case??
Here is a basic (abbreviated) rundown of the process occurring:
//set up function to be fired on frame construction
addEventListener(Event.FRAME_CONSTRUCTED, fadeIn, false, 0, true);
public function fadeIn(event:Event):void {
_handler.handle(); //this function is called which runs the debug statement below
trace (mainDoc.numChildren); //displays 9
for (var i = 0; i < mainDoc.numChildren; i++) { trace(mainDoc.getChildAt(i).name); } //throws null when it gets to 7
optionMenuTitle = OptionMenu(mainDoc.getChildByName("optionMenuTitle")); //the original failed call that caused me to debug
}
edit: One other potentially useful bit of information. If I comment out the getChild commands above that error, the frame loads and I can see the MovieClip visually displayed on the stage (although it's not interactive and is constantly cycling through the frames of its child objects). Still can't access it programatically though.
another edit: The object in question is a subclass of MovieClip that I named "OptionMenu". I put a breakpoint in the OptionMenu constructor, and when the frame loads correctly, that breakpoint is hit. When I get the error above, the breakpoint in the constructor is never hit. The debugger doesn't seem to give me access to see what's going on inside Flash's mind when it's instantiating the frame, however, so I can't see the logic as to why the constructor is never called.
Well this one has been driving me crazy. I could not workout why it does not reference your optionMenuTitle when you go back to the frame called title a second time.
The only way I could work around it was to take the 3 buttons out of the OptionMenu MovieClip and put them on the stage with the grey background underneath, essentially doing away with OptionsMenu.
So I moved all initialization code from OptionMenu to your TitleHanlder and also added the destroy calls to your destroy method in TitleHandler for each of the 3 buttons.
I also changed the refs from root to mainDoc:
sound.initialize(LogicGameMain(mainDoc).soundOn);
music.initialize(LogicGameMain(mainDoc).musicOn);
This worked for me as you can still interact with the buttons the second time around. It definately seems like there is some bug with these buttons being nested.
I hope this is useful for you.