Game Development Community

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;
}

#1
07/14/2006 (1:49 pm)
I get this all the time on mine as well. Considering it only happens when the editor loads up, and terrain editing isn't "in" at this point, I wasn't worrying about it.

What you could try (and I just thought of it now) is to name your AtlasInstance "Terrain." So in your script:
new AtlasInstance(Terrain) ...
#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
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
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.