Hi.
I want to add objects to the world of Roaming Ralph and I want to randomize the XY position of the objects.
How can I get the Z coordinate of any given XY point in the “world” ??
Best regards,
KK
Hi.
I want to add objects to the world of Roaming Ralph and I want to randomize the XY position of the objects.
How can I get the Z coordinate of any given XY point in the “world” ??
Best regards,
KK
You must place a temporary object with a CollisionRay at the given point and check it for collisions. Just exactly as in Ralph’s case.
i really sugest you change the terrain to a Geomipmap one, then you only have to use the built-in getElevation(x,y) function
Hi guys.
I’ve created the CollisionRay at the given xy point, attached it to my object and it points down to the terrain. How can I get the Z coordinate to move my object down to the ground?
I’m a total newby, so sorry for the silly questions
Create a collision handler, attach to traverser, traverse once and get the collision entry from the handler (unless you use a Floor handler, in which case it gets done automatically, I guess)
Roaming Ralph shows how to achieve this.
I implemented it creating a node with a collisionray pointing down, and a personal traverser; when i load the level, i place the collision node at random x, y position, call traverser.traverse(render) and get the x from the cEntry with a cHandlerQueue.
Then i place at that position the model I want.
This metod creates the nodes:
def createRayPutter(self):
#this node serves to put elements at the right height
self.cDummy=self.model.attachNewNode(CollisionNode("cDummy"))
self.floorRay=CollisionRay()
self.floorRay.setDirection(0,0,-1)
self.floorRay.setOrigin(0, 0, 100)
self.cDummy.node().addSolid(self.floorRay)
self.cDummy.node().setIntoCollideMask(BitMask32.allOff())
self.cDummy.node().setFromCollideMask(BitMask32.bit(0))
self.cHandler=CollisionHandlerQueue()
self.cTrav=CollisionTraverser()
self.cTrav.addCollider(self.cDummy, self.cHandler)
Then I use another metod to do the rest:
def putBush(self):
for x in range(1000):
holder=loader.loadModel("Models/grassBlade")
holder.reparentTo(self.flattenHolder)
x=random.random()*300-150
y=random.random()*300-150
self.cDummy.setPos(x, y, 0)
self.cTrav.traverse(self.model)
if self.cHandler.getNumEntries()>0:
self.cHandler.sortEntries()
pos=self.cHandler.getEntry(0).getSurfacePoint(render)
holder.setPos(pos)
holder.setH(random.random()*120)
self.cHandler.clearEntries()
print "Nodes flattened (grassBlade): ",self.flattenHolder.flattenStrong()
These are inside my “level” class, and self.flattenHolder is a temporary node just to flatten static models.
At the end of the init i destroy the cHandler, the cDummy and the traverser, as i don’t need them anymore.
probably you won’t need it now, but here’s a way for finding the elevation of a terrain without need of collisions. Basically is a bilinear interpolation function wich find the elevation point given 4 vertices, so you first have to found the 4 vertices of the terrain wich are nearest to the character and then found the elevation.
The getElevation function:
def getElevation(self,x,y):
""" returns the terrain elevation at the given xy location
Uses bilinear interpolation (thanks pro-soft for let me know about that)
(1-a)(1-b) a(1-b) where a and b are the horizontal and vertical
b(1-a) ab distances to the nearest top-left pixel.
"""
v1,v2,v3,v4=self.getCellVertices(x,y)
#get elevation: bilinear interpolation
a=abs(x-v4[0])#x distance to top-left
b=abs(y-v4[1])#y distance to top-right
i1=v4[2]#top-left
i2=v3[2]#top-right
i3=v1[2]#bottom-left
i4=v2[2]#bottom-right
#bilinear interpolation equation
z=(1-a)*(1-b)*i1 + (a)*(1-b)*i2 + (1-a)*(b)*i3 + (a)*(b)*i4
return z
and the function for finding the 4 vertices:
(it was a grid based thing so always the char was in a given cell of an grid array wich had the height values of the vertices stored)
def getCellVertices(self,x,y,debug=False):
""" calculates the location of the 4 vertices of the current cell at the given location """
#vertex 1
x1=int(x)
y1=int(y)
z1=self.data[x1][y1]['h']
#vertex2
x2=x1+1
y2=y1
z2=self.data[x2][y2]['h']
#vertex3
x3=x1+1
y3=y1+1
z3=self.data[x3][y3]['h']
#vertex4
x4=x1
y4=y1+1
z4=self.data[x4][y4]['h']
return (x1,y1,z1),(x2,y2,z2),(x3,y3,z3),(x4,y4,z4)
As i said, probably you won’t need it now but i thing is an interesting approach wich was sugested to me by rpro-soft, and in fact is a lot more fast than collision detection…
Or, if you use the GeoMipTerrain, the builtin getElevation function already performs bilinear interpolation, if you supply non-whole numbers.
Well, is it possible to change the world in RoamingRalphs sample program to a GeoMipTerrain ? The sample program only comes with the file world.egg.pz and no grayscale image of the terrain.
yes of course its possible
-you have to change the code yourself and generate a geomipmap terrain from a given heightmap and texturize it with a given texture
-take a look at Yet Another Roaming Ralph entry in the forums, it has the geomipterrain already implemented
c