Is removeChild enough to completely remove a movieclip from Flash Player memory? - actionscript-3

Will this line
clip.removeChild(clip.getChildAt(0));
completely remove the child of clip at 0 index? I read somewhere you should set to null to all the references to that clip, but I have no other reference in my code. The clip at 0 was added via a regular addChild().

For the garbage collector to swipe your object you should:
-not have any other reference to the object throughout your code
-the object shouldn't be part of any collection (like Array or Vector)
-the current reference should be set to null
Be sure to pay extra attention to the second condition, the most common situation when the object is part of a collection you can't control directly is when it had a listener attached to it and when is part of the display list. On top of that, there are other situations when the object is part of a collection you can control, don't forget to remove it form there too.
Also, to force the garbage collector to swipe your object (only for testing, not production), you can use System.gc() and then check the memory with System.privateMemory

if you're removing them in a loop, do it like this:
while (clip.childNum > 0)
{
var child:MovieClip = clip.getChildAt(0);
clip.removeChild(child);
// remove all listeners
child.removeEventListener(...);
child = null;
}
if "child" is a custom class you may call a kill() method to clean everything up inside your class/instance.

Not sure, if you still have reference on the clip, garbage collector may distroy the object, try to remove an event listener and force the clip reference to null.

If you have no references, no listeners or any other handle to the clip then it will eventually be garbage collected. Due to the way the GC works it might not immediately be removed from memory. Your DisplayObject will however immediately be removed from the display list.
But if you do something like this in one of your classes:
private var mc:MovieClip = new MovieClip();
private function addClip() : void {
mc.addEventListener(Event.ENTER_FRAME, myListener);
myClass.addChild(mc);
}
Then you'll want to properly remove mc like this:
private function removeClip() : void {
mc.removeEventListener(Event.ENTER_FRAME, myListener);
myClass.removeChild(mc);
mc = null;
}

Related

Check the existence of an object instance

I'm surprised I don't know how to do this, but as it turns out I really don't; simply put, I'm trying to make a side-scrolling shooter game, a basic one and in it, I have 50 stars spawned on-screen through a "for" loop upon the game starting. There is a function which does this and a listener is at the beginning. Problem is, when you lose the game and go back to main menu, 50 more stars would be spawned, which isn't what I want. So, I'm trying to make an "if" statement check at the beginning, so that the game checks whether there is an instance/movie clip of the star object/symbol before determining whether the function that spawns stars should be called out with a listener. So, how do I do this? I looked through some other checks and they didn't help as the codes presented were vastly different there and so I'm just getting errors.
Let me know if a better explanation is needed or if you would like to see some of the code. Note that the game overall already has a lot of code, so just giving all of it would probably not be helpful.
I suggest you rethink your approach. You're focusing on whether stars have been instantiated. That's ok but not the most basic way to think about it.
I would do this instead
private function setup():void{
loadLevel(1);
addListeners();
loadMusic();
// etc...
// call all functions that are needed to just get the app up and running
}
private function loadLevel(lev:int):void{
addStars();
// call all functions that are needed each time a new level is loaded
}
private function restartLevel():void{
// logic for restarting level,
// but this *won't* include adding star
// because they are already added
}
There are other ways to do this but this makes more sense to me than your approach. I always break my game functions into smaller bits of logic so they can be reused more easily. Your main workhorse functions should (IMHO) primarily (if not exclusively) just call other functions. Then those functions do the work. By doing it this way, you can make a function like resetLevel by assembling all the smaller functions that apply, while excluding the part about adding stars.
Here's what I did to solve my problem... Here's what I had before:
function startGame():void
{
starsSpawn();
//other code here
}
This is what I changed it to:
starsSpawn();
function startGame():void
{
//other code here
}
when you said existance, so there is a container, i named this container, (which contain stars , and stars was added to it) as starsRoot, which absolutely is a DisplayObject (right?)
now, to checking whole childrens of a DisplayObject, we have to do this :
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
}
then, how to check if that child is really star!?
as you said
whether there is an instance/movie clip of the star
so your stars's type is MovieClip, and they don't have any identifier (name), so how to find them and make them clear from other existing movieclips. my suggestion :
define a Linkage name for stars from library, thats a Class name and should be started with a capital letter, for example Stars
now, back to the code, this time we can check if child is an instance of Stars
for (var i:int=0; i<starsRoot.numChildren; i++) {
var child = starsRoot.getChildAt[i];
if (child is Stars) {
// test passed, star exist
break;
}
}

Saving the state of a movieclip containing multiple movieclips inside

this is actually a noobish question, but is there a possible way to save a certain state of a movieclip?, example i dynamically added a movieclip called big_mc, then inside big_mc contains three(3) smaller movie called child_mc1 and child_mc2 and a close_big to remove big_mc from the stage, when i click either of child_mc1 and child_mc2, the child_mc will disappear prior to which child_mc i clicked.
so the scenario is when I click child_mc1 which remove itself from the scene, then next I'll click the close_big movieclip to remove big_mc from the stage and will save it's own state, so then the next time i run the SWF file and dynamically add big_mc to stage, child_mc1 would be still missing and child_mc2 would still be displayed (EVEN IF I CLOSE THE SWF FILE, the state should be saved). please help..much is appreciated.
code in main time line:
var big_mc:mother_mc = new mother_mc;
add_big_btn.addEventListener(MouseEvent.CLICK, call_big);
function call_big(e:MouseEvent):void
{
addChild(big_mc);
}
the code inside big_mc:
child_mc1.addEventListener(MouseEvent.CLICK, remove_child1);
child_mc2.addEventListener(MouseEvent.CLICK, remove_child2);
close_big.addEventListener(MouseEvent.CLICK, bye);
function remove_child1(e:MouseEvent):void
{
removeChild(child_mc1);
}
function remove_child2(e:MouseEvent):void
{
removeChild(child_mc2);
}
function bye(e:MouseEvent):void
{
this.parent.removeChild(this);
}
You want to start with SharedObject, which as Adobe puts it, "is used to read and store limited amounts of data on a user's computer or on a server". To save the "state" of the MovieClip is more complicated.
What about it do you want to save? The x property? Perhaps the alpha? EVERYTHING? Each object is stored in a default state in your swf. Library items in the Flash IDE are technically miniature classes, as evidenced by the way we instantiate them. Assuming you create something called customButton, you could spawn thousands of them onscreen (or one) like this:
var foo:customButton = new customButton();
Like a hand-written class, a copy of the customButton is created with all the properties you defined on it before you compiled it. If you want to change those properties, you have to address each and every one you want different.
Looking at this broadly, let's assuming you want to save the position of your button every time you load the swf. Load with getLocal(), and save with flush().
var settings:Object = SharedObject.getLocal("foo");
function updateState(e:Event):void {
myButton.x = settings.x;
myButton.y = settings.y;
}
function saveState():void {
settings.x = myButton.x;
settings.y = myButton.y;
settings.flush();
}
It's not impossible; there's simply no push-button solution for it. If you wanted, you could write a function which iterates over all DisplayObjects, and loads/saves each relavent property from/into your SharedObject. Might be overkill, though.

AS3 - Loading multiple videos into the same container - addChild removeChild

This is a function that loads a specific video into a MovieClip container at 0.0 using a video class.
public var mainVideo:SimpleVideo;
public function loadVideo(videoString:String) :void{
mainVideo = new
SimpleVideo("videos/"+videoString+".flv","",true,video_container.positionMc);
video_container.addEventListener(MouseEvent.MOUSE_DOWN,controlVideoPlayer);
addChild(mainVideo);
trace('adding new video to container');
}
I'd like to preferably check, each time a video is loaded, to see if there already is another video loaded. And if there is, then remove it, and add the new video.
I've tried using removeChild() in a variety of ways, but it doesn't seem to work correctly.
Would I use removeChild(mainVideo)? video_container.removeChild(mainVideo)?
And how would I be able to check if there was already an existing mainVideo?
Any help would be greatly appreciated!
-Update-
If I try and use removeChild(mainVideo) I get this error:
TypeError: Error #2007: Parameter child must be non-null. at
flash.display::DisplayObjectContainer/removeChild() at
Main/removeVideo() at MethodInfo-127()
If you add the video into a container movieclip rather than onto stage, and that container only has just one instance of SimpleVideo in its display list at a time, you could do:
if( myVideoContainer.numChildren > 0 )
{
myVideoContainer.removeChild( myVideoContainer.getChildAt( 0 ) );
}
A bigger issue though is how the SimpleVideo class you are using cleans itself up. Most video classes have a cleanup or kill function that removes the listeners and cleans up the netStream. I would think you'd need to call something like that as well as removing the video instance from the container.
I hope this respone may help you
--> Would I use removeChild(mainVideo) ? video_container.removeChild(mainVideo) ?
you should use removeChild function but you need to know who is the parent of mainVideo and call this function of his parent, in your case, I think, video_container is not the parent because is a variable near mainVideo and you add mainVideo to the instance of the class which has loadVideo function
sometimes you can use mainVideo.parent.removeChild(mainVideo), not the best approach but it works, it's better to know who is the parent and call function removeChild() explicitly on that "parent"
--> would I be able to check if there was already an existing mainVideo?
well, you can do a simple if(mainVideo != null) { .. } because in function loadVideo you create new instances each time, that means if you called at least one time this function then if condition should be true that means you have already an existing mainVideo
--> TypeError: Error #2007: Parameter child must be non-null.
that means your mainVideo is not instantiated, because I guess you have not called loadVideo() yet, that's why #putvande asked you to provide more code, we need to see where and when you call removeChild()

AS3 call a just added element

i'm adding a movieclip element ("lastSlide") to an other movieclip element("endLogoButton"). The added element has a child which is a button("endLogoButton"). How can i call that button?
mcSlideHolder.addChild(lastSlide);
/*mcSlideHolder.getChildByName("endLogoButton").buttonMode = true;;
mcSlideHolder.getChildByName("endLogoButton").mouseChildren = false;
mcSlideHolder.getChildByName("endLogoButton").useHandCursor = true;*/
lastSlide.endLogoButton.addEventListener(MouseEvent.CLICK, linkClick);
As a beginner i'm struggling around ... but can't make it work ...
It always tells me that the access to a Nullobject reference is not possible.
Thanks for any advice!
You can either 'dig in' to the nested objects to get to the button instance or you can add event listeners to the button instance before adding it to its parent container then let its click event bubble up.
I'm having a bit of trouble understanding what is nested inside of what in your case but I see you're trying getChildByName. getChildByName only gets a direct child (not a child of a child) by its instance name, (not it's variable name).
Dig in example:
lastSlide.getChildByName("endLogoButton").addEventListener(MouseEvent.CLICK, linkClick);
or
lastSlide.name = "myLastSlide";
mcSlideHolder.getChildByName("myLastSlide").getChildByName("endLogoButton").addEventListener(MouseEvent.CLICK, linkClick);
If lastSlide were placed on the stage visually in the Flash IDE, then you could set the instance name myLastSlide there in the properties panel rather than by setting the name property in as3.
or maybe: try casting the "lastSlide" to a MovieClip like:
MovieClip(mcSlideHolder.getChildByName("lastSlide")).getChildByName("endLogoButton").addEventListener(MouseEvent.CLICK, linkClick);
This worked for me several times when the "possible unreferenced object" error popped up when referencing a movieclip that was clearly added to the stage

combining getChildAt with addChild

i have the following code:
seatContainer.getChildAt(order.seats[i])
i want to add a child to this but it doesnt allow me, i can only add an eventListener to this.
Anyone know how i can add a child to this without using an eventListener?
If I remember correctly, getChildAt() from the container classes (e.g. VBox, HBox, etc.) returns a DisplayObject. This object type does not have methods such as "addChild" -- these methods are introduced further down the inheritance hierarchy.
You'll need to cast the referenced returned by the getChildAt() method to something other than DisplayObject; I believe the method you want is in DisplayObjectContainer:
var child:DisplayObject = seatContainer.getChildAt(order.seats[i]);
(child as DisplayObjectContainer).addChild(your_child_class_here);