Game Development Community

Does the function command mountObject work in TGE1.5.2?

by Infinitum3D · in Torque Game Engine · 04/20/2009 (2:38 pm) · 12 replies

I originally posted this in the Artist Forum, but I think it belongs here. Sorry about the double post, but I couldn't delete it from the other forum.

I'm trying to mount an object with a single "mountpoint" to an object with a single "mount0" mountnode.

It works in ShowTool, but not in Stronghold. I get "unknown command mountObject"...

Any ideas why?

Tony

#1
04/21/2009 (10:03 am)
How are you calling the function and what are you calling it on? Could you post the whole console error?
#2
04/21/2009 (12:37 pm)
//--Thanks Tim Feni for the resource
//--See Also:  Interaction.cs

// -----------------------------------------------------------------------------
// Datablocks - shapes
// -----------------------------------------------------------------------------

datablock StaticShapeData(doorHinge){
 category = "doors";
 className = door;
 shapeFile = "~/data/shapes/doors/hinge_rotate.dts";
 position = "0 0 0";
 Scale="1 1 1";
 emap = true;
 receiveSunLight = "1";
 mountpoint = "0";
};


datablock StaticShapeData(theDoor){
 category = "doors";
 className = door;
 shapeFile = "~/data/shapes/doors/door_mountpoint.dts";
 position = "0 0 0";
 scale="1 1 1";
 emap = true;
 receiveSunLight = "1";
 mountpoint = "0";
};


// ----------------------------------------------------------------------------------
// Functions - door open events
// ----------------------------------------------------------------------------------

    // This function is called whenever the client presses the 'use interaction' key ("u" key)
    // within the set distance.
    // calls from interaction.cs change distance there.



function door::onAdd(%this, %obj)
{
%this.mountObject(%doorHinge, 0); //<<----WHAT IS CORRECT SYNTAX HERE?
}


function door::interact(%this, %obj, %client)
{
	%this.MoveDoor(%obj);
                  echo("just open the door %this.MoveDoor!");
	 messageClient(%client, 'MsgDoorOpen');
}

function door::OpenDoor(%this, %door)
{
 
//This calls the function that incrementally moves the door to give the
//illusion of animation
	%this.MoveDoor(%door);
}

function door::MoveDoor(%this, %door)
{
if (!%door.open)
	{
 	   %door.open = true; 		
	   %door.setthreaddir(0,"true");	
	   %door.playthread(0,"open");	
	}
	   else
	{
	 	   //does a distance check between the door and what hit it last
		   //I have it set for 2... but you can use whatever you like
		   %dist = VectorDist(%col.getTransform(), %door.getTransform());
		   if (%dist > 2)
		{
		   %door.setthreaddir(0,"false");
		   %door.open = false;	      
          		}
	}
}


Everything else works, it just doesn't mount. Is my Datablock wrong? Should mountpoint = "0"; only be part of the object which gets mounted (the door) or only the object which gets mounted to (the hinge)?

Thanks!
Tony
#3
04/21/2009 (12:56 pm)
CONSOLE.LOG
//-------------------------- 4/21/2009 -- 15:41:12 -----

...
edited for length
...
Object 'hinge' is not a member of the 'GameBaseData' data block class
starter.fps/data/missions/SouthYalgophaeMain.mis (0): Register object failed for object (null) of class StaticShape.
Object 'door' is not a member of the 'GameBaseData' data block class
starter.fps/data/missions/SouthYalgophaeMain.mis (0): Register object failed for object (null) of class StaticShape.


...

starter.fps/server/scripts/door.cs (42): Unknown command mountObject.
Object doorHinge(98) doorHinge -> door -> StaticShapeData -> ShapeBaseData -> GameBaseData -> SimDataBlock -> SimObject
starter.fps/server/scripts/door.cs (42): Unknown command mountObject.
Object theDoor(99) theDoor -> door -> StaticShapeData -> ShapeBaseData -> GameBaseData -> SimDataBlock -> SimObject



That's all that pertains to the mounting...

Thanks!
Tony

#4
04/21/2009 (2:00 pm)
Well, here's something interesting. When I add the doorHinge by using the World Editor Creator, when I check it using the Inspector, it doesn't have the animation sequence listed as a Dynamic Field at the bottom. The hinge animation ("open") doesn't play, because it's not recognized as existing.

BUT if I shoot the hinge (with the crossbow) the sequence suddenly appears as a Dynamic Field (open | 0). Now the animation will play correctly.

Why on earth is that?!?!?

How could collision by a projectile correct things?

Tony
#5
04/21/2009 (6:06 pm)
Things I notice in your code block, not sure if they are big problems or not:

Line 44. %doorHinge isn't defined
Line 08. Try calling the datablock "hinge"
Line 20. Try calling the datablock "door"
#6
04/21/2009 (6:23 pm)
Yes, you're right %doorHinge isn't defined. That's what I can't figure out. I know its not right, but what IS the right syntax to put in the mountObject part of the on::add function?

Thanks!
Tony
#7
04/22/2009 (8:18 am)
I'm guessing you want to create a doorHinge object when you add a door. But before that, here's what's causing your original problem - you're trying to mount an object to a datablock. Datablocks do not exist, only objects.

function door::onAdd(%this, %obj)   
{   
%this.mountObject(%doorHinge, 0); //<<----WHAT IS CORRECT SYNTAX HERE?   
}
Assuming the object %doorHinge actually existed, you'd still be off. 'door', which is the namespace where your function is declared, is a datablock (your theDoor datablock is of type 'door'). The first parameter in a datablock method will refer to the datablock - so %this refers to the theDoor datablock. %obj refers to the actual door object that was created and caused onAdd to be called.

Now, if you want to create a hinge for the door, you'll need to actually create the object in the door::onAdd function. Like this:
function door::onAdd(%this, %obj)   
{   
   %doorHinge = new StaticShape() {
      datablock = doorHinge;
   };
   %obj.mountObject(%doorHinge, 0);
}
I don't know if that's technically correct, but it's something like what you've got there.

I noticed you added position and scale members to your StaticShape datablocks. This suggests to me that you're misunderstanding what datablocks actually are. Don't worry - I had the exact same problem when I started Torque. When I got over it, everything started making more sense ;). The fundamental isue is the divide between actual objects and datablock objects. Datablocks aren't real - they just hold static information that should be the same for all objects of that type. A datablock is like a stereotype - say the stereotype that Australians speak like Steve Irwin. If we define an Australian datablock, it might look like this:
datablock AussieData(NormalAussiePerson) {
   speaksLikeSteveIrwin = true;
};
However, the following would not be useful:
datablock AussieData(NormalAussiePerson) {
   speaksLikeSteveIrwin = true;
   currentLocation = Sydney;
};
Because it is not true that all Australians are in Sydney - in fact, none of the sane ones are. ;)
When you define a static shape datablock, you're defining a 'type' of static shape - in your case, a door. It is true that all doors should have a handle - but is is certainly not true that every door should be placed at the position "1 1 1". Different doors may be in different locations, and that is a property of each individual door object, not the door datablock. Just like living in Sydney or living in Melbourne is a property of each individual Australian - not of the Australian stereotype.
#8
04/24/2009 (5:03 am)
Thank you Daniel for having so much patience with me. You've explained things very well.

Quote:
Datablocks do not exist, only objects.

A very good point! I knew this, I just needed reminded :)

Quote:
'door', which is the namespace where your function is declared, is a datablock (your theDoor datablock is of type 'door').

So are "NAMESPACE" and "TYPE" the same thing? 'Namespace' is the term used in a function and 'type' is the term when in a Datablock?

Quote:
The first parameter in a datablock method will refer to the datablock - so %this refers to the theDoor datablock. %obj refers to the actual door object that was created and caused onAdd to be called.

The first parameter in a datablock method will refer to the datablock ALWAYS and the second always refers to the object? Is that standard in all coding (C++?) or just TorqueScript? If so, then that's probably the most important thing I've learned all day :)

Unfortunately the script doesn't work. It compiles, but when I go into the Creator and try to add "theDoor" or "doorHinge" TGE just shuts off. No console errors.

function door::onAdd(%this, %obj)
{
	%doorHinge = new StaticShape()
	{
		datablock = doorHinge;
	};
	%obj.mountObject(%doorHinge, 0);
}

So I changed this line
%doorHinge = new StaticShape()

to this
%doorHinge = new StaticShape("doorHinge")

Now I get the console error - Object 'doorHinge' is not a member of 'GameBaseData' datablock...

Again, thank you for helping with this. I wish there was a primer for this kind of stuff. Like "Torque for Dummies". (I guess there is, it's called University!)

I really appreciate all your help!

Tony
#9
04/24/2009 (7:40 pm)
@Daniel: I'm still laughing at your datablock explanation XD
#10
04/25/2009 (7:19 am)
Quote:So are "NAMESPACE" and "TYPE" the same thing? 'Namespace' is the term used in a function and 'type' is the term when in a Datablock?
Hmm... namespace is a C++ term so I'm not exactly sure exactly what it is ;P. However, you're basically right - the 'type' field deermines what namespace the datablock uses. But I think the datablock namealso defines a namespace - so you could have functions declared like
function theDoor::somethingSpedific(%this)
that would only be valid for the theDoor datablock. However, it's more useful to write generic functions for a broader namespace, so you don't have to rewrite lots of functions. Here's some example scripts, which bryce will probably enjoy ;)

Here's how you'd have to do it if we were just using the datablock's normal namespaces:
dataBlock AussieData(SydneyResident) {
   talksLikeSteveIrwin = true;
   livesIn = Sydney;
};

dataBlock AussieData(MelbourneResident) {
   talksLikeSteveIrwin = true;
   livesIn = Melbourne;
};

//--------------

function SydneyResident::saySomething(%this,%obj)
{
   echo(%obj @ "says: G\'day, mate");
}

function MelbourneResident::saySomething(%this,%obj)
{
   echo(%obj @ "says: G\'day, mate");
}
Now, we might create an Australian object with either datablock and call this code somewhere:
%australian.getDataBlock().saySomething(%australian);
And we'd get in the console:
[whatever the object ID is] says: G\'day, mate
Whichever datablock we use, we get the same output, because the methods for both datablocks are identical (because, of course, all Australians say 'G'day, mate' ;P. This is kind of inelegant, because for every different type of Australian we're going to have to write a new method that does the same thing. So instead:
dataBlock AussieData(SydneyResident) {
   talksLikeSteveIrwin = true;
   livesIn = Sydney;
   type = AustralianPerson;
};

dataBlock AussieData(MelbourneResident) {
   talksLikeSteveIrwin = true;
   livesIn = Melbourne;
   type = AustralianPerson;
};

//--------------

function AustralianPerson::saySomething(%this,%obj)
{
   echo(%obj @ "says: G\'day, mate");
}
Now we can call the saySomething function the same way as before, and obtain the same result - but we've written less code and we can now add more datablocks for different types of Aussie more easily (becaue we only need to define a datablock and don't need to worry about writinga new function).




Quote:The first parameter in a datablock method will refer to the datablock ALWAYS and the second always refers to the object? Is that standard in all coding (C++?) or just TorqueScript? If so, then that's probably the most important thing I've learned all day :)
I think this is the case. It's nothing to do with C++ - in code, there is no concept of a datablock. Datablocks are programmed the same way as objects, both of them are things referred to as 'classes'. It's just that some classes are designated as datablocks and do a certain job. So you could say that it's a Torque thing, not a C++ thing.
To answer your question more clearly: when you call a method on an object, the object is actually passed as the first parameter. So if you call a function like this:
%anyObject.anyFunction(%param1,%param2);
you will actually pass three parameters into the function: %anyObjtct, %param1 and %param2. So if we defined th function like this:
function namespace::anyFunction(%first,%second,%third)
Then %first = %anyObject, %second = %param1, and %third = %param2.




Your problem creating a hinge seems weird. Have you tried running it in a debug build and seeing what error you get?
Quote:Object 'doorHinge' is not a member of 'GameBaseData' datablock...
This usually indicates that there is no datablock named 'doorHinge', but you have defined it. Very odd.
#11
04/28/2009 (4:10 am)
here's what finally worked for me:

//--Thanks Tim Feni for the resource
//--See Also:  Interaction.cs

// -----------------------------------------------------------------------------
// Datablocks - shapes
// -----------------------------------------------------------------------------


datablock StaticShapeData(doorHinge)
{
 	category = "doors";
	className = hinge;
	shapeFile = "~/data/shapes/doors/hinge0424.dts";
    	emap = true;
	receiveSunLight = "1";
	mountPoint = 0;
	name = "hinge";
};


datablock StaticShapeData(theDoor)
{
 	category = "doors";
	className = door;
	shapeFile = "~/data/shapes/doors/door0424.dts";
    	emap = true;
	receiveSunLight = "1";
	mountPoint = 0;
	name = "door";
};

// ----------------------------------------------------------------------------------
// Functions - door open events
// ----------------------------------------------------------------------------------

    // This function is called whenever the client presses the 'use interaction' key ("u" key)
    // within the set distance.
    // calls from interaction.cs change distance there.

function hinge::onAdd(%this, %obj)
{
	%theDoor = new StaticShape("mountedDoor")
	{
		datablock = theDoor;
	};
	%obj.mountObject(%theDoor);
}


function hinge::interact(%this, %obj, %client)
{
	%this.OpenDoor(%obj);
                  echo("just open the door %this.OpenDoor!");
	 messageClient(%client, 'MsgDoorOpen');
}

function hinge::OpenDoor(%this, %door)
{
 

	    //This calls the function that incrementally moves the door to give the
	    //illusion of animation
	%this.MoveDoor(%door);
}

function hinge::MoveDoor(%this, %door)
{
if (!%door.open)
	{
 	   %door.open = true; 		
	   %door.setthreaddir(0,"true");	
	   %door.playthread(0,"open");	
	}
	   else
	{
	 	   //does a distance check between the door and what hit it last
		   //I have it set for 2... but you can use whatever you like
		   %dist = VectorDist(%col.getTransform(), %door.getTransform());
		   if (%dist > 2)
		{
		   %door.setthreaddir(0,"false");
		   %door.open = false;	      
          		}
	}
}
#12
04/29/2009 (11:47 am)
SO that worked for you without the crash you had last time? Good, but odd. Ah well, it probably does make more sense to mount the door to the hinge anyway.