Sim::findObject("Terrain") returns null
by Juan Aramburu · in Torque Game Engine Advanced · 07/14/2006 (1:35 pm) · 12 replies
Why? This is inside the ConsoleFunction getTerrainHeight (terrData.cpp). My terrain is an atlas instance, but returns 0 at every XY value thrown at it. The script that calls this is server-side.
ConsoleFunction(getTerrainHeight, F32, 2, 2, "(Point2I pos) - gets the terrain height at the specified position.")
{
Point2F pos;
F32 height = 0.0f;
dSscanf(argv[1],"%f %f",&pos.x,&pos.y);
TerrainBlock * terrain = dynamic_cast<TerrainBlock*>(Sim::findObject("Terrain"));
[b]if(terrain) //FAILS[/b]
if(terrain->isServerObject())
{
Point3F offset;
terrain->getTransform().getColumn(3, &offset);
pos -= Point2F(offset.x, offset.y);
terrain->getHeight(pos, &height);
}
return height;
}
#2
07/14/2006 (2:00 pm)
Named it Terrain still returns null...I need this function to work cause I have a spawn point @ X,Y,Z. But multiple players will spawn from it, and usually they end up on top of each other if they all have the same spawn transform. So I added a random vector (X, Y, z=0) to it, and use getTerrainHeight(X Y) to see if I'm below the terrain, cause if I am, the player will indefinitely fall.
#3
07/14/2006 (11:10 pm)
Judging soley by what you pasted above, getTerrainHeight() works for the old terrain only.
#4
It looks for an object called "Terrain", then casts it to TerrainBlock* type. Atlas terrains are not TerrainBlock, so the result will be NULL. To get Atlas support, you'd need to also try to cast the Sim::findObject() result to an AtlasInstance and work with it.
I just quickly peeked at the AtlasInstance class, but it doesn't seem to feature a getHeight() method. You could achieve similar results by doing a ray cast, though.
07/15/2006 (8:07 am)
Just to elaborate. This line:TerrainBlock * terrain = dynamic_cast<TerrainBlock*>(Sim::findObject("Terrain"));It looks for an object called "Terrain", then casts it to TerrainBlock* type. Atlas terrains are not TerrainBlock, so the result will be NULL. To get Atlas support, you'd need to also try to cast the Sim::findObject() result to an AtlasInstance and work with it.
I just quickly peeked at the AtlasInstance class, but it doesn't seem to feature a getHeight() method. You could achieve similar results by doing a ray cast, though.
#5
07/15/2006 (2:16 pm)
OK, I will see; but what is a ray cast? Is a ray a special class type that I'm trying to cast something to?
#6
07/17/2006 (9:13 am)
Hehe, no, not *that* kind of cast. I mean ray cast as in "shooting-a-ray-and-checking-where-it-hits".
#7
07/17/2006 (10:27 am)
Atlas does not assume a heightfield. Just do a raycast from a very high Z to a very low Z at the position you want, with just the AtlasObjectType flag passed in.
#8
07/17/2006 (10:50 am)
Tried out doing a raycast, however I have no object to do it on. I can tie to some arbitrary object, but I need to be object-less. In other words, I would like to do something like Container::rayCast(startPos, endPos, pRayInfo) except there's no static form of it.
#9
07/17/2006 (11:30 am)
Sure there is - in C++ you do either gClientContainer->castRay or gServerContainer->castRay, in script you do (IIRC) containerCastRay, which always does it against the server container.
#10
Then, in script:
07/20/2006 (12:04 pm)
Thanks Ben. Found that the actual TorqueScript function name is ContainerRayCast, but I just ended up writing it in-engine.ConsoleFunction(getTerrainHeightAtlas, F32, 2, 2, "(Point2I pos) - gets the terrain height at the specified position + atlas support")
{
Point3F posStart(0.0F, 0.0F, 0.0F), posEnd(0.0F, 0.0F, 0.0F);
F32 height = 0.0f;
RayInfo rInfo;
dSscanf(argv[1],"%f %f",&posStart.x,&posStart.y);
posStart.z = -5000;
posEnd.set(posStart.x, posStart.y, 5000);
if (gServerContainer.castRay(posStart, posEnd, AtlasObjectType|TerrainObjectType, &rInfo))
height = rInfo.point.z;
return height;
}Then, in script:
//randomVector(%maxRadius, %bDoRandomZ)
// -> just creates a random vector XY vector (or XYZ if %bDoRandomZ is true)
function getGoodBotSpawnPoint(%basePoint) {
%theZ = -1;
%terrainLocation = 1;
%tCount = 0;
while (%terrainLocation > %theZ) { //terrainZ is above the Z we got
if (%tCount == 20) {
//if it takes too long, get out & just return the default spawn
echo("break due to no point found");
%theSpawnPoint = %basePoint;
break;
}
%theSpawnPoint = TransformVectorAdd(%basePoint,randomVector(25, false));
%theXY = getWords(%theSpawnPoint, 0, 1);
%theZ = getWord(%theSpawnPoint, 2);
//echo("z=" @ %theZ @ "; xy=" @ %theXY);
%terrainLocation = getTerrainHeightAtlas(%theXY);
//echo("terrain=" @ %terrainLocation);
%tCount++;
}
return %theSpawnPoint;
}
#11
07/20/2006 (2:00 pm)
Looks good. Don't forget to update the usage string - you're accepting a Point2F not a Point2I.
#12
07/20/2006 (2:27 pm)
Ah, OK...I just copied & pasted the declaration from the original getTerrainHeight, so I guess I should update that too.
Torque 3D Owner Mark Dynna
What you could try (and I just thought of it now) is to name your AtlasInstance "Terrain." So in your script: