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 «Previous 1 2
#1
02/04/2007 (8:26 am)
The Thingie namespace refers to the datablock, not the object itself which is why calling %obj.sayHi wont work, as it is an object, and not a datablock. Since your Thingie object is a StaticShape, try declaring it like this:

function StaticShape::sayHi()
{
.
.
.
}

--Amr

Edit: Just expanded a little bit
#2
02/05/2007 (10:04 am)
...so my onCollision function is somehow different to functions I create myself, being one that's already defined?

EDIT: I tested this with the change you suggested. The method itself worked, printing 'hi! 1' to the conmsole, then a second later, it printed 'sayHi: Unknown command.'
#3
02/06/2007 (10:57 am)
I thought I was getting it. There's something fundamental in the difference between my implementation of onCollision and hat of sayHi which means one works and the other doesn't. I tried using a className instead of the datablock name.
datablock StaticShapeData(Thingie)
{
   category = "Items";
   shapeFile = "~/data/shapes/3dtorquelogo/torque_logo.dts";
   hiCount = 0;
   className = "AThing";
};

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

function AThing::sayHi(%this)
{
	echo("hi!" SPC %this.hiCount);
	%this.hiCount += 1;
}
The onCollision works fine, but sayHi isn't found.
#4
02/06/2007 (11:06 am)
Hi Daniel,

Again the same reason applies. The AThing className you have in your code has been declared in the datablock. This means that this function is now part of the the Thingie datablock, but NOT the Thingie object that was created using the datablock.

With the code that you have there, try the following in your onCollision code:

%obj.getDatablock.sayHi()

assuming that %obj is a valid Thingie StaticShape object.

Also, a point to note is that as far as I know, you can't modify a datablock in game like you have done there. This is because datablocks are only sent to clients at the start of the game, so subsequent modifications won't be reflected on clients, and since even the Torque single player relies on this architecture, you might run into the same problems.

The last edit in your previous post is interesting - I'm going to try myself and see.

--Amr
#5
02/06/2007 (11:15 am)
I've just tested out this namespace thing in Torque and I didn't get any errors like you described in your second post. Maybe there's something in your script that's calling the function incorrectly?

--Amr
#6
02/06/2007 (11:48 am)
Amr: Thanks for clearing that up... how, then, can I perform changes on individual objects?
#7
02/06/2007 (11:50 am)
Have you a particular example in mind?
#8
02/06/2007 (12:10 pm)
Well, for example, say I have a Thingie names shape1. If I wanted to perform the sayHi() method on it, have its hiCount changed, etc., what changes would I need to make?
By the way, I tried doing an object.getDatablock().sayHi(); and it worked perfectly.

I sense this is a really basic Torque thing I should know :P...
#9
02/06/2007 (12:30 pm)
I see. OK when would you like to do this on your object? For example, you could do this when something collides with your object. In this case, you would use the object datablock's onCollision function. The following is n example, using the Thingie object.

function StaticShape::sayHi()
{
echo("Hi!");
}

function Thingie::onCollision(%this,%obj,%col)
{
//%this points to the Thingie [b]datablock[/b]
//%obj points to the Thingie [b]object[/b]
//%col points to whatever object collided with our thingie object
//In this case, we're only interested in dealing with the Thingie object, so
%obj.sayHi();
%obj.hiCount++; //You CAN create and store variables in objects and this will work perfectly fine
}

The first function is the sayHi function - since your Thingie object is a StaticShape, we have used the StaticShape namespace. Note that any StaticShape object can call sayHi.

The second function does the work. If something collides with your object, Torque calls the onCollision function in the object datablock's namespace. However, when it calls the function it also gives you a reference to the Thingie object itself in the function's 2nd parameter, %obj.

Using %obj, you can then call the sayHi function. You can also create and modify variables in objects, like I've shown in the example above.

Hope that explains!

--Amr

Edit: Just wanted to add this: You'll find that some of the functions that Torque calls on an object (called callbacks e.g.: onCollision, onAdd and many others) are defined in the object's datablock namespace, but you'll always be given a reference to the actual object itself
#10
02/06/2007 (1:26 pm)
There's another thing I just found out, and I thought it'd be useful to share - if you have a function declared in a particular namespace, like the 2 examples above, when you call the function, the first parameter in the function will always point to the thing that's related to the namespace. For example, if you look at the onCollision function, the first paramter is %this, and since the function's namespace is Thingie, which is a datablock, then %this will point to the Thingie datablock.

Likewise, if we had declared the sayHi function like this:

function StaticShape::sayHi(%var)

the function's namespace is StaticShape, so %var will point to the StaticShape which called the function.

Now, let's say you want to call sayHi but with a parameter, e.g.: sayHi("my name is Amr"); you would have to declare sayHi like this:

function StaticShape::sayHi(%var, %message)
{
echo("Hi" SPC %message);
}

The thing to note is that the first parameter will always point to the namespace object. So, even though when we called the function we only passed one parameter, Torque places it second.

By convention, scripters tend to call the first parameter %this in cases like this, since it points to this object, but the names are just arbitrary. As long as your aware of this feature, you can call them whatever you want.

Hope that was useful.

--Amr
#11
02/07/2007 (10:21 am)
Ah... I see the light!...

Thank you for clearing that up :P. Now I just need to figure out what callback methods are available. The thing I'm working on right now is a weapons system. I know Torque has one already, but I don't like it. ;)
So I basically wanted to have a method I call on a weapon to make it fire... which I guess is onFire (seen that used in the example scripts...).

And, henceforth, I shall always name my first parameter %db. %this is just plain misleading :P
#12
02/07/2007 (10:14 pm)
I just wanted to say that Amr's explanations are 100% correct, and he did a better job of explaining it than I do in my Boot Camps--and my job at GarageGames is teaching Torque technology, so that's quite a compliment!

Quote:
And, henceforth, I shall always name my first parameter %db. %this is just plain misleading :P

That is a really really really bad idea....because while the callbacks you happen to currently be working with ARE datablocks, many of the callbacks in Torque are not.

%this is a direct naming convention from the C++ language itself, where you always have a locally scoped variable called "this" which is a pointer to the object that the method is called upon. It's why we use it.
#13
02/08/2007 (9:35 am)
Okay... maybe I won't :P. Thanks for the heads-up.
Quote:you always have a locally scoped variable called "this" which is a pointer to the object that the method is called upon
That's just why it's mislading - it should point to the object, but instead it points to its datablock.
#14
02/08/2007 (12:56 pm)
No , it points to the object who the function is being called upon. Datablocks ARE objects--they just aren't player objects.

You should try to expand your concept of what objects are--just about everything in torque that you ever will use at the scripting layer is an object, and has an ObjectID, as well as a namespace, and quite a lot of other concepts.

In c++, "this" is more accurately is "a pointer to the instantation of the class (known as an object) for which this namespace method is being called".

In Torquescript, it is the "object" (of any type, but guaranteed to at least be a SimObject) on which the method is being called. For moddability and expandability purposes, this very often makes much more sense for the object of callbacks to be the datablock--which unfortunately is a much more involved theory discussion than is appropriate for a forum post.

Summary: datablocks are objects--as are players, and just about everything else.
#15
02/09/2007 (9:23 am)
Right... that's strange, but I guess it makes sense.
Thank you both very much for clearing that up... I'm off to do more testing and ask more newbie questions :P
#16
02/10/2007 (4:43 am)
Okay, one problem. I had a go implementing what I had before, according to Amr's suggestion. This is the .cs file:
//-----------------------------------------------------------------------------
// Torque Game Engine 
// Copyright (C) GarageGames.com, Inc.
//-----------------------------------------------------------------------------

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

function StaticShape::doIt(%this,%obj)
{
	%obj.hitCount++;
	echo("You hit Thingie object" SPC %obj SPC %obj.hitCount SPC "times.");
}

function Thingie:onCollision(%this, %obj, %col)
{
	echo("Collision!");
//	%obj.doIt(%obj); //Not doing this yet
}

Then, when I open the mission, the console gives me this, and the onCollision function doesn't echo anything.
Quote:
Compiling GameOne/server/thingie.cs...
GameOne/server/thingie.cs Line: 19 - parse error
>>> Advanced script error report. Line 19.
>>> Some error context, with ## on sides of error halt:
shapeFile = "~/data/shapes/3dtorquelogo/torque_logo.dts";
hitCount = 0;
};

function StaticShape::doIt(%this,%obj)
{
^%obj.hitCount++;
^echo("You hit Thingie object" SPC %obj SPC %obj.hitCount SPC "times.");
}

function Thingie:onCollision(%this, %obj, %col)
##{##
^echo("Collision!");
//^%obj.doIt(%obj);
}
>>> Error report complete.
It seems to be having trouble with the fact that I want to actually have a function onCollision :P.
#17
02/10/2007 (5:05 am)
I see the problem: You missed out a ":" when writing the on Collision function name.

Just something to note. Remember how the first parameter in the function points to the namespace object? In your case, the first parameter in doIt points to the static shape which called the function, which is your Thingie object. This means that you don't need the 2nd parameter in that function and could just use %this. Regardless, your current code would still work, once that small mistake is fixed.

To summarize, here's how you could implement it.

function StaticShape::doIt(%this)
{
	%this.hitCount++;
	echo("You hit Thingie object" SPC %this SPC %this.hitCount SPC "times.");
}

function Thingie:onCollision(%this, %obj, %col)
{
	echo("Collision!");
//	%obj.doIt(); //Not doing this yet
}

Amr
#18
02/10/2007 (11:36 pm)
I shall now hide my face for thirty days...

(In other words, you should have given me a hiding for posting such a stupid error... :P But thank you for not ;))
#19
02/11/2007 (3:53 am)
Haha, I assure you everyone slips up on the keyboard. Why don't you try a Torque IDE, for example Torsion? That way, the IDE will catch out mistakes like that for you, saving you a lot of headache. You can download a demo from the GG website.

Amr
#20
02/12/2007 (9:16 am)
Aha... I never figured out that Torsion was an IDE. I've been looking for TribalIDE, but the internet's leading me in circles :P

Time for one more question, and probably the whole point of confusion for me here: what's the difference in this case between the StaticShape namespace and the Thingie namespace? Why can I have a Thingie::onCollision but not a Thingie::doIt?

EDIT: And one more specific poblem :P. I think my schedule() syntax is wrong.
With this script:
function StaticShape::sayHi(%obj)
{
	echo("Hi! From" SPC %obj);
}

function Thingie::onCollision(%this, %obj, %col)
{
	echo("Collision!");
	%obj.sayHi();
}
The following is echoed to the console:
Quote:Collision!
Hi! From 1417
But changing it to look like this:
function StaticShape::sayHi(%obj)
{
	echo("Hi! From" SPC %obj);
	schedule(1000,0,sayHi);
}
Echoes the following:
Quote:Collision!
Hi! From 1417
sayHi: Unknown command.
Page «Previous 1 2