Game Development Community

Namespace problems

by Daniel Buckmaster · in Torque Game Engine · 02/04/2007 (6:29 am) · 31 replies

I have this script, linked into the Getting Started tutorial in the same way as logoitem is.
datablock StaticShapeData(Thingie)
{
   category = "Items";
   shapeFile = "~/data/shapes/3dtorquelogo/torque_logo.dts";
   hiCount = 0;
};

function Thingie::onCollision(%this,%obj,%col)
{
	if(%col.getClassName() $= "Player")
	{
		%client = %col.client;
		commandToClient(%client,'EchoConsole',"Collided with Thinge object");
	}
}

function Thingie::sayHi(%this)
{
	%this.hiCount += 1;
	echo("hi!" SPC %this.hiCount);
	schedule(1000,0,sayHi);
}
Now, whenever I collide with the object, I get "Collided with Thinge object" in the console, but when I try to call the sayHi method on it, I get:

==>shape1.sayHi();
(0): Unknown command sayHi.
Object Shape1(1782) StaticShape -> ShapeBase -> GameBase -> SceneObject -> NetObject -> SimObject

About the author

Studying mechatronic engineering and computer science at the University of Sydney. Game development is probably my most time-consuming hobby!

Page«First 1 2 Next»
#21
02/12/2007 (3:48 pm)
Quote:What's the difference in this case between the StaticShape namespace and the Thingie namespace?

I guess you could say the difference is who owns the function. If you declare a function with a namespace, then that namespace owns the function and can use it.

The thing you want to say to yourself is: what do I want to call the function on? Is it a Player? StaticShape? Item? A StaticShapeDatablock? The choice of namespace relies on what you want to call the function on.

In your case, you wanted to call a function on a StaticShape, which was why we used the StaticShape namespace. By declaring the function that way, you've written a function that all StaticShape objects can use and call.

Quote:Why can I have a Thingie::onCollision but not a Thingie::doIt?

There's nothing to stop you having a Thingie::doIt function. The problem you had was that you were using it incorrectly. Thingie is a StaticShapeData object. Because the function was declared with the Thingie namespace, only Thingie objects can use that function. You were trying to use doIt on a StaticShape object and that's why it didn't work. A StaticShape is a seperate object from a StaticShapeData object. They are related, but they're seperate objects.

Quote:I think my schedule() syntax is wrong.

Your schedule syntax is just fine. The problem is that there's no function called "sayHi". The function is called StaticShape::sayHi.

Now, if you try modfying your shedule to use StaticShape::sayHi instead of sayHi, you'll come up with an error.

Alternatively, try doing it this way:

%obj.schedule(1000,sayHi);

Because your using %obj.schedule, you don't need to add the StaticShape:: infront of sayHi, because %obj is a StaticShape, so Torque assumes the StaticShape namespace.

I hope that's clear!

--Amr
#22
02/13/2007 (11:48 am)
Quote:There's nothing to stop you having a Thingie::doIt function. The problem you had was that you were using it incorrectly. Thingie is a StaticShapeData object. Because the function was declared with the Thingie namespace, only Thingie objects can use that function. You were trying to use doIt on a StaticShape object and that's why it didn't work. A StaticShape is a seperate object from a StaticShapeData object. They are related, but they're seperate objects.
So what is a Thingie object, then? Do I need a className definition in the Thingie datablock? And if so, why does Thingie::onCollision work without having this?

Wait... are callback methods called on an object's datablok? That would explain why Thingie::onCollision worked, because Thingie is a datablock.
#23
02/13/2007 (3:13 pm)
You have the following in your code:

datablock StaticShapeData(Thingie)
{
   category = "Items";
   shapeFile = "~/data/shapes/3dtorquelogo/torque_logo.dts";
   hiCount = 0;
};

You've defined a StaticShapeData object called Thingie and so Thingie is a StaticShapeData.

You do not need a className for any object to work, because you can use the object's name (if it has one - e.g.: Thingie) as a namespace or you can use an object's type (e.g.: StaticShapeData). However, classNames are useful because they add an extra namespace to your object. Here's an example:

Lets say you have 3 different types of exploding objects in your game: dynamite, flaming barrels and mines. For each of these 3 objects you would define a seperate datablock. However, when it comes to collision these objects behave in exactly the same way.

What you might do is define 3 onCollision functions: Dynamite::onCollision, Barrels::onCollision and Mines::onCollision. The problem with this is that you have 3 seperate functions which are doing exactly the same thing. Here's where className comes in handy.

In each of the 3 datablocks, you add the line className=Explosive. How you only need to write one onCollision function, which is Explosive::onCollision. This new function can be used with all 3 datablocks, because they share the same nameSpace.

I don't know if ALL callbacks are called on datablocks, but quite a fair bit are. The best way to find out is to look up the callback name in the TDN and find out, or if you have the Game Programmer's Guide to Torque, there's a really handy reference book on the CD.

--Amr
#24
02/14/2007 (12:02 pm)
So a definition 'datablock StaticShapeData(Thingie)' is a StaticShapeData object with the name Thingie. Then if I give, for example a StaticShape object the datablock Thingie, that shape just inherits the fields I defined in Thingie.

So, for the above, I want to create some objects that use the Thingie datablock, and are part of their own little group. If I added className = "Things"; to Thingie, could I then define Things::whatever functions and use thoses on the objects that are created with the Thingie datablock?
#25
02/14/2007 (4:20 pm)
Yep, I agree with nearly everything you said there.

The only thing I want to comment on is where you said
Quote:that shape just inherits the fields I defined in Thingie
. When creating an object using a datablock, the object doesn't inherit the datablock fields.

--Amr
#26
02/14/2007 (7:27 pm)
The only other thing to add here is that the engine selects which object, and therefore which namespace to search for when it provides a callback to script.

Most of the time the callback will be on an object's datablock namespace, but occasionally it will be on the object itself, and the decision is made based on the type of callback and it's expected use. Here's two examples:

GameConnection::onClientEnterGame()
{
}

This callback is provided on an object's namespace (the GameConnection object, which is the server's object that contains information and the bitstream for connecting with a client) because in stock, there is no reason to have different types of GameConnection objects--in other words, there aren't GameConnection datablocks.

Armor::onEnterLiquid()
{
}

This is a datablock namespace callback. The object in this case will be a Player, but the callback is sent to the Player's datablock namespace, because it very much makes sense that we may have different types of players, and each may handle entering liquid differently--even though both are still Players.

The example I commonly use here is that of the following types of Player datablocks:

Robot
Human
ScubaDiver

--a human might start taking damage (can't breathe) when liquid is entered. Movement is slowed somewhat.
--a robot wouldn't take damage, and would move the exact same way under water as not.
--a scuba diver would move much faster (swimming with fins), and would not take damage (oxygen tank).

Since the engine provides the ::onEnterLiquid() callback on the datablock's namespace, we as scripters can affect behaviour for different datablocks differently, while still having all of the code for the Player class relatively unchanged...and this is what modding/scripting is all about.
#27
02/17/2007 (12:38 am)
But can I write my own functions that use these namespaces, or am I restricted to using only the callbacks already defined? (I don't want to get into engine coding just yet...)

This:
datablock StaticShapeData(Thingie)
{
   category = "Items";
   shapeFile = "~/data/shapes/3dtorquelogo/torque_logo.dts";
   hitCount = 0;
   className = "Thingies";
};

function Thingies::sayHi(%obj)
{
	echo("Hi! From" SPC %obj);
	%obj.schedule(1000,sayHi);
}

function Thingies::onCollision(%this, %obj, %col)
{
	echo("Thingie Collision!");
	%obj.sayHi();
}
Will echo 'Thingie Collision!' and then say it can't find the function sayHi in the object's namespace chain (the chain starts with StaticShape). Is this another issue where I'm getting confused as to what's being called on what?

I did a little testing, and defined a new function, Thingie::sayHi (as opposed to 'Thingies'). When I called %this.sayHi() in onCollision, it worked. However, it wouldn't work when calling it on %obj.

Quote:When creating an object using a datablock, the object doesn't inherit the datablock fields.
Now I'm even more confused...
#28
02/17/2007 (4:52 pm)
Quote:But can I write my own functions that use these namespaces, or am I restricted to using only the callbacks already defined? (I don't want to get into engine coding just yet...)

You can certainly write and use your own functions in script. You aren't restricted to the defined callbacks.

Quote:When creating an object using a datablock, the object doesn't inherit the datablock fields.

When you write a datablock, you are telling Torque how you would like it to create an object. Torque takes the datablock, looks at the information and uses that to create an object. It doesn't copy the information in the datablock to the object - it just uses the datablock as a kind of instruction sheet, telling it how to create the object. Your datablock has the following fields: category shapeFile hitCount and className. Your object, will not have those fields and because of this, your object doesn't fall under the Thingies namespace.

--Amr
#29
02/17/2007 (11:39 pm)
So if I want an object to have dynamic fields, I need to define them myself, instead of getting a datablock to set them?
Then if this is true, I need to set className = Thingies to each object that I create and want to use to use functions?
#30
02/18/2007 (3:14 am)
Quote:So if I want an object to have dynamic fields, I need to define them myself, instead of getting a datablock to set them?

That is correct. A good time to initialize these fields might be during the onAdd callback, which is called when the object is created and added to the mission.

Quote:Then if this is true, I need to set className = Thingies to each object that I create and want to use to use functions?

Theoreically, that's correct. However, I think only datablocks have a className property. I think when it comes to other objects, you're going to have to use the object type's namespace (e.g.: StaticShape, Player, Item etc).

--Amr
#31
02/18/2007 (5:04 am)
Okay. I think there's the heart of the issue. So basically, methods should be structured like callbacks - called on an object's datablock to have access to the fields defined there, but also to the object itself. Then I define those callback functions in the datablock namespace.

EDIT: But if I want to put creators for dynamic fields in an onAdd function, I can't make those fields unique to different types of items! That's the problem. I would have to give all StaticShape objects those dynamic fields (or all Players, or all Items, etc.).
Page«First 1 2 Next»