A Flash Developer Resource Site

Results 1 to 12 of 12

Thread: [RESOLVED] Cleaning up object vars...

  1. #1
    Junior Member
    Join Date
    Aug 2007
    Posts
    23

    resolved [RESOLVED] Cleaning up object vars...

    I've just done this tutorial:

    http://jasonmerchant.com/tutorial.php?t=5

    Basically, the code in the timeline is this:

    Code:
    var enemy1:enemy = new enemy();
    stage.addChild(enemy1);
    Which adds a new enemy. In the enemy.AS class, we have this:

    Code:
    public function die():void {
             stage.removeChild(this);
          }
    When it's called, it removes the movieclip from the stage. Simple, right?

    But my question is, what happens to our var, enemy1? Presumably this var is our entire copy of the object program, including the enemy's health and all its methods. Is there any way to destroy it? If we don't destroy it manually, will it reside in memory forever? Or will Garbage collection somehow take care of it? If so, when?

    I want to spawn hundreds of enemies, perhaps 10 or so at a time, so it's vitally important that nothing "pile up" in memory as the game progresses, not even Numbers.

    Thanks in advance for any helpful replies.

  2. #2
    Junior Member
    Join Date
    Aug 2007
    Posts
    23
    Whoops, never mind, I found this.

    First, you must remove it from the display list:
    Code:
    removeChild(myobject);
    You must also remove anything attached to the object, dynamic properties, event listeners:
    Code:
    object.removeEventListener(MouseEvent.CLICK, object.ClickHandler);
    The delete operator will delete an object property. You can only delete properties that are dynamically created.
    Code:
    delete myobject.myproperty;
    Finally you need to set the variable to null:
    Code:
    myobject = null;
    The rest is left to the Garbage Collector to clean up. All you can do is hope that the GC does it's job and you didn't miss anything.
    Sounds scary. Is there any sort of automated way to delete all properties and remove all listeners in an object? Something akin to AS 2.0's for/in loops with a type check to decide what to do next? I know the tutorial says "just be careful," but if there's a way to craft a ubiquitous cleanUp method, I'm sure we'd all bennefit from discovering it!

    Leaving this unresolved for now, because I really want to see if there's a better way...
    Last edited by WarpZone; 08-22-2007 at 07:52 AM.

  3. #3
    Junior Member
    Join Date
    Aug 2007
    Posts
    23
    Following the instructions above, is this correct? (The die() fucntion is in bold.)

    Code:
    package {
       import flash.display.MovieClip;
       import flash.events.MouseEvent;
       public class enemy extends MovieClip {
          public var health:int = 100;
          public function enemy() {
             addEventListener(MouseEvent.CLICK, mouseClick);
          }
          public function mouseClick(event:MouseEvent):void {
             trace(damage(10));
          }
          public function damage(amount:int):int {
             health -= amount;
             if(health <= 0) {
                health = 0;
                die();
             } else if(health > 100) {
                health = 100;
             }
             return health;
          }
          public function die():void {
            stage.removeChild(this);
    	this.removeEventListener(MouseEvent.CLICK, mouseClick);
    	delete this.health;
    	this = null;
          }
       }
    }
    Did I do it right?
    Last edited by WarpZone; 08-22-2007 at 08:07 AM.

  4. #4
    Junior Member
    Join Date
    Aug 2007
    Posts
    23
    Oh... wait a minute... I just read this.

    Does that mean I can just call "delete this;" in my die method, and it will erradicate the entire instance of the object, including any listeners and other objects therein?

    Or do I need to do both?

    I'm digging myself a lot of holes in this thread, someone who knows what they're doing needs to help me out. :P

  5. #5
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    As I understand it, the delete keyword is only used for dynamic properties. You don't have any of those in your code, so you shouldn't need to worry about it, including the "delete this.health" line.

    Unfortunately, I don't think you can do "this = null". You'll have to set the variable pointing to the enemy object to null.

    in enemy class:
    Code:
          public function die():void {
            stage.removeChild(this); //only if it was on the stage in the first place
    	this.removeEventListener(MouseEvent.CLICK, mouseClick);
          }
    In another class
    Code:
      //...enemy is existing enemy object
      enemy.die();
      enemy = null;
    I tried to think of a way to encapsulate the setting to null within a general purpose kill function, but everything I could think of would only set the local reference to null rather than the original which we were trying to remove.

    There is one thing you might want to look into, which is using weak references in your event listeners for short-lived objects. A weak reference doesn't count for garbage collection, and so will not prevent your object from being automatically cleaned up (you still must remove the object from the stage and set any referencing vars to null).
    Code:
          public function enemy() {
             addEventListener(MouseEvent.CLICK, mouseClick, false, 0, true);
          }

  6. #6
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    5Tons is right that you need to weak reference the MouseEvent listener. After that, assuming the code is not being called anymore / there are no loops still running in it or ongoing EnterFrame listeners, etc., and you remove it from the display chain, it will be picked up for garbage collection. You do not need to explicitly remove the event listener if it's weak-referenced to begin with and you remove it from the stage.
    Having said that, if you want to really force it to delete right then and there, you can create it dynamically in the class you're calling it FROM -- e.g.
    this.enemy1 = new enemy();
    then in that class you can say delete this.enemy -- and then it will be null right away, again if there are no other references to it anywhere else.
    Hope that helps.

  7. #7
    Junior Member
    Join Date
    Aug 2007
    Posts
    23
    Ahhhh... okay. So I would do delete this.enemy from either the main timeline or the document class, depending on where my main loop is?

    That's fine if I have 5 explicitly named enemies named enemy1, enemy2, etc. But what if I want to spawn an arbitrary number of enemies in my main loop? In AS 2.0, I would just attach them to the stage, and each enemy would have a collision and death routine within it (much like the click > health > death routines you see in the enemy object, above.)

    Under AS 2.0, the only time I needed to step through my enemy objects would be to test for collisions with the player's bullets. (And that I would accomplish with a for/in loop... I had all my bullets in one movieclip and all my enemies in another one, specifically for this purpose.) AS 3.0 turns this entire system on its head.

    We're quickly digressing into another subject here, thought, so I'm going to mark this resolved. I'm gonna tinker some more and read some more. Hopefully I can find an OOP tutorial on keeping track of the game objects from a main class, and testing collisions for game objects from that parent class against an arbitrary number of spawned enemy objects. I'm sure it's possible to do this, because I've seen it done before in games that obviously used the shape class. I just want to learn how to do it right...

  8. #8
    Junior Member
    Join Date
    Aug 2007
    Posts
    23
    Quote Originally Posted by 5TonsOfFlax
    I tried to think of a way to encapsulate the setting to null within a general purpose kill function, but everything I could think of would only set the local reference to null rather than the original which we were trying to remove.

    There is one thing you might want to look into, which is using weak references in your event listeners for short-lived objects. A weak reference doesn't count for garbage collection, and so will not prevent your object from being automatically cleaned up (you still must remove the object from the stage and set any referencing vars to null).
    Code:
          public function enemy() {
             addEventListener(MouseEvent.CLICK, mouseClick, false, 0, true);
          }
    Sounds to me like the example I learned from was poorly engineered. In keeping with AS3's "Outside looking In" model, there should be no die() class, or at the very least, it should never be called from within the object itself, and object creation and destruction both need to be handled from the main loop, and not from within an object.

    Is there a way to send a death event from the object when its health gets too low, have the main loop catch it, and then have the main loop either call that function's die routine, or else manually remove it from the stage and delete the variable referencing it?

    I haven't worked much with events yet... all of this is still much too new to me.

    Heck, for that matter, I probably shouldn't have a mouse listener embedded within the object anyway, right? I should probably handle I/O in the main loop and only have methods that react to the IO in my enemy object. Otherwise my enemy class is only useful in games that use the mouse...
    Last edited by WarpZone; 08-22-2007 at 10:41 PM.

  9. #9
    Junior Member
    Join Date
    Aug 2007
    Posts
    23
    Wait, wait, WAIT. In the Flash help, it says

    The delete operator can fail and return false if the reference parameter cannot be deleted. You cannot delete fixed properties or variables that are declared with the var statement. A fixed property is a variable or method defined in a class definition.
    That means that when I do this:

    Code:
    var enemy1:enemy = new enemy();
    Am I correct in assuming that this means enemy1 can now never be deleted? As in garbage collection won't kill it, and I can't kill it manually? That sucks! I've basically created a variable that I'm stuck with in memory, causing a performance hit until the end of time. In what universe is that desirable behavior?

    They trained me to use var all the time in AS2 as a scripting language, and now they've gone and made the var statement the worst possible thing I could do to a variable. What gives?

    I hope I'm wrong about this. It seems very counter-intuitive.

  10. #10
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I think for the most part the delete operator is a red herring. It only applies to properties that were created dynamically, which is something you should not do in the first place if you're looking for performance (it incurs a large penalty for having to look up the prototype chain). Dynamic in this sense is as in the "dynamic" keyword which allows you to add undeclared properties on the fly like so:
    Code:
    var o:Object = new Object();
    o.something = "dumb";
    
    delete o.something; //should work because "something" is dynamically added to o.
    delete o; //should NOT work, because o was declared with var.
    
    o = null;  
    /*
    the original object is now sitting in memory with nothing pointing to it.  
    GC will kill it.
    */
    In the example where you replace enemy1 with a new enemy object, the original object it pointed to is now reference by nothing, and will be garbage collected eventually.

  11. #11
    Junior Member
    Join Date
    Aug 2007
    Posts
    23
    Interesting.

    I've played some Flash games such as Bloons Tower Defense, which hundreds of objects spawn and die rapidly. The game seems to gradually slow down and then suddenly speed up again.

    Is this the sort of performance we can expect from Flash's Garbage Collection? If so, GC is a band-aid on a much more severe problem. IMHO it would make more sense to have a command like delete that simply destoys the named instance of that object, any time, anywhere, no questions asked. That way, when the enemy goes boom in-game, everything that was going on behind the scenes to maintain it gets wiped.

    Of course, I don't even know if the Bloons game was written in AS2 or AS3. It's entirely possible the perfromance issues I'm seeing are caused by something else. But the slow-fast-slow pattern sure sounds familiar, given what little I know about GC.

  12. #12
    hippie hater Cimmerian's Avatar
    Join Date
    Oct 2006
    Location
    over there
    Posts
    599
    seems like they want you to use events for everything instead of passing references,that makes easy to null it
    However even after that the GC will not remove it rigth now, you can never know when...that really really sux

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  




Click Here to Expand Forum to Full Width

HTML5 Development Center