Game Development Community

Parent datablock

by Erik Madison · in Torque Game Engine · 03/07/2004 (10:55 am) · 19 replies

How do I find the parent of a known datablock? ie, I'm declaring a few mobs like
Datablock PlayerData(Zombie1 : Zombie). I have a statement
%data = %this.getDataBlock();
switch (%data.getName())
which of course is returning zombie1. I need it to return zombie, as they all act alike and the numbered version are just different models.

#1
03/13/2004 (7:27 am)
Could it not be

dataBlock = Zombie;

instead of

%data = %this.getDataBlock();

hope that works

Nick.
#2
03/13/2004 (8:43 am)
Are you looking for the classname?

I think it could be:

getDatablock.classname
#3
07/15/2009 (6:54 pm)
Erik, did you ever figure out how to access the parent of a datablock? I have the exact issue and question in your post here. Or is there better way to create different versions of the same NPC class that all share the same behavior?
#4
07/16/2009 (4:19 am)

The object specified after the colon in the datablock/singleton/new construct is merely a copy source, i.e. it only provides a set of default values for the object being created. There is no permanent relation emerging from this.

To inherit behavior along a datablock hierarchy, simply define methods and use the class/superClass relations to control inheritance.
#5
07/16/2009 (5:32 am)
Oh, I see. So there is no real datablock inheritance.

So, how does one, for example, create an NPC with different shape files but that all share the same callback functions from the AIPlayer class? I'm specifically referring to the code in aiPlayer.cs where you have a DemoPlayer datablock and its member methods receiving the callback from AIPlayer. But if create two "child" datablocks named DemoPlayerNPCTYPE1 and DemoPlayerNPCTYPE2 with different shape files and perhaps a few other modified paramenters, how can both player objects share the same callback functions from AIPlayer?
#6
07/16/2009 (9:09 am)
Quote:
But if create two "child" datablocks ... how can both player objects share the same callback functions from AIPlayer?
The answer is right there already.
Quote:
To inherit behavior along a datablock hierarchy, simply define methods and use the class/superClass relations to control inheritance.
This "className" would be the namespace for your methods.

Take a look at the player/armor distinction, or even the dynamically created script classes such as weapon, weaponImage, etc, etc.
#7
07/16/2009 (9:12 am)
Like this, for example:

datablock PlayerData( DemoPlayerNPCTYPE1 : DemoPlayer )
{
   className = "DemoPlayer";
};

datablock PlayerData( DemoPlayerNPCTYPE2 : DemoPlayer )
{
   className = "DemoPlayer";
};

This way, you can even override methods for only particular datablocks:

// This function will be called only for NPCTYPE2 but not for NPCTYPE1
function DemoPlayerNPCTYPE2::onReachDestination( %this, %obj )
{
   //...

   // Call overridden function.
   Parent::onReachDestination( %this, %obj );
}

//Edit: wrong tags
#8
07/16/2009 (9:13 am)

Ha, Michael, we're the force :)

Parallel post.
#9
07/16/2009 (9:26 am)
I was just too lazy to post an example ;D
#10
07/16/2009 (9:41 am)
So, uh what is "super class name " for , then?
#11
07/16/2009 (12:44 pm)
It sets the superclass namespace to use, i.e. what you refer to as "Parent" in script:

new ScriptObject( Foobar )
{
   className = "Barfoo";
   superClass = "SuperBarfoo";
};

function SuperBarfoo::foobar()
{
   echo( "SUPER" );
}

function Barfoo::foobar()
{
   echo( "NOT SUPER" );
   Parent::foobar();
}

Foobar2.foobar();
// print:
// NOT SUPER
// SUPER

Admittedly that's a little odd in ways but it is useful.
#12
07/16/2009 (1:21 pm)
This is VERY instructive. Thanks!

However, it doesn't seem to be working for me. For example, if I have this:

datablock PlayerData( DemoPlayerNPCTYPE1 : DemoPlayer )
{
   className = "DemoPlayer";
};

datablock PlayerData( DemoPlayerNPCTYPE2 : DemoPlayer )
{
   className = "DemoPlayer";
};

...what I want is to have the call back function associated with DemoPlayer be called (and thus shared between NPCTYPE1 and 2 for example). As in:

function DemoPlayer::onReachDestination( %this, %obj )
{
   //...
}

However, nowhere do I do anything with "superClass". Is that my problem? Do I need define the superClass as DemoPlayer?
#13
07/16/2009 (1:27 pm)

No, in your case you can pretty much just forget about the whole superClass business.

The code you've posted above works as is.

The onReachDestination method is associated with the DemoPlayer namespace (think "class" here). By setting "className" to "DemoPlayer" you instruct Torque to start looking in that namespace for methods.

So, when the onReachDestination callback is triggered, it will immediately be found in the namespace and correctly be called.

Only when the first, initial namespace yields no result does Torque start walking up the parent hierarchy (think "superclass" here).
#14
07/17/2009 (5:41 am)
Well, I am having the exact same problem as Peter. I believe I understand what Rene and Michael are saying about Inheritance, but it just won't work!

aiplayer.cs does this:

datablock PlayerData(DemoPlayer : DefaultPlayerData) {

shootingDelay = 2000;
};

Eventually, this gets called:

function AIPlayer::spawn(%name,%spawnPoint)
{
// Create the demo player object
%player = new AiPlayer()
{
dataBlock = DemoPlayer;
// dataBlock = npcguard; this is the one I want to create!!
path = "";
};
etc
}

All I want to do, at this point, is override the shape. So, I wrote this:

datablock PlayerData(npcguard : DemoPlayer)
{
superClass = "DefaultPlayerData";
classname = "DemoPlayer";
category="npcs";
shapefile="art/shapes/actors/gideon/base.dts";

};

The above, does indeed override the shape file. But the Bot that is created will not move. It just stands there. This tells me that some behavior or function is not being inherited correctly? I have tried all sorts of combos, such as:

datablock PlayerData(npcguard : DefaultPlayerData)
{ classname=demoplayer;
}

etc etc, but I can not seem to get all the properties of DemoPlayer to be inherited by my datablock.

I thought I understood the inheritance structure, but I guess I dont.

Please help!
#15
07/17/2009 (6:14 am)

Well, your PlayerData looks perfectly fine to me except for "superClass". There's a peculiarity in PlayerData that I haven't noticed before. It is itself using the className "Armor", so the namespace (re-)linking above won't work.

Instead, it probably must be this:

datablock PlayerData(npcguard : DemoPlayer)
{ 
   classname = "DemoPlayer"; 
   superClass = "Armor";
   category="npcs";
   shapefile="art/shapes/actors/gideon/base.dts";
};

As for the player not moving, AIPlayer::spawn() does not set a path on the bot. Without one, it won't move. Is that possibly your problem?
#16
07/17/2009 (6:22 am)
Addendum:

To maybe shed some light on the admittedly somewhat confusing namespace thing.

In other languages you write something like this, for example:

class A : B
{
   // ...

   methodA( parameter1 ) { /* ... /* }
}

In TorqueScript, however, there is no explicit representation of "class A" as such. Instead, the whole thing works by directly modifying the lookup structures.

Methods are associated with namespaces and objects refer to namespaces to tell the system where to start method lookup for them. Each namespace has a parent namespace. *One* parent namespace.

So, what you do when setting up class relations in your objects is to actually modify the namespace relations. If you now have two objects that modify the same namespace in conflicting ways, one setup will not pass.

Ergo: you need to know and conform to the hierarchies as they have been set up through object declarations (or through script functions).

TorqueScript is pretty much stomping all major language design principles, but it makes for a surprisingly powerful language albeit one that requires solid discipline or total mess and anarchy in your script sources will ensue.
#17
07/17/2009 (6:28 am)
Like Steve, what Rene and Michael had said made sense, but was still not working... until now!!

I can stop pulling my hair out now - Rene you solved it.

The key is to include the [superClass = "Armor"] line in the datablock. As in:

datablock PlayerData(SomeNPCGuy : DemoPlayer)
{ 
   classname = "DemoPlayer"; 
   superClass = "Armor";
   shapefile="art/shapes/actors/gideon/base.dts";
};

Once I did that, everything started working again - a call to a SomeNPCGuy.somefunction was now recognizing and calling DemoPlayer.somefunction if SomeNPCGuy.somefunction did not exist.

Thanks Rene!

But what does the [category="npcs"] line do? Turns out it worked without that line included but it looks like it might be useful. What's "category" for?
#18
07/17/2009 (6:55 am)
Yep, making superclass = armor did it! I guess I should have been able to figure that out, once I understood the inheritance structure. Once again, you have my thanks, Rene. Looks like this was what Peter was missing as well.

As far as your other point, for what I am doing so far, AI manager calls AIplayer::followpath after all the spawning functions are done.
#19
07/17/2009 (7:12 am)

Cool. Glad things are working for you know.

Had I actually tried my "Like this, for example" above, I would have noticed that it wouldn't work without the superClass. Oh well.

Have fun torqueing.