Game Development Community

OnRemove() not called when object is killed

by Tim Doty · in Torque Game Builder · 04/12/2005 (10:04 pm) · 12 replies

OnRemove() is not getting called when an object is killed, e.g., because of setLifetime() expiring. My demonstration is code utilizing the OO resource. I apologize for that and will reduce this to regular T2D when I can.

link(testClass, "", fxStaticSprite2D);

// construction
function testClass::create(%objectName) {
  %this = new fxStaticSprite2D(%objectName) {
    superClassName = "";
    className = testClass;
    scenegraph = aa_SceneGraph;
    };
  testClass::protInit(%this);
  return %this;
  }

// protected initializer
function testClass::protInit(%this) {
  echo(%this SPC "initialized");
  %this.setLifetime(2);
  %this.setImageMap(numbersImageMap,0);
  %this.setPosition("0 0");
  %this.setSize("20 20");
  %this.setVisible(true);
  }

// destructor
function testClass::onRemove(%this) {
  echo("test object" SPC %this SPC "is being removed");
  Parent::onRemove(%this);
  }

testClass::create(testsprite2);

Yes, I refer to an image map I made, it really doesn't matter what it is. The
purpose of that was to simply initially show it disappearing. I put this code in a file, loaded a game and exec()'ed the file. Wait two seconds and do a dump() on the object (it will echo its reference id when instantiated): you will get a message that the object could not be found. It is gone, but without the echo() in onRemove() ever having been called.

Note that onRemove() is called if the object still exists when you close T2D.

#1
04/13/2005 (12:40 am)
The only objects in TGE/T2D that have a "onRemove" callback are "ScriptObject" and anything based on "GuiControl". T2D objects have "onSafeDelete()".

I am not familiar with the OO resource and can't really comment on how it works.

When T2D deletes an object, it calls ".deleteObject()" which is a platform-level call and destroys the object and all its resources. T2D doesn't do anything special here.

I'm not sure what else to suggest without going through the OO resource.

- Melv.
#2
04/13/2005 (6:08 am)
I've been talking with Bryan Edds about this due to the OO resource connection in how I found it and I will try to provide a proper minimal case without referring to it.

My understanding is that T2D will call an object's onRemove() call back if it is defined when the object is removed and this is certainly the case with this fxStaticSprite2D object except when it is removed based on its life time. edit: checking this morning it looks like onRemove() is only being called for ScriptObject objects. Still working on the minimal code.

As a matter of testing I will also define onSafeDelete() the same way and see what that does. edit: it did nothing

Tim Doty
#3
04/13/2005 (6:59 am)
Okay, if I understand this correctly ScriptObject() has onRemove(), all T2D objects have onSafeDelete() ? I did the following using a base T2D (this used the same client directory as where I worked on the tutorial).

Quote:
==>$t = new ScriptObject(test);
==>echo($t);
1838
==>function ScriptObject::onRemove(%this) { echo("onRemove called on ScriptObject " @ %this); }
==>quit();

In the console log:
Quote:
...
==>quit();
Exporting client prefs
Exporting client config
Exporting client prefs
Exporting client config
Exporting client prefs
Exporting client config
Exporting client prefs
Exporting server prefs
onRemove called on ScriptObject 1838
onRemove called on ScriptObject 1392
onRemove called on ScriptObject 1391
onRemove called on ScriptObject 1390
onRemove called on ScriptObject 1389
onRemove called on ScriptObject 1388
onRemove called on ScriptObject 1387
onRemove called on ScriptObject 1386
onRemove called on ScriptObject 1385
onRemove called on ScriptObject 1384
onRemove called on ScriptObject 1383
onRemove called on ScriptObject 1382
onRemove called on ScriptObject 1381
onRemove called on ScriptObject 1380
onRemove called on ScriptObject 1379
onRemove called on ScriptObject 1378
onRemove called on ScriptObject 1377
onRemove called on ScriptObject 1376
onRemove called on ScriptObject 1375
onRemove called on ScriptObject 1374
onRemove called on ScriptObject 1373

So over riding the onRemove() function worked for the ScriptObject. Repeating the same for an fxStaticSprite2D object:

Quote:
==>$t = new fxStaticSprite2D(test) { scenegraph = t2dscenegraph; };
==>echo($t);
1838
==>function fxStaticSprite2D::onRemove(%this) { echo("onRemove called on ScriptObject " @ %this); }
==>function fxStaticSprite2D::onSafeDelete(%this) { echo("onSafeDelete called on ScriptObject " @ %this); }
==>quit();

there are no echo entries in the log for having quit. If I understand you correctly the lack of onRemove() calls is expected, but there should have been onSafeDelete(), right? Just to make sure I repeated the above but used a graphic and made it visible with a lifetime:

Quote:
==>$t = new fxStaticSprite2D(test) { scenegraph = t2dscenegraph; };
==>$t.setPosition("0 0");
==>$t.setSize("14 7");
==>$t.setImageMap(playershipImageMap);
==>$t.setVisible(true);
==>$t.setLifetime(5);
==>echo($t);
1838
==>function fxStaticSprite2D::onRemove(%this) { echo("onRemove called on ScriptObject " @ %this); }
==>function fxStaticSprite2D::onSafeDelete(%this) { echo("onSafeDelete called on ScriptObject " @ %this); }

I waited until the graphic died and then issued quit(). onRemove() and onSafeDelete() were never called.

If this is expected behavior I would request some callback function for when sprites are removed.
#4
04/13/2005 (7:05 am)
Hi Tim,

OnSafeDelete() is actually a function of the scenegraph, not the object. This works for me:

function fxSceneGraph2D::onSafeDelete( %this, %obj )
{
    echo(%obj SPC "will be safely deleted");    
}

The %this parameter is actually the scenegraph that %obj is being deleted from.

Hope that helps :)
Chris
#5
04/13/2005 (7:09 am)
Tim,

As I said, the only objects in TGE/T2D that have a "onRemove" SCRIPT callback are "ScriptObject" and anything based on "GuiControl". Not every object in TGE/T2D calls the script back with "onRemove". Every object has a "onRemove" C++ function which has no relation to this here.

"onSafeDelete()" is only called if you call "%obj.onSafeDelete()" on it. If you just delete the object using the standard TGE call ".deleteObject()" then it won't call "onSafeDelete()" because you didn't safe-delete it.

Ignore "onSafeDelete()" as this is confusing your issue. Essentially, "onAdd" and "onRemove" script-callbacks are not available for all objects in TGE although a "onAdd" or "onRemove" could be added to T2D objects.

Hopefully this will clarify the situation.

- Melv.
#6
04/13/2005 (7:20 am)
Sorry, I wasn't paying close enough attention I guess and I missed the part where you identified it as not being a script call back. This then represents a misunderstanding on my part.

Sorry to waste your time. :(
#7
04/13/2005 (9:58 am)
@Tim: Dude, you're not wasting my time. If I've helped then that's good! :)

- Melv.
#8
04/14/2005 (1:35 pm)
@Melv: When you wrote:

Quote:"onSafeDelete()" is only called if you call "%obj.onSafeDelete()" on it.

Did you mean:
Quote:...if you call "%obj.safeDelete()" on it.

Or did you mean we must call onSafeDelete() explicitly before calling safeDelete() on a T2D object?

Thanks.
#9
04/14/2005 (4:07 pm)
@Jason: My understanding is as follows. Calling .safeDelete() will, among other things, invoke an objects onSafeDelete() method. As an example, in my game there are missiles with a limited life span (fxStaticSprite2D objects with .setLifetime() called) that I would like to blow up when their time expires (currently they just disappear).

If I made a missile subclass of fxStaticSprite2D in C++ I could include an onSafeDelete() method for that class which would then be called whenever .safeDelete() was called on an object instantiated from it. In this onSafeDelete() method I could then spawn an explosion.

This is much the same as onCollision() -- the "on" functions are ones that you do not call directly, they are triggered by the named event.

Now, in T2D's TorqueScript you cannot create a subclass of fxStaticSprite2D or, in fact, any object other than ScriptObject. Thus you cannot do this outside of programming in C.

The OO Resource by Bryan Edd adds the ability to subclass all objects, but it does not (at this time anyway) modify the engine to call functions that do not otherwise exist for script objects. So you can create an onCollision() method for a TorqueScript class, but not onSafeDelete(). (Well, you can create it without errors, but it will never be called.)

There is also an onRemove() method for ScriptObjects, but this is not exposed to TorqueScript for others, such as fxStaticSprite2D. This bug report stemmed from my (mis)understanding that onRemove() was valid for all objects.

Because of the "use TorqueScript" mantra I'd expect it to be there instead of C++ only, but I'm sure Melv and Josh have their reasons.
#10
04/15/2005 (5:38 am)
* Warning - the below only applies to the OOInT2DScript resource.

There's a how it should be and how it is because I have not updated the resource -

HOW IT SHOULD BE -

It is important to remember that all T2D objects derive from SimObject AND that I moved ALL ScriptObject functionality into SimObject. Therefore, in theory, all T2D objects should call onRemove in script when deleted because all T2D objects inherit all of ScriptObject's functionality.

I have tested creating and deleting fxStaticSprite2D, and it DOES call onRemove when safeDelete is called.

HOW IT IS -

Unfortunately, I have been doing some final FINAL testing on the resource, and haven't updated the resource to reflect the final state of the code... As of right now, the available resource does NOT contain the proper call to onRemove. I only learned how out of date the resource is after Tim had a problem. I assumed it was in there, and I just now looked at the resource and found that I assumed wrong... This unfortunately cost Tim to lose a lot of time... and I fell like a total dweeb....

So, my apologies - the resource needs updating, after which all will work fine, I promise. I will update very soon since I am very certain it will not need updating again.

Tim, if you want a quick fix, shoot me an e-mail.

-new subject-

Now, whether it is preferable to define onSafeDelete to handle destruction for T2D object over onRemove, I do not know. I use onRemove for everything, and it works perfect for me with the final version of the resource.

Apologies again for making a stupid assumption and wasting people's time.... Maintaining resources is a pain, but you have to do it or else it's better not to post the resource at all.
#11
04/15/2005 (1:13 pm)
Actually, with next immenent T2D release, it will be the perfect time to redo the resource with all the new features and fixes. Stay detuned :)
#12
04/15/2005 (3:08 pm)
@Bryan: I appreciate your resource and the time you put into it. Thanks for clarifying exactly how it interrelates. Since I'm still deep in dev the onRemove() call missing is a rather minor thing -- I'm currently focused on the complete implementation of the core classes.