Game Development Community

Extending callbacks

by Ty Schacht · in Torque Game Builder · 06/24/2005 (5:20 am) · 3 replies

A tscript code trick i recently discovered may be useful to some here. Maybe most of you will be saying 'no s**t sherlock', but i wanted to share something that wasn't obvious to me at first as a tscript newbie.

One thing that was 'difficult' to work with for me was the single callback function for multiple objects. For example, i could have 30 sceneobjects that would all use the same fxSceneObject2D::onCollision callback block. Handling all of this collision logic in that single block quickly led to spaghetti code. I recently saw a post by member 'Luke D' that gave me insight on handling this situation much more elegantly. It takes nice advantage of the tscript's 'call' method, which effectivly calls the function which is passed to it as a string.

In the following example, i define my player and enemy sprite objects, and i define the custom callback function each will use. I then add a short block of code in the fxSceneObject2D::onCollision method which subsequently calls my custom callback function for the appropriate objects:

function createPlayer() {
                $player = new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
                // other init code deleted for brevity


                // define special callback method
                $player.collisionCB = "handlePlayerCollision";   
}

function createBugEnemy() {
                $benemy= new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
                // other init code deleted for brevity
                 
                // define special callback method
                $benemy.collisionCB = "handleBugEnemyCollision"; 
}


function fxSceneObject2D::onCollision( %srcObj, %dstObj.......... ){ 



       // if either collision object has a 
       //collision callback special method defined,
       // call the defined function:



        if (!(%srcObj.collisionCB $= "") ) {   
                call(%srcObj.collisionCB, %dstObj);        
        }
        
        if (!(%dstObj.collisionCB $= "")) { 
                call(%dstObj.collisionCB, %srcObj);
        }       
}

function handleBugEnemyCollision(%collisionObject) {  
        
       //my custom collision code for this specific object can go here
        
       %collisionObject.safeDelete();  
}

function handlePlayerCollision(%collisionObject) {  
       
       //my custom collision code for this specific object can go here
        
       %collisionObject.safeDelete();  
}

Here you see how i was able to shrink the logic in the actual fxSceneObject2D::onCollision block. I was then able to move object specific logic into each appropriate collision handling method. For me, this makes code much more readable and manageable.

One thing to note is that in the 'call' method, you can pass each required target function argument as an additional argument within the 'call' parameters. In my example, i only needed to pass the other collision object. However, if more of the original fxSceneObject2D::onCollision arguments were required by your child function logic, you could easily extend these.

This approach can also be used to seperate logic used in other callbacks.

As I stated before, i am a tscript newbie, so i may be missing a better way to accomplish what was done above. If that is the case, i'd be grateful to know the cleaner methodology.

#1
06/24/2005 (6:40 am)
Would it not be easier to do:
function createPlayer()
{
                new sciptObject(Player)
                { 
                // other init code deleted for brevity
                };
}
  
function createBugEnemy()
{
                new sciptObject(BugEnemy)
                { 
                // other init code deleted for brevity
                };
}
  
function Player::onCollision( %srcObj, %dstObj.......... )
{        
  // Player related collision stuff here
}
  
function BugEnemy::onCollision( %srcObj, %dstObj.......... )
{        
  // Bug Enemy related collision stuff here
}
I haven't tested the above, as I really want to get into Script objects this weekend, but it *should* work. Your collisions are kept seperate, plus you get the benefit of being able to do Player::PrettyMuchAnythingYouLike.
#2
06/24/2005 (10:11 am)
Thanks for the feedback! I did some searching in the context of your example and found the following post:

www.garagegames.com/mg/forums/result.thread.php?qt=26887

Your logic is close to working, but since ScriptObject's Player and BugEnemy don't extend fxSceneObject2D, their onCollision() methods don't override fxSceneObject2D's static onCollision() callback.

Combining the above post's example with your example, i have gotten the following code to work:

function createBugEnemy() {
                $benemy= new fxStaticSprite2D() { scenegraph = t2dSceneGraph; };
                // other init code deleted for brevity
                 
                // define class type:
                $benemy.class = new ScriptObject(BugEnemy);
}

BugEnemy::onCollision( %srcObj, %dstObj........ ) {
	// BugEnemy specific logic here
}

function fxStaticSprite2D::onCollision( %srcObj, %dstObj......... ){   
     if (isObject(%srcObj.class))   {      
           %srcObj.class.onCollision( %srcObj, %dstObj........ );      
     }   else   {      
           // handle other collisions here   
     }
}

Basically, you need to code a dispatcher in the static fxStaticSprite2D::onCollision method which evaluates the class type referenced by your fxStaticSprite2D object, and then calls the onCollision method for that class. It is similar to the first example i posted, but instead of using the string function name to map the 2 onCollision methods, it uses the class type. I believe it is more readable to have the functions hierarchically (sp?) named in this standard c++ style.

There may be a better way to do this, and Phillip may discover a better way this weekend. Maybe someone else can chime in.
#3
06/24/2005 (1:43 pm)
Nevermind. I see you basically already do what I was going to suggest. :)