def play(self, ai, difficult=False): self.easyAI.destroy() self.hardAI.destroy() self.ai = None self.cTrav = CollisionTraverser() self.coll = CollisionHandlerEvent() self.coll.addInPattern("%fn-into-%in") self.clock = ClockObject() terrain = GeoMipTerrain("worldTerrain") terrain.setHeightfield("heightMap.png") terrain.setColorMap("colormap.png") terrain.setBruteforce(True) root = terrain.getRoot() root.reparentTo(self.render) root.setSz(1) terrain.generate() self.player = Character("models/panda-model", 0.05, (300, 300, 0), self.render, {"walk": "models/panda-walk4"}, self, self.path, 200, "player") self.addControls() self.loadUI() self.startTasks() self.accept("proj-into-player", self.player.changeLife, [-1]) self.others = dict() self.roundOv = False self.taskMgr.add(self.update, "Update") self.gameOver = False if ai: self.aiBattle(difficult)
def __init__(self, data_source): ShowBase.__init__(self) if not os.path.isfile('world.bam'): terrain = GeoMipTerrain("worldTerrain") terrain.setHeightfield(os.path.join(RESOURCE_DIR, "uk_height_map_25.png")) terrain.setColorMap(os.path.join(RESOURCE_DIR, "uk_flopped_rotated_25.png")) terrain.setBruteforce(True) root = terrain.getRoot() root.reparentTo(render) root.setSz(10) terrain.generate() root.writeBamFile('world.bam') else: world = loader.loadModel("world.bam") world.reparentTo(render) self.toasters = {} self.toasters_by_zone = {} for vm in data_source.get_vms(): height = len(self.toasters_by_zone.get(vm.zonename, [])) self.toasters[vm.name] = Toaster(vm.zonename, height, vm.state == "Running") self.toasters_by_zone.setdefault(vm.zonename, []).append(self.toasters[vm.name]) # In Panda3D you have to cancel the default mouse control to set the camera explicitly # Falsify the following 3 lines to allow it back again: if True: self.disableMouse() self.camera.setPos(350, -100, 100) self.camera.setHpr(0, -25, 0)
def __init__(self, data_source): ShowBase.__init__(self) if not os.path.isfile('world.bam'): terrain = GeoMipTerrain("worldTerrain") terrain.setHeightfield( os.path.join(RESOURCE_DIR, "uk_height_map_25.png")) terrain.setColorMap( os.path.join(RESOURCE_DIR, "uk_flopped_rotated_25.png")) terrain.setBruteforce(True) root = terrain.getRoot() root.reparentTo(render) root.setSz(10) terrain.generate() root.writeBamFile('world.bam') else: world = loader.loadModel("world.bam") world.reparentTo(render) self.toasters = {} self.toasters_by_zone = {} for vm in data_source.get_vms(): height = len(self.toasters_by_zone.get(vm.zonename, [])) self.toasters[vm.name] = Toaster(vm.zonename, height, vm.state == "Running") self.toasters_by_zone.setdefault(vm.zonename, []).append(self.toasters[vm.name]) # In Panda3D you have to cancel the default mouse control to set the camera explicitly # Falsify the following 3 lines to allow it back again: if True: self.disableMouse() self.camera.setPos(350, -100, 100) self.camera.setHpr(0, -25, 0)
def createGround(self, terrainData): """Create ground using a heightmap""" # Create heightfield for physics heightRange = terrainData["heightRange"] # Image needs to have dimensions that are a power of 2 + 1 heightMap = PNMImage(self.basePath + terrainData["elevation"]) xdim = heightMap.getXSize() ydim = heightMap.getYSize() shape = BulletHeightfieldShape(heightMap, heightRange, ZUp) shape.setUseDiamondSubdivision(True) np = self.outsideWorldRender.attachNewNode(BulletRigidBodyNode("terrain")) np.node().addShape(shape) np.setPos(0, 0, 0) self.physicsWorld.attachRigidBody(np.node()) # Create graphical terrain from same height map terrain = GeoMipTerrain("terrain") terrain.setHeightfield(heightMap) terrain.setBlockSize(32) terrain.setBruteforce(True) rootNP = terrain.getRoot() rootNP.reparentTo(self.worldRender) rootNP.setSz(heightRange) offset = xdim / 2.0 - 0.5 rootNP.setPos(-offset, -offset, -heightRange / 2.0) terrain.generate() # Apply texture diffuse = self.loader.loadTexture(Filename(self.basePath + terrainData["texture"])) diffuse.setWrapU(Texture.WMRepeat) diffuse.setWrapV(Texture.WMRepeat) rootNP.setTexture(diffuse) textureSize = 6.0 ts = TextureStage.getDefault() rootNP.setTexScale(ts, xdim / textureSize, ydim / textureSize) # Create planes around area to prevent player flying off the edge # Levels can define barriers around them but it's probably a good # idea to leave this here just in case sides = ( (Vec3(1, 0, 0), -xdim / 2.0), (Vec3(-1, 0, 0), -xdim / 2.0), (Vec3(0, 1, 0), -ydim / 2.0), (Vec3(0, -1, 0), -ydim / 2.0), ) for sideNum, side in enumerate(sides): normal, offset = side sideShape = BulletPlaneShape(normal, offset) sideNode = BulletRigidBodyNode("side%d" % sideNum) sideNode.addShape(sideShape) self.physicsWorld.attachRigidBody(sideNode)
def __init__(self): ShowBase.__init__(self) # initialise terrain = GeoMipTerrain("worldTerrain") # create a terrain terrain.setHeightfield("HM.jpg") # set the height map #terrain.setColorMap("512xA_TN.jpg") # set the colour map terrain.setBruteforce(True) # level of detail root = terrain.getRoot() # capture root root.reparentTo(render) # render from root root.setSz(60) # maximum height terrain.generate() # generate
def __init__(self): ShowBase.__init__(self) # initialise terrain = GeoMipTerrain("worldTerrain") # create a terrain terrain.setHeightfield("mapheight.png") # set the height map terrain.setColorMap("maptex.png") # set the colour map terrain.setBruteforce(True) # level of detail root = terrain.getRoot() # capture root root.reparentTo(render) # render from root root.setSz(60) # maximum height terrain.generate() # generate
def __init__(self): ShowBase.__init__(self) terrain = GeoMipTerrain("worldTerrain") terrain.setHeightfield("height-map.png") terrain.setColorMap("texture-map.png") terrain.setBruteforce(True) root = terrain.getRoot() root.reparentTo(render) root.setSz(60) terrain.generate()
def generate(self): '''(Re)generate the entire terrain erasing any current changes''' factor = self.blockSize*self.chunkSize #print "Factor:", factor for terrain in self.terrains: terrain.getRoot().removeNode() self.terrains = [] # Breaking master heightmap into subimages heightmaps = [] self.xchunks = (self.heightfield.getXSize()-1)/factor self.ychunks = (self.heightfield.getYSize()-1)/factor #print "X,Y chunks:", self.xchunks, self.ychunks n = 0 for y in range(0, self.ychunks): for x in range(0, self.xchunks): heightmap = PNMImage(factor+1, factor+1) heightmap.copySubImage(self.heightfield, 0, 0, xfrom = x*factor, yfrom = y*factor) heightmaps.append(heightmap) n += 1 # Generate GeoMipTerrains n = 0 y = self.ychunks-1 x = 0 for heightmap in heightmaps: terrain = GeoMipTerrain(str(n)) terrain.setHeightfield(heightmap) terrain.setBruteforce(self.bruteForce) terrain.setBlockSize(self.blockSize) terrain.generate() self.terrains.append(terrain) root = terrain.getRoot() root.reparentTo(self.root) root.setPos(n%self.xchunks*factor, (y)*factor, 0) # In order to texture span properly we need to reiterate through every vertex # and redefine the uv coordinates based on our size, not the subGeoMipTerrain's root = terrain.getRoot() children = root.getChildren() for child in children: geomNode = child.node() for i in range(geomNode.getNumGeoms()): geom = geomNode.modifyGeom(i) vdata = geom.modifyVertexData() texcoord = GeomVertexWriter(vdata, 'texcoord') vertex = GeomVertexReader(vdata, 'vertex') while not vertex.isAtEnd(): v = vertex.getData3f() t = texcoord.setData2f((v[0]+ self.blockSize/2 + self.blockSize*x)/(self.xsize - 1), (v[1] + self.blockSize/2 + self.blockSize*y)/(self.ysize - 1)) x += 1 if x >= self.xchunks: x = 0 y -= 1 n += 1
def __init__(self): ShowBase.__init__(self) # initialise terrain = GeoMipTerrain("worldTerrain") # create a terrain terrain.setHeightfield("test_height_map.png") # set the height map terrain.setColorMap("test_texture_map.png") # set the colour map terrain.setBruteforce(True) # level of detail root = terrain.getRoot() # capture root root.reparentTo(self.render) # render from root root.setSz(60) # maximum height terrain.generate() # generate root.writeBamFile('world.bam') # create 3D model
def __init__(self): ShowBase.__init__(self) terrain = GeoMipTerrain("worldTerrain") terrain.setHeightfield("models/issue1terrain.png") terrain.setColorMap("models/issue2terrain.png") terrain.setBruteforce(True) # level of detail root = terrain.getRoot() root.reparentTo(render) root.setSz(60) # maximum height terrain.generate() root.writeBamFile("models/world.bam")
def __init__(self): ShowBase.__init__(self) # initialise terrain = GeoMipTerrain("worldTerrain") # create a terrain terrain.setHeightfield(height) # set the height map terrain.setColorMap(texture) # set the colour map terrain.setBruteforce(True) # level of detail root = terrain.getRoot() # capture root root.reparentTo(render) # render from root root.setSz(2) # maximum height terrain.generate() # generate root.writeBamFile('models/world' + worldNameSuffix + ".bam") # create 3D model
def __init__(self): ShowBase.__init__(self) self.debug = False self.statusLabel = self.makeStatusLabel(0) self.collisionLabel = self.makeStatusLabel(1) if os.path.isfile("assets/1stmap.bam"): self.world = self.loader.loadModel("assets/1stmap.bam") self.world.reparentTo(self.render) else: print "generating terrain and saving bam for future use" terrain = GeoMipTerrain("worldTerrain") terrain.setHeightfield("./assets/1stmap_HF.png") terrain.setColorMap("./assets/1stmap_TM.png") terrain.setBruteforce(True) root = terrain.getRoot() root.reparentTo(self.render) root.setSz(60) terrain.generate() root.writeBamFile("./assets/1stmap.bam") self.worldsize = 1024 # Player self.maxspeed = 100.0 self.startPos = Vec3(200, 200, 35) self.startHpr = Vec3(225, 0, 0) self.player = self.loader.loadModel("assets/alliedflanker.egg") self.player.setScale(0.2, 0.2, 0.2) self.player.reparentTo(self.render) self.resetPlayer() # Player destruction self.explosionModel = loader.loadModel("assets/explosion") self.explosionModel.reparentTo(self.render) self.explosionModel.setScale(0.0) self.explosionModel.setLightOff() # Only one explosion at a time self.exploding = False self.taskMgr.add(self.updateTask, "update") self.keyboardSetup() self.maxdistance = 600 self.camLens.setFar(self.maxdistance) self.camLens.setFov(60) self.createEnvironment() self.setupCollisions() self.textCounter = 0
class MyApp(ShowBase): # our 'class' def __init__(self): ShowBase.__init__(self) # initialise self.terrain = GeoMipTerrain("worldTerrain") # create a terrain self.terrain.setHeightfield( "heightmapper-1567436259173.png") # set the height map self.terrain.setColorMap( "TexturesCom_Moss0138_2_L.jpg") # set the colour map self.terrain.setBruteforce(True) # level of detail root = self.terrain.getRoot() # capture root root.reparentTo(self.render) # render from root root.setSz(80) # maximum height self.terrain.generate() # generate self.sphere = self.loader.loadModel("skysphere-1.egg") self.sphere.setScale(700) self.sphere.setPos(500, 500, 0) self.tex = self.loader.loadTexture("TexturesCom_Skies0282_L.jpg") self.sphere.setTexture(self.tex) self.sphere.reparentTo(self.render) self.setupLight() def setupLight(self): self.sunLight = DirectionalLight("sun") # sunLight.setColor(get_vbase4_from_hex('fbfcde')) self.sunLight.setColor(VBase4(.99, .99, .99, 1)) self.light = self.render.attach_new_node(self.sunLight) self.light.setHpr(45, -45, 0) self.light.setPos(0, 0, 300) self.render.setLight(self.light) ambientLight = AmbientLight("ambient") ambientLight.setColor(VBase4(0.2, 0.2, 0.2, 1)) self.ambientLight = self.render.attach_new_node(ambientLight) self.render.setLight(self.ambientLight) return
def generate(self): '''(Re)generate the entire terrain erasing any current changes''' factor = self.blockSize * self.chunkSize #print "Factor:", factor for terrain in self.terrains: terrain.getRoot().removeNode() self.terrains = [] # Breaking master heightmap into subimages heightmaps = [] self.xchunks = (self.heightfield.getXSize() - 1) / factor self.ychunks = (self.heightfield.getYSize() - 1) / factor #print "X,Y chunks:", self.xchunks, self.ychunks n = 0 for y in range(0, self.ychunks): for x in range(0, self.xchunks): heightmap = PNMImage(factor + 1, factor + 1) heightmap.copySubImage(self.heightfield, 0, 0, xfrom=x * factor, yfrom=y * factor) heightmaps.append(heightmap) n += 1 # Generate GeoMipTerrains n = 0 y = self.ychunks - 1 x = 0 for heightmap in heightmaps: terrain = GeoMipTerrain(str(n)) terrain.setHeightfield(heightmap) terrain.setBruteforce(self.bruteForce) terrain.setBlockSize(self.blockSize) terrain.generate() self.terrains.append(terrain) root = terrain.getRoot() root.reparentTo(self.root) root.setPos(n % self.xchunks * factor, (y) * factor, 0) # In order to texture span properly we need to reiterate through every vertex # and redefine the uv coordinates based on our size, not the subGeoMipTerrain's root = terrain.getRoot() children = root.getChildren() for child in children: geomNode = child.node() for i in range(geomNode.getNumGeoms()): geom = geomNode.modifyGeom(i) vdata = geom.modifyVertexData() texcoord = GeomVertexWriter(vdata, 'texcoord') vertex = GeomVertexReader(vdata, 'vertex') while not vertex.isAtEnd(): v = vertex.getData3f() t = texcoord.setData2f( (v[0] + self.blockSize / 2 + self.blockSize * x) / (self.xsize - 1), (v[1] + self.blockSize / 2 + self.blockSize * y) / (self.ysize - 1)) x += 1 if x >= self.xchunks: x = 0 y -= 1 n += 1
def makeBlock(self, drawResourcesFactories, x, y, x1, y1, tileCenter, collision): drawResourcesFactory = drawResourcesFactories[self.LOD] tile = drawResourcesFactory.getTile() resources = drawResourcesFactory.getDrawResources(self.dataIndex[self.LOD]) # Set up the GeoMipTerrain terrain = GeoMipTerrain("TerrainTile") heightTex = tile.bakedTile.renderMaps[self.specialMaps["height"]].tex heightTexSize = heightTex.getXSize() pnmImage = PNMImage() # heightTex.makeRamImage() # Makes it run without having ran image in advance, but it all ends up flat. heightTex.store(pnmImage) terrain.setHeightfield(pnmImage) # Set terrain properties terrain.setBruteforce(True) # Store the root NodePath for convenience root = terrain.getRoot() root.setPos(tile.bakedTile.x - tileCenter.getX(), tile.bakedTile.y - tileCenter.getY(), 0) for t in self.texList: texScale = 1.0 / (t[1]) root.setTexture(t[0], t[2]) root.setShaderInput("tex2D_" + t[3], t[2]) root.setTexScale(t[0], texScale * tile.tileScale) root.setTexOffset(t[0], (tile.getX() % t[1]) * texScale, (tile.getY() % t[1]) * texScale) for t in self.mapTexStages: tex = tile.bakedTile.renderMaps[t].tex root.setTexture(self.mapTexStages[t], tex) # Here we apply a transform to the textures so centers of the edge pixels fall on the edges of the tile # Normally the edges of the edge pixels would fall on the edges of the tiles. # The benifits of this should be visible, though they have not been varified sucessfully yet. # In fact, these transforms appear to not do anything. # This is troubling, but the problem they are supposed to fix is currently invisible as well. # size=tex.getXSize() # margin=bakery.texMargin(size) # tile.setTexOffset(t,-margin,-margin) # tile.setTexScale(t,float(size+margin*2)/size) root.setShaderInput("offset", tile.bakedTile.x, tile.bakedTile.y, 0.0, 0.0) root.setShaderInput("scale", tile.bakedTile.scale) xyScale = float(tile.tileScale) / (heightTexSize - 1) root.setScale(xyScale, xyScale, self.heightScale) if self.shader: root.setShader(self.shader) # Generate it. terrain.generate() # root.flattenLight() if collision: col = collisionUtil.rebuildGeomNodesToColPolys(root, collision) col.setCollideMask(collisionUtil.groundMask) col.reparentTo(collision) return root
class WorldGen(ShowBase): # our 'class' def __init__(self): if __name__ == '__main__': ShowBase.__init__(self) # initialise self.initTerrain() self.initModels() self.initPositions() self.loadingStringParser(parameters["loadingString"]) # self.plotPosition() if self.evenLoad: self.evenInstance(self.evenObj, scale=self.evenScale, tex=self.evenTex, z=self.evenZ) if self.oddLoad: self.oddInstance(self.oddObj, scale=self.oddScale, tex=self.oddTex, z=self.oddZ) # print " \n \n \n Generate is about to exit \n \n \n" self.generate() # print "kill is ", parameters["killWorldGen"] # parameters["killWorldGen"]=False if parameters["killWorldGen"]: import sys print " \n \n \n World Generate is about to exit \n \n \n" sys.exit() def initTerrain(self): self.terrain = GeoMipTerrain("worldTerrain") # create a self.terrain self.terrain.setHeightfield( parameters["modelHeightMap"]) # set the height map if parameters[ "loadNullModels"]: #if null, then create uniform back and sky self.terrain.setColorMap( parameters["modelTextureMapNull"]) # set the colour map else: self.terrain.setColorMap( parameters["modelTextureMap"]) # set the colour map self.terrain.setBruteforce(True) # level of detail self.root = self.terrain.getRoot() # capture root self.root.reparentTo(self.render) # render from root self.root.setSz(0.2) # maximum height self.terrain.generate() # generate def initModels(self): self.tree = self.loader.loadModel(parameters["treePath"]) self.greenSphere = self.loader.loadModel(parameters["spherePath"]) self.redSphere = self.loader.loadModel(parameters["spherePath"]) self.treeTex = self.loader.loadTexture(parameters["treeTexPath"]) self.greenTex = self.loader.loadTexture(parameters["greenTexPath"]) self.redTex = self.loader.loadTexture(parameters["redTexPath"]) def initPositions(self): self.evenObj = self.oddObj = self.evenScale = self.oddScale = \ self.evenTex = self.oddTex = self.evenLoad = self.oddLoad =self.evenZ=self.oddZ= \ self.evenPlotColor=self.oddPlotColor=self.evenPlotMarker=self.oddPlotMarker=None if parameters["hcp"]: self.odd, self.even = self.hcpListGenerator( heightObjects=parameters["heightObjects"], widthObjects=parameters["widthObjects"], lattice=parameters["lattice"]) elif parameters["quad"]: self.odd, self.even = self.quadPositionGenerator() # print "odd is",self.odd # print "even is ", self.even def hcpListGenerator(self, heightObjects, widthObjects, lattice): self.posList = np.zeros([heightObjects * widthObjects, 2]) self.alternate = False index = 0 for i in range(0, heightObjects): y = i * lattice * (3**0.5) / 2 self.alternate = not self.alternate for j in range(0, widthObjects): if self.alternate: x = j * lattice + (lattice / 2) else: x = j * lattice self.posList[index, :] = [x, y] index += 1 # self.posList[:,0]=np.linspace(0,100,num=(self.posList.shape)[0]) # self.posList[:,1]=np.linspace(0,100,num=(self.posList.shape)[0]) self.oddPosList = self.posList[1::2] self.evenPosList = self.posList[0::2] # print "odd is ",self.oddPosList # print "even is", self.evenPosList return self.oddPosList, self.evenPosList def quadPositionGenerator(self): offset = ((int(parameters["worldSize"]) - 1) / 2) + 1 quad3PosL = parameters["posL"] quad3PosR = parameters["posR"] quad4PosL = (parameters["posL"][0] + offset, parameters["posL"][1]) quad4PosR = (parameters["posR"][0] + offset, parameters["posR"][1]) quad2PosL = (parameters["posL"][0], parameters["posL"][1] + offset) quad2PosR = (parameters["posR"][0], parameters["posR"][1] + offset) quad1PosL = (parameters["posL"][0] + offset, parameters["posL"][1] + offset) quad1PosR = (parameters["posR"][0] + offset, parameters["posR"][1] + offset) #identical visual stim # odd=np.array([quad1PosR,quad2PosR,quad3PosR,quad4PosR]) # even=np.array([quad1PosL,quad2PosL,quad3PosL,quad4PosL]) odd = np.array([quad1PosR, quad2PosL, quad3PosL, quad3PosR]) even = np.array([quad1PosL, quad2PosR, quad4PosL, quad4PosR]) # print offset # print "even is ",odd # print "even is ", even return odd, even def loadingStringParser(self, loadingString): """ Args: loadingString:2 letter string, r - red sphere g - green sphere t - tree 0 - None 1st letter is even instance 2nd letter is odd instance Returns: """ if len(loadingString) > 2: print "only 2 objects in world" j = 0 for i in loadingString: if i == "t": obj = self.tree tex = self.treeTex scale = parameters["treeScale"] z = parameters["treeZ"] plotColor = "k" plotMarker = "s" load = True elif i == "r": obj = self.redSphere tex = self.redTex scale = parameters["sphereScale"] z = parameters["sphereZ"] plotColor = "r" plotMarker = "o" load = True elif i == "g": obj = self.greenSphere tex = self.greenTex scale = parameters["sphereScale"] z = parameters["sphereZ"] plotColor = "g" plotMarker = "o" load = True else: obj = None tex = None scale = None z = None plotColor = None plotMarker = None load = False if j == 0: self.evenObj = obj self.evenTex = tex self.evenScale = scale self.evenZ = z self.evenPlotColor = plotColor self.evenPlotMarker = plotMarker self.evenLoad = load else: self.oddObj = obj self.oddTex = tex self.oddScale = scale self.oddZ = z self.oddPlotColor = plotColor self.oddPlotMarker = plotMarker self.oddLoad = load j += 1 def oddInstance(self, dummy, scale, tex, z): dummy.setPos(tuple(parameters["origin"])) dummy.setScale(scale) dummy.setTexture(tex) for i in range(self.odd.shape[0]): self.oddPlaceholder = self.render.attach_new_node("odd Holder") self.oddPlaceholder.setPos(self.odd[i][0], self.odd[i][1], z) dummy.instanceTo(self.oddPlaceholder) def evenInstance(self, dummy, scale, tex, z): dummy.setPos(tuple(parameters["origin"])) dummy.setScale(scale) dummy.setTexture(tex) for i in range(self.even.shape[0]): evenPlaceholder = self.render.attach_new_node("even Holder") evenPlaceholder.setPos(self.even[i][0], self.even[i][1], z) dummy.instanceTo(evenPlaceholder) def plotPositions(self): self.tree = self.greenSphere = self.redSphere = self.treeTex = self.greenTex = self.redTex = None self.loadingStringParser(parameters["loadingString"]) plt.scatter(self.odd[:, 0], self.odd[:, 1], color=self.oddPlotColor, marker=self.oddPlotMarker, s=80) plt.scatter(self.even[:, 0], self.even[:, 1], color=self.evenPlotColor, marker=self.evenPlotMarker, s=80) #,marker='|',color='g') def worldNameGen(self): self.worldFilename = "models/world_" + "size:" + parameters["modelSizeSuffix"] \ + "_obj:" + parameters["loadingString"] + "_num:" \ + str(parameters["widthObjects"]) + "x" \ + str(parameters["heightObjects"])+"_lattice:"\ +str(parameters["lattice"]) + ".bam" print "world file name is ", self.worldFilename def generate(self): self.worldNameGen() self.render.writeBamFile(self.worldFilename)
def makeBlock(self,drawResourcesFactories,x,y,x1,y1,tileCenter,collision): drawResourcesFactory=drawResourcesFactories[self.LOD] tile=drawResourcesFactory.getTile() resources=drawResourcesFactory.getDrawResources(self.dataIndex[self.LOD]) # Set up the GeoMipTerrain terrain = GeoMipTerrain("TerrainTile") heightTex=tile.bakedTile.renderMaps[self.specialMaps["height"]].tex heightTexSize=heightTex.getXSize() pnmImage=PNMImage() #heightTex.makeRamImage() # Makes it run without having ran image in advance, but it all ends up flat. heightTex.store(pnmImage) terrain.setHeightfield(pnmImage) # Set terrain properties terrain.setBruteforce(True) # Store the root NodePath for convenience root = terrain.getRoot() root.setPos(tile.bakedTile.x-tileCenter.getX(),tile.bakedTile.y-tileCenter.getY(),0) for t in self.texList: texScale=1.0/(t[1]) root.setTexture(t[0],t[2]) root.setShaderInput('tex2D_'+t[3],t[2]) root.setTexScale(t[0],texScale*tile.tileScale) root.setTexOffset(t[0],(tile.getX() % t[1])*texScale,(tile.getY() % t[1])*texScale) for t in self.mapTexStages: tex=tile.bakedTile.renderMaps[t].tex root.setTexture(self.mapTexStages[t],tex) # Here we apply a transform to the textures so centers of the edge pixels fall on the edges of the tile # Normally the edges of the edge pixels would fall on the edges of the tiles. # The benifits of this should be visible, though they have not been varified sucessfully yet. # In fact, these transforms appear to not do anything. # This is troubling, but the problem they are supposed to fix is currently invisible as well. #size=tex.getXSize() #margin=bakery.texMargin(size) #tile.setTexOffset(t,-margin,-margin) #tile.setTexScale(t,float(size+margin*2)/size) root.setShaderInput("offset",tile.bakedTile.x,tile.bakedTile.y,0.0,0.0) root.setShaderInput("scale",tile.bakedTile.scale) xyScale=float(tile.tileScale)/(heightTexSize-1) root.setScale(xyScale,xyScale,self.heightScale) if self.shader: root.setShader(self.shader) # Generate it. terrain.generate() #root.flattenLight() if collision: col=collisionUtil.rebuildGeomNodesToColPolys(root,collision) col.setCollideMask(collisionUtil.groundMask) col.reparentTo(collision) return root
class SMWorld(DirectObject): #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Constructor # (Game state, Map name, Height of death plane) #------------------------------------------------------------------------------------------------------------------------------------------------------------ def __init__(self, mapID, tObj, aObj): self.mapID = mapID # EX: maps/map-1/map-1.yetimap metaFile = open( "../maps/map" + str(self.mapID) + "/map" + str(self.mapID) + ".yetimap", 'r') metaLines = metaFile.readlines() lineCount = len(metaLines) self.snowflakeCount = lineCount - 2 self.snowCount = 0 # First Line: Player's starting position # EX: 50,50,50 (NO SPACES) playerLine = metaLines[0] playerPosList = playerLine.split(",") playerInitX = int(playerPosList[0]) playerInitY = int(playerPosList[1]) playerInitZ = int(playerPosList[2]) self.playerStart = Point3(playerInitX, playerInitY, playerInitZ) # 2nd Line: Deathzone Height # ONE INTEGER self.deathHeight = int(metaLines[1]) # Get dem snowflakes self.snowflakePositions = [] print("Snowflake Count: " + str(self.snowflakeCount)) for i in xrange(0, self.snowflakeCount): sfline = metaLines[i + 2] sfList = sfline.split(",") sfx = int(sfList[0]) sfy = int(sfList[1]) sfz = int(sfList[2]) self.snowflakePositions.append(Point3(sfx, sfy, sfz)) print("New snowflake to add: (" + str(sfx) + "," + str(sfy) + "," + str(sfz) + ")") #load in controls ctrlFl = open("ctrConfig.txt") #will skip n lines where [n,] #makes a list of controls self.keymap = eval(ctrlFl.read()) #close file ctrlFl.close() # Create new instances of our various objects self.mapName = str(mapID) self.audioMgr = aObj self.worldObj = self.setupWorld() self.heightMap = self.setupHeightmap(self.mapName) self.deathZone = self.setupDeathzone(self.deathHeight) self.debugNode = self.setupDebug() # Player Init self.playerObj = SMPlayer(self.worldBullet, self.worldObj, self, self.playerStart, self.audioMgr) self.playerNP = self.playerObj.getNodePath() self.playerNP.setH(180) self.canUseShift = True self.canAirDash = True # Snowball Init self.ballObj = SMBall(self.worldBullet, self.worldObj, self.playerObj, self.playerNP) self.sbCollideFlag = False self.ballNP = self.ballObj.getNodePath() # Key Handler self.kh = SMKeyHandler() self.lastMousePos = self.kh.getMouse() # Collision Handler self.colObj = self.setupCollisionHandler() # Lighting self.ligObj = SMLighting(Vec4(.4, .4, .4, 1), Vec3(-5, -5, -5), Vec4(2.0, 2.0, 2.0, 1.0)) # Camera self.camObj = SMCamera(self.playerObj, self.worldBullet, self.worldObj) self.cameraControl = False # GUI self.GUI = SMGUI() self.snowflakeCounter = SMGUICounter( "snowflake", self.snowflakeCount) # Replace 3 with # of snowflakes in level. self.snowMeter = SMGUIMeter(100) self.GUI.addElement("snowflake", self.snowflakeCounter) self.GUI.addElement("snowMeter", self.snowMeter) #Snowy Outside # base.enableParticles() # self.p = ParticleEffect() # self.p.cleanup() # self.p = ParticleEffect() # self.p.loadConfig('snow.ptf') # self.p.start(self.camObj.getNodePath()) # self.p.setPos(0.00, 0.500, 0.000) # AI # self.goat1 = SMAI("../res/models/goat.egg", 75.0, self.worldBullet, self.worldObj, -70, -95, 5) # self.goat1.setBehavior("flee", self.playerNP) # self.goat2 = SMAI("../res/models/goat.egg", 75.0, self.worldBullet, self.worldObj, -80, -83, 5) # self.goat2.setBehavior("flee", self.playerNP) # print("AI Initialized") # Debug Text self.textObj = tObj self.textObj.addText("yetiPos", "Position: ") self.textObj.addText("yetiVel", "Velocity: ") self.textObj.addText("yetiFric", "Friction: ") self.textObj.addText("onIce", "Ice(%): ") self.textObj.addText("onSnow", "Snow(%): ") self.textObj.addText("terrHeight", "T Height: ") self.textObj.addText("terrSteepness", "Steepness: ") # Pause screen transition self.transition = Transitions(loader) # Method-based keybindings # self.accept('b', self.spawnBall) self.accept('escape', base.userExit) self.accept('enter', self.pauseUnpause) self.accept('f1', self.toggleDebug) self.accept('lshift-up', self.enableShiftActions) self.accept('mouse1', self.enableCameraControl) self.accept('mouse1-up', self.disableCameraControl) self.accept('wheel_up', self.camObj.zoomIn) self.accept('wheel_down', self.camObj.zoomOut) self.pauseUnpause() # Disable the mouse base.disableMouse() props = WindowProperties() props.setCursorHidden(True) base.win.requestProperties(props) # Uncomment this to see everything being rendered. self.printSceneGraph() # Play the BGM self.audioMgr.playBGM("snowmanWind") # Skybox formed skybox = loader.loadModel("../res/models/skybox.egg") # skybox.set_two_sided(true) skybox.setScale(500) skybox.setPos(0, 0, -450) skybox.reparentTo(render) mountain = loader.loadModel("../res/models/mountain.egg") mountain.reparentTo(render) mountain.setPos(650, 800, 20) mountain.setScale(120) self.colObjects = [] self.caveNew = SMCollide("../res/models/cave_new.egg", self.worldBullet, self.worldObj, Point3(-50, 95, -13), 11, Vec3(0, 0, 0)) self.colObjects.append(self.caveNew) self.planeFront = SMCollide("../res/models/plane_front", self.worldBullet, self.worldObj, Point3(190, -100, -15), 8, Vec3(190, 0, 30)) self.colObjects.append(self.planeFront) self.caveModel = SMCollide("../res/models/cave_tunnel.egg", self.worldBullet, self.worldObj, Point3(233, 68, 32), 4, Vec3(135, 180, 0)) self.colObjects.append(self.caveModel) self.planeTail = SMCollide("../res/models/plane_tail.egg", self.worldBullet, self.worldObj, Point3(-40, -130, -7), 10, Vec3(230, 0, 0)) self.colObjects.append(self.planeTail) self.ropeBridge = SMCollide("../res/models/rope_bridge.egg", self.worldBullet, self.worldObj, Point3(180, 115, 30), 6, Vec3(50, 0, 0)) self.colObjects.append(self.ropeBridge) self.colObjectCount = len(self.colObjects) print("World initialized.") #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Enables the camera to be rotated by moving the mouse horizontally. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def enableCameraControl(self): self.cameraControl = True #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Disables the camera control. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def disableCameraControl(self): self.cameraControl = False #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Enables the use of shift actions again. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def enableShiftActions(self): self.canUseShift = True def disableShiftActions(self): self.canUseShift = False #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Respawns the yeti's snowball. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def spawnBall(self): if (not (self.playerObj.getAirborneFlag())): self.ballObj.respawn() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Toggles the pause screen #------------------------------------------------------------------------------------------------------------------------------------------------------------ def pauseUnpause(self): if taskMgr.hasTaskNamed('UpdateTask'): taskMgr.remove('UpdateTask') self.transition.fadeScreen(0.5) else: taskMgr.add(self.update, 'UpdateTask') self.transition.noFade() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Sets up the world and returns a NodePath of the BulletWorld #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupWorld(self): self.worldBullet = BulletWorld() self.worldBullet.setGravity(Vec3(0, 0, -GRAVITY)) self.terrSteepness = -1 wNP = render.attachNewNode('WorldNode') self.audioMgr.loadSFX("snowCrunch01") self.audioMgr.loadBGM("snowmanWind") return wNP #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Prints all nodes that are a child of render. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def printSceneGraph(self): print(render.ls()) #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Initializes and returns a DebugNode NodePath. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupDebug(self): debug = BulletDebugNode() debug.showWireframe( False ) # Yeah, don't set this to true unless you want to emulate an 80's computer running Crysis on Ultra settings. debug.showConstraints(True) debug.showBoundingBoxes(True) # This is the main use I have for it. debug.showNormals(True) debugNP = render.attachNewNode(debug) self.worldBullet.setDebugNode(debugNP.node()) debugNP.hide() return debugNP #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Initializes and returns a BulletRigidBodyNode of the terrain, which loads the map with the specified name. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupHeightmap(self, name): # Automatically generate a heightmap mesh from a monochrome image. self.hmHeight = 120 hmPath = "../maps/map" + name + "/map" + name + "-h.png" imPath = "../maps/map" + name + "/map" + name + "-i.png" smPath = "../maps/map" + name + "/map" + name + "-s.png" scmPath = "../maps/map" + name + "/map" + name + "-sc.png" print(hmPath) print(imPath) print(smPath) print(scmPath) hmImg = PNMImage(Filename(hmPath)) hmShape = BulletHeightfieldShape(hmImg, self.hmHeight, ZUp) hmNode = BulletRigidBodyNode('Terrain') hmNode.addShape(hmShape) hmNode.setMass(0) self.hmNP = render.attachNewNode(hmNode) self.worldBullet.attachRigidBody(hmNode) self.hmOffset = hmImg.getXSize() / 2.0 - 0.5 self.hmTerrain = GeoMipTerrain('gmTerrain') self.hmTerrain.setHeightfield(hmImg) # Optimizations and fixes self.hmTerrain.setBruteforce( True) # I don't think this is actually needed. self.hmTerrain.setMinLevel(3) # THIS is what triangulates the terrain. self.hmTerrain.setBlockSize( 128) # This does a pretty good job of raising FPS. # Level-of-detail (not yet working) # self.hmTerrain.setNear(40) # self.hmTerrain.setFar(200) self.hmTerrain.generate() self.hmTerrainNP = self.hmTerrain.getRoot() self.hmTerrainNP.setSz(self.hmHeight) self.hmTerrainNP.setPos(-self.hmOffset, -self.hmOffset, -self.hmHeight / 2.0) self.hmTerrainNP.flattenStrong( ) # This only reduces the number of nodes; nothing to do with polys. self.hmTerrainNP.analyze() # Here begins the scenery mapping treeModel = loader.loadModel("../res/models/tree_1.egg") rockModel = loader.loadModel("../res/models/rock_1.egg") rock2Model = loader.loadModel("../res/models/rock_2.egg") rock3Model = loader.loadModel("../res/models/rock_3.egg") # caveModel = loader.loadModel("../res/models/cave_new.egg") # planeFrontModel = loader.loadModel("../res/models/plane_front.egg") # planeWingModel = loader.loadModel("../res/models/plane_wing.egg") texpk = loader.loadTexture(scmPath).peek() # GameObject nodepath for flattening self.objNP = render.attachNewNode("gameObjects") self.treeNP = self.objNP.attachNewNode("goTrees") self.rockNP = self.objNP.attachNewNode("goRocks") self.rock2NP = self.objNP.attachNewNode("goRocks2") self.rock3NP = self.objNP.attachNewNode("goRocks3") # self.caveNP = self.objNP.attachNewNode("goCave") # self.planeFrontNP = self.objNP.attachNewNode("goPlaneFront") # self.planeWingNP = self.objNP.attachNewNode("goPlaneWing") for i in range(0, texpk.getXSize()): for j in range(0, texpk.getYSize()): color = VBase4(0, 0, 0, 0) texpk.lookup(color, float(i) / texpk.getXSize(), float(j) / texpk.getYSize()) if (int(color.getX() * 255.0) == 255.0): newTree = self.treeNP.attachNewNode("treeNode") treeModel.instanceTo(newTree) newTree.setPos( i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newTree.setScale(randint(0,4)) newTree.setScale(2) if (int(color.getX() * 255.0) == 128): newRock = self.rockNP.attachNewNode("newRock") newRock.setPos( i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rockModel.instanceTo(newRock) if (int(color.getX() * 255.0) == 77): newRock2 = self.rock2NP.attachNewNode("newRock2") newRock2.setPos( i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rock2Model.instanceTo(newRock2) if (int(color.getX() * 255.0) == 102): newRock3 = self.rock3NP.attachNewNode("newRock3") newRock3.setPos( i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rock3Model.instanceTo(newRock3) # if(int(color.getX() * 255.0) == 64): # newCave = self.caveNP.attachNewNode("newCave") # newCave.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newCave.setScale(5) # newCave.setP(180) # caveModel.instanceTo(newCave) # if(int(color.getX() * 255.0) == 191): # newPlaneFront = self.planeFrontNP.attachNewNode("newPlaneFront") # newPlaneFront.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newPlaneFront.setScale(6) # planeFrontModel.instanceTo(newPlaneFront) # if(int(color.getX() * 255.0) == 179): # newPlaneWing = self.planeWingNP.attachNewNode("newPlaneWing") # newPlaneWing.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newPlaneWing.setScale(6) # newPlaneWing.setH(250) # newPlaneWing.setR(180) # newPlaneWing.setP(135) # planeWingModel.instanceTo(newPlaneWing) self.snowflakes = [] for i in xrange(0, self.snowflakeCount): print("Call " + str(i)) sf = SMCollect(self.worldBullet, self.worldObj, self.snowflakePositions[i]) self.snowflakes.append(sf) # render.flattenStrong() self.hmTerrainNP.reparentTo(render) # Here begins the attribute mapping ts = TextureStage("stage-alpha") ts.setSort(0) ts.setPriority(1) ts.setMode(TextureStage.MReplace) ts.setSavedResult(True) self.hmTerrainNP.setTexture(ts, loader.loadTexture(imPath, smPath)) ts = TextureStage("stage-stone") ts.setSort(1) ts.setPriority(1) ts.setMode(TextureStage.MReplace) self.hmTerrainNP.setTexture( ts, loader.loadTexture("../res/textures/stone_tex.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) ts = TextureStage("stage-ice") ts.setSort(2) ts.setPriority(1) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor) self.hmTerrainNP.setTexture( ts, loader.loadTexture("../res/textures/ice_tex.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) ts = TextureStage("stage-snow") ts.setSort(3) ts.setPriority(0) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcAlpha) self.hmTerrainNP.setTexture( ts, loader.loadTexture("../res/textures/snow_tex_1.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) # print(self.snowflakes) return hmNode #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Sets up and returns the death zone plane (returns its NodePath) with the specified height. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupDeathzone(self, height): planeShape = BulletPlaneShape(Vec3(0, 0, 1), 1) planeNode = BulletRigidBodyNode('DeathZone') planeNode.addShape(planeShape) planeNP = render.attachNewNode(planeNode) planeNP.setPos(0, 0, height) self.worldBullet.attachRigidBody(planeNode) return planeNP #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Sets up and returns the collision handler. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupCollisionHandler(self): colHand = SMCollisionHandler(self.worldBullet) return colHand #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Toggles showing bounding boxes. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def toggleDebug(self): if self.debugNode.isHidden(): self.debugNode.show() else: self.debugNode.hide() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Returns the terrain height of the nearest vertical descending raycast from the passed Point3. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def getTerrainHeight(self, pos): result = 0 x = pos.getX() y = pos.getY() z = pos.getZ() rayTerrA = Point3(x, y, z) rayTerrB = Point3(x, y, z - 256) rayTest = self.worldBullet.rayTestClosest(rayTerrA, rayTerrB) rayNode = rayTest.getNode() if (rayTest.hasHit()): rayPos = rayTest.getHitPos() result = rayPos.getZ() else: self.playerObj.respawn() return result # return self.hmTerrain.get_elevation(x + self.hmOffset, y + self.hmOffset) * self.hmHeight #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Handles player movement #------------------------------------------------------------------------------------------------------------------------------------------------------------ def playerMove(self): # Go through the collision and flag tests, and update them self.doPlayerTests() # Rotation and camera movement if self.kh.poll(self.keymap['Left']): self.playerObj.turn(True) elif self.kh.poll(self.keymap['Right']): self.playerObj.turn(False) elif (self.cameraControl): newMousePos = self.kh.getMouse() mx = newMousePos.getX() self.camObj.rotateCamera(mx) self.camObj.calculatePosition() # Movement if self.kh.poll(self.keymap['Forward']): self.playerObj.move(True) self.camObj.rotateTowards(90) elif self.kh.poll(self.keymap['Back']): self.playerObj.move(False) else: self.playerObj.stop() # Jump if (self.kh.poll(self.keymap['Space']) and self.terrSteepness < 0.25): #and not(self.ballObj.isRolling())): self.playerObj.jump() else: self.playerObj.resetJump() # Air Dash if ( self.kh.poll(self.keymap['airDash']) ): #and self.playerObj.getAirborneFlag() == True and self.canAirDash == True): self.canAirDash = False self.playerObj.airDash() # Shift-based actions if (self.kh.poll("lshift") and not (self.sbCollideFlag) and not (self.playerObj.getAirborneFlag()) and self.canUseShift): # If there's another snowball already placed if (self.ballObj.exists() and not (self.ballObj.isRolling())): self.ballObj.respawn() # If we're rolling a snowball elif (self.ballObj.isRolling()): # Absorb snowball if (self.kh.poll("v")): self.canUseShift = False snowAmt = self.ballObj.getSnowAmount() self.playerObj.addSnow(snowAmt) # self.snowMeter.fillBy(snowAmt) self.ballObj.destroy() # Go to iceball throwing mode elif (self.kh.poll("b")): print("TODO: Ice ball throwing mode.") # Grow the snowball elif (self.kh.poll("w")): self.ballObj.grow() # Spawn a new snowball elif (self.ballObj.exists() == False): self.ballObj.respawn() # If the player is not pressing shift else: if (self.ballObj.isRolling()): self.ballObj.dropBall() base.win.movePointer(0, 400, 300) # So updating the stats is VERY expensive. if (self.debugNode.isHidden() == False): self.updateStats() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Various tests concerning the player flags and collisions. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def doPlayerTests(self): # Player's position plPos = self.playerObj.getPosition() px = plPos.getX() py = plPos.getY() pz = plPos.getZ() # Raycast directly down for terrain steepness rayYetiA = Point3(px, py, pz) rayYetiB = Point3(px, py, pz - 300) self.downRayTest = self.worldBullet.rayTestClosest( rayYetiA, rayYetiB).getHitNormal() rx = self.downRayTest.getX() ry = self.downRayTest.getY() rz = self.downRayTest.getZ() self.terrSteepness = 1.0 - rz # Redo collision flags later objCollisionFlag = False # Snow/Ice height adjust self.playerObj.updateTerrain() # Collision: Player x Objects for i in xrange(0, self.colObjectCount): if (self.colObj.didCollide(self.playerNP.node(), self.colObjects[i].AINode)): objCollisionFlag = True self.playerObj.setAirborneFlag(False) self.canAirDash = True self.playerObj.setFactor(1, 1, 1) # Collision: Player x Snowball if (self.ballObj.exists() and self.colObj.didCollide( self.playerNP.node(), self.ballObj.getRigidbody())): self.sbCollideFlag = True self.playerObj.setAirborneFlag(False) self.playerObj.setFactor(1, 1, 1) else: self.sbCollideFlag = False # Collision: Player x Terrain if (self.colObj.didCollide(self.playerNP.node(), self.heightMap)): if (self.playerObj.getAirborneFlag()): self.audioMgr.playSFX("snowCrunch01") self.playerObj.setAirborneFlag(False) self.canAirDash = True self.playerObj.setFactor(1, 1, 1) objCollisionFlag = False # Collision: Player x Death Zone # if(pz - 7 <= self.deathHeight or (self.colObj.didCollide(self.playerNP.node(), self.deathZone.node()))): if (self.colObj.didCollide(self.playerNP.node(), self.deathZone.node())): print("Player confirmed #REKT") self.playerObj.respawn() # Out of bounds checking if (abs(px) > 254 or abs(py) > 254): print("Player out of bounds!") self.playerObj.respawn() # Snap to terrain if... something. I need to restructure this. Don't read it. if (not (self.playerObj.getAirborneFlag()) and not (self.sbCollideFlag) and not (objCollisionFlag)): z = self.getTerrainHeight(Point3(px, py, pz)) self.playerObj.snapToTerrain(z) # self.playerObj.snapToTerrain(th, self.hmHeight) # Collision: Player x Snowflakes for i in xrange(0, self.snowflakeCount): if (self.snowflakes[i].exists() and self.colObj.didCollide( self.playerNP.node(), self.snowflakes[i].getNode())): self.snowflakes[i].destroy() self.snowflakeCounter.increment() self.snowCount += 1 self.snowMeter.updateSnow(self.playerObj) #Check if there is a "next" level. If there is, load it. Otherwise display end game screen. if (self.snowCount >= self.snowflakeCount): file_path = "../maps/map" + str(self.mapID + 1) + "/map" + str(self.mapID + 1) + ".yetimap" if os.path.lexists(file_path): self.snowCount = 0 self.snowflakeCount = 0 self.snowflakeCounter.setValue(0) self.snowflakeCounter.setState(2) #Loading Screen self.transition.fadeScreen(0.7) self.loadingText = OnscreenText("Loading...", 1, fg=(1, 1, 1, 0), pos=(0, 0), align=TextNode.ACenter, scale=.07, mayChange=1) base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() self.transition.noFade() #destroy objects self.worldBullet.removeRigidBody(self.heightMap) self.hmTerrainNP.removeNode() self.objNP.removeNode() self.treeNP.removeNode() self.rockNP.removeNode() self.rock2NP.removeNode() self.rock3NP.removeNode() # self.caveNP.removeNode() # self.planeFrontNP.removeNode() # self.planeWingNP.removeNode() self.hmNP.removeNode() if (int(self.mapID) == 1): self.ropeBridge.AIChar.setPos(-200, -300, -200) # self.ropeBridge.AIChar.removeNode() self.planeFront.AIChar.removeNode() self.planeTail.AIChar.setPos(-200, -200, -200) # self.planeTail.AIChar.removeNode() self.caveNew.AIChar.setPos(-1000, -1000, -1000) self.caveModel.AIChar.removeNode() #Added More Props here! self.boulder = SMCollide("../res/models/rock_3.egg", self.worldBullet, self.worldObj, Point3(117, 123, 17), 15, Vec3(0, 0, 0)) elif (int(self.mapID) == 2): self.boulder.AIChar.setPos(-222, -222, -222) self.caveNew.AIChar.setScale(150) self.caveNew.AIChar.setPos(-50, 95, -50) # self.skybox.setScale(600) # self.caveNew.setH(0) # self.boulder.removeNode() self.mapID += 1 print self.mapID # EX: maps/map-1/map-1.yetimap metaFile = open( "../maps/map" + str(self.mapID) + "/map" + str(self.mapID) + ".yetimap", 'r') metaLines = metaFile.readlines() lineCount = len(metaLines) self.snowflakeCount = lineCount - 2 # First Line: Player's starting position # EX: 50,50,50 (NO SPACES) playerLine = metaLines[0] playerPosList = playerLine.split(",") playerInitX = int(playerPosList[0]) playerInitY = int(playerPosList[1]) playerInitZ = int(playerPosList[2]) self.playerObj.playerNP.setPos(playerInitX, playerInitY, playerInitZ) self.playerObj.startX = playerInitX self.playerObj.startY = playerInitY self.playerObj.startZ = playerInitZ # 2nd Line: Deathzone Height # ONE INTEGER self.deathHeight = int(metaLines[1]) self.snowflakePositions = [] print("Snowflake Count: " + str(self.snowflakeCount)) for i in xrange(0, self.snowflakeCount): sfline = metaLines[i + 2] sfList = sfline.split(",") sfx = int(sfList[0]) sfy = int(sfList[1]) sfz = int(sfList[2]) self.snowflakePositions.append(Point3(sfx, sfy, sfz)) print("New snowflake to add: (" + str(sfx) + "," + str(sfy) + "," + str(sfz) + ")") self.snowflakeCounter.setMaxValue(self.snowflakeCount) #load new map self.mapName = str(self.mapID) self.heightMap = self.setupHeightmap(self.mapName) self.deathZone = self.setupDeathzone(self.deathHeight) self.loadingText.cleanup() else: taskMgr.remove('UpdateTask') self.endImage = OnscreenImage( image="../res/icons/endgame1.png", pos=(0.0, 0.0, 0.0), scale=(1.35, 2, 1)) #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Update the debug text. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def updateStats(self): pos = self.playerObj.getPosition() x = pos.getX() y = pos.getY() z = pos.getZ() vel = self.playerObj.getVelocity() vx = str(round(vel.getX(), 1)) vy = str(round(vel.getY(), 1)) vz = str(round(vel.getZ(), 1)) sx = str(round(x, 1)) sy = str(round(y, 1)) sz = str(round(z, 1)) rx = str(round(self.downRayTest.getX(), 2)) ry = str(round(self.downRayTest.getY(), 2)) rz = str(round(self.terrSteepness, 2)) fric = str(round(self.playerObj.getFriction(), 2)) ip = str(round(self.playerObj.getIceCoefficient(), 2)) sp = str(round(self.playerObj.getSnowCoefficient(), 2)) tHeight = str(round(self.getTerrainHeight(Point3(x, y, z)), 1)) self.textObj.editText("yetiPos", "Position: (" + sx + ", " + sy + ", " + sz + ")") self.textObj.editText("yetiVel", "Velocity: (" + vx + ", " + vy + ", " + vz + ")") self.textObj.editText("yetiFric", "Friction: " + fric) self.textObj.editText("onIce", "Ice(%): " + ip) self.textObj.editText("onSnow", "Snow(%): " + sp) self.textObj.editText("terrHeight", "T Height: " + tHeight) self.textObj.editText("terrSteepness", "Steepness: " + rz) #------------------------------------------------------------------------------------------------------------------------------------------------------------ # throw Snowball #------------------------------------------------------------------------------------------------------------------------------------------------------------ def throw(self): self.throwing = True size = self.ballObj.getSize() #zoom camera and grab pos you wish to throw self.camObj.aimMode() taskMgr.add(self.controlCamera, "camera-task") rotation = self.camObj.getH() pitch = self.camObj.getP() self.ballObj.throwBall(size, pitch, rotation) #fix camera #self.throwing = False #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Update the world. Called every frame. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def update(self, task): dt = globalClock.getDt() self.worldBullet.doPhysics(dt) # self.goat1.AIUpdate() # self.goat2.AIUpdate() self.playerMove() return task.cont
class SMWorld(DirectObject): #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Constructor # (Game state, Map name, Height of death plane) #------------------------------------------------------------------------------------------------------------------------------------------------------------ def __init__(self, mapID, tObj, aObj): self.mapID = mapID # EX: maps/map-1/map-1.yetimap metaFile = open("../maps/map" + str(self.mapID) + "/map" + str(self.mapID) + ".yetimap", 'r') metaLines = metaFile.readlines() lineCount = len(metaLines) self.snowflakeCount = lineCount - 2 self.snowCount = 0 # First Line: Player's starting position # EX: 50,50,50 (NO SPACES) playerLine = metaLines[0] playerPosList = playerLine.split(",") playerInitX = int(playerPosList[0]) playerInitY = int(playerPosList[1]) playerInitZ = int(playerPosList[2]) self.playerStart = Point3(playerInitX, playerInitY, playerInitZ) # 2nd Line: Deathzone Height # ONE INTEGER self.deathHeight = int(metaLines[1]) # Get dem snowflakes self.snowflakePositions = [] print("Snowflake Count: " + str(self.snowflakeCount)) for i in xrange(0, self.snowflakeCount): sfline = metaLines[i+2] sfList = sfline.split(",") sfx = int(sfList[0]) sfy = int(sfList[1]) sfz = int(sfList[2]) self.snowflakePositions.append(Point3(sfx, sfy, sfz)) print("New snowflake to add: (" + str(sfx) + "," + str(sfy) + "," + str(sfz) + ")") #load in controls ctrlFl = open("ctrConfig.txt") #will skip n lines where [n,] #makes a list of controls self.keymap = eval(ctrlFl.read()) #close file ctrlFl.close() # Create new instances of our various objects self.mapName = str(mapID) self.audioMgr = aObj self.worldObj = self.setupWorld() self.heightMap = self.setupHeightmap(self.mapName) self.deathZone = self.setupDeathzone(self.deathHeight) self.debugNode = self.setupDebug() # Player Init self.playerObj = SMPlayer(self.worldBullet, self.worldObj, self, self.playerStart, self.audioMgr) self.playerNP = self.playerObj.getNodePath() self.playerNP.setH(180); self.canUseShift = True self.canAirDash = True # Snowball Init self.ballObj = SMBall(self.worldBullet, self.worldObj, self.playerObj, self.playerNP) self.sbCollideFlag = False self.ballNP = self.ballObj.getNodePath() # Key Handler self.kh = SMKeyHandler() self.lastMousePos = self.kh.getMouse() # Collision Handler self.colObj = self.setupCollisionHandler() # Lighting self.ligObj = SMLighting(Vec4(.4, .4, .4, 1), Vec3(-5, -5, -5), Vec4(2.0, 2.0, 2.0, 1.0)) # Camera self.camObj = SMCamera(self.playerObj, self.worldBullet, self.worldObj) self.cameraControl = False # GUI self.GUI = SMGUI() self.snowflakeCounter = SMGUICounter("snowflake", self.snowflakeCount) # Replace 3 with # of snowflakes in level. self.snowMeter = SMGUIMeter(100) self.GUI.addElement("snowflake", self.snowflakeCounter) self.GUI.addElement("snowMeter", self.snowMeter) #Snowy Outside # base.enableParticles() # self.p = ParticleEffect() # self.p.cleanup() # self.p = ParticleEffect() # self.p.loadConfig('snow.ptf') # self.p.start(self.camObj.getNodePath()) # self.p.setPos(0.00, 0.500, 0.000) # AI # self.goat1 = SMAI("../res/models/goat.egg", 75.0, self.worldBullet, self.worldObj, -70, -95, 5) # self.goat1.setBehavior("flee", self.playerNP) # self.goat2 = SMAI("../res/models/goat.egg", 75.0, self.worldBullet, self.worldObj, -80, -83, 5) # self.goat2.setBehavior("flee", self.playerNP) # print("AI Initialized") # Debug Text self.textObj = tObj self.textObj.addText("yetiPos", "Position: ") self.textObj.addText("yetiVel", "Velocity: ") self.textObj.addText("yetiFric", "Friction: ") self.textObj.addText("onIce", "Ice(%): ") self.textObj.addText("onSnow", "Snow(%): ") self.textObj.addText("terrHeight", "T Height: ") self.textObj.addText("terrSteepness", "Steepness: ") # Pause screen transition self.transition = Transitions(loader) # Method-based keybindings # self.accept('b', self.spawnBall) self.accept('escape', base.userExit) self.accept('enter', self.pauseUnpause) self.accept('f1', self.toggleDebug) self.accept('lshift-up', self.enableShiftActions) self.accept('mouse1', self.enableCameraControl) self.accept('mouse1-up', self.disableCameraControl) self.accept('wheel_up', self.camObj.zoomIn) self.accept('wheel_down', self.camObj.zoomOut) self.pauseUnpause() # Disable the mouse base.disableMouse() props = WindowProperties() props.setCursorHidden(True) base.win.requestProperties(props) # Uncomment this to see everything being rendered. self.printSceneGraph() # Play the BGM self.audioMgr.playBGM("snowmanWind") # Skybox formed skybox = loader.loadModel("../res/models/skybox.egg") # skybox.set_two_sided(true) skybox.setScale(500) skybox.setPos(0, 0, -450) skybox.reparentTo(render) mountain = loader.loadModel("../res/models/mountain.egg") mountain.reparentTo(render) mountain.setPos(650,800,20) mountain.setScale(120) self.colObjects = [] self.caveNew = SMCollide("../res/models/cave_new.egg", self.worldBullet, self.worldObj, Point3(-50, 95, -13), 11, Vec3(0,0,0)) self.colObjects.append(self.caveNew) self.planeFront = SMCollide("../res/models/plane_front", self.worldBullet, self.worldObj, Point3(190, -100, -15), 8, Vec3(190,0,30)) self.colObjects.append(self.planeFront) self.caveModel = SMCollide("../res/models/cave_tunnel.egg", self.worldBullet, self.worldObj, Point3(233, 68, 32), 4, Vec3(135,180,0)) self.colObjects.append(self.caveModel) self.planeTail = SMCollide("../res/models/plane_tail.egg", self.worldBullet, self.worldObj, Point3(-40, -130, -7), 10, Vec3(230,0,0)) self.colObjects.append(self.planeTail) self.ropeBridge = SMCollide("../res/models/rope_bridge.egg", self.worldBullet, self.worldObj, Point3(180, 115, 30), 6, Vec3(50,0,0)) self.colObjects.append(self.ropeBridge) self.colObjectCount = len(self.colObjects) print("World initialized.") #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Enables the camera to be rotated by moving the mouse horizontally. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def enableCameraControl(self): self.cameraControl = True #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Disables the camera control. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def disableCameraControl(self): self.cameraControl = False #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Enables the use of shift actions again. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def enableShiftActions(self): self.canUseShift = True def disableShiftActions(self): self.canUseShift = False #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Respawns the yeti's snowball. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def spawnBall(self): if(not(self.playerObj.getAirborneFlag())): self.ballObj.respawn() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Toggles the pause screen #------------------------------------------------------------------------------------------------------------------------------------------------------------ def pauseUnpause(self): if taskMgr.hasTaskNamed('UpdateTask'): taskMgr.remove('UpdateTask') self.transition.fadeScreen(0.5) else: taskMgr.add(self.update, 'UpdateTask') self.transition.noFade() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Sets up the world and returns a NodePath of the BulletWorld #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupWorld(self): self.worldBullet = BulletWorld() self.worldBullet.setGravity(Vec3(0, 0, -GRAVITY)) self.terrSteepness = -1 wNP = render.attachNewNode('WorldNode') self.audioMgr.loadSFX("snowCrunch01") self.audioMgr.loadBGM("snowmanWind") return wNP #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Prints all nodes that are a child of render. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def printSceneGraph(self): print(render.ls()) #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Initializes and returns a DebugNode NodePath. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupDebug(self): debug = BulletDebugNode() debug.showWireframe(False) # Yeah, don't set this to true unless you want to emulate an 80's computer running Crysis on Ultra settings. debug.showConstraints(True) debug.showBoundingBoxes(True) # This is the main use I have for it. debug.showNormals(True) debugNP = render.attachNewNode(debug) self.worldBullet.setDebugNode(debugNP.node()) debugNP.hide() return debugNP #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Initializes and returns a BulletRigidBodyNode of the terrain, which loads the map with the specified name. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupHeightmap(self, name): # Automatically generate a heightmap mesh from a monochrome image. self.hmHeight = 120 hmPath = "../maps/map" + name + "/map" + name + "-h.png" imPath = "../maps/map" + name + "/map" + name + "-i.png" smPath = "../maps/map" + name + "/map" + name + "-s.png" scmPath = "../maps/map" + name + "/map" + name + "-sc.png" print(hmPath) print(imPath) print(smPath) print(scmPath) hmImg = PNMImage(Filename(hmPath)) hmShape = BulletHeightfieldShape(hmImg, self.hmHeight, ZUp) hmNode = BulletRigidBodyNode('Terrain') hmNode.addShape(hmShape) hmNode.setMass(0) self.hmNP = render.attachNewNode(hmNode) self.worldBullet.attachRigidBody(hmNode) self.hmOffset = hmImg.getXSize() / 2.0 - 0.5 self.hmTerrain = GeoMipTerrain('gmTerrain') self.hmTerrain.setHeightfield(hmImg) # Optimizations and fixes self.hmTerrain.setBruteforce(True) # I don't think this is actually needed. self.hmTerrain.setMinLevel(3) # THIS is what triangulates the terrain. self.hmTerrain.setBlockSize(128) # This does a pretty good job of raising FPS. # Level-of-detail (not yet working) # self.hmTerrain.setNear(40) # self.hmTerrain.setFar(200) self.hmTerrain.generate() self.hmTerrainNP = self.hmTerrain.getRoot() self.hmTerrainNP.setSz(self.hmHeight) self.hmTerrainNP.setPos(-self.hmOffset, -self.hmOffset, -self.hmHeight / 2.0) self.hmTerrainNP.flattenStrong() # This only reduces the number of nodes; nothing to do with polys. self.hmTerrainNP.analyze() # Here begins the scenery mapping treeModel = loader.loadModel("../res/models/tree_1.egg") rockModel = loader.loadModel("../res/models/rock_1.egg") rock2Model = loader.loadModel("../res/models/rock_2.egg") rock3Model = loader.loadModel("../res/models/rock_3.egg") # caveModel = loader.loadModel("../res/models/cave_new.egg") # planeFrontModel = loader.loadModel("../res/models/plane_front.egg") # planeWingModel = loader.loadModel("../res/models/plane_wing.egg") texpk = loader.loadTexture(scmPath).peek() # GameObject nodepath for flattening self.objNP = render.attachNewNode("gameObjects") self.treeNP = self.objNP.attachNewNode("goTrees") self.rockNP = self.objNP.attachNewNode("goRocks") self.rock2NP = self.objNP.attachNewNode("goRocks2") self.rock3NP = self.objNP.attachNewNode("goRocks3") # self.caveNP = self.objNP.attachNewNode("goCave") # self.planeFrontNP = self.objNP.attachNewNode("goPlaneFront") # self.planeWingNP = self.objNP.attachNewNode("goPlaneWing") for i in range(0, texpk.getXSize()): for j in range(0, texpk.getYSize()): color = VBase4(0, 0, 0, 0) texpk.lookup(color, float(i) / texpk.getXSize(), float(j) / texpk.getYSize()) if(int(color.getX() * 255.0) == 255.0): newTree = self.treeNP.attachNewNode("treeNode") treeModel.instanceTo(newTree) newTree.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newTree.setScale(randint(0,4)) newTree.setScale(2) if(int(color.getX() * 255.0) == 128): newRock = self.rockNP.attachNewNode("newRock") newRock.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rockModel.instanceTo(newRock) if(int(color.getX() * 255.0) == 77): newRock2 = self.rock2NP.attachNewNode("newRock2") newRock2.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rock2Model.instanceTo(newRock2) if(int(color.getX() * 255.0) == 102): newRock3 = self.rock3NP.attachNewNode("newRock3") newRock3.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) rock3Model.instanceTo(newRock3) # if(int(color.getX() * 255.0) == 64): # newCave = self.caveNP.attachNewNode("newCave") # newCave.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newCave.setScale(5) # newCave.setP(180) # caveModel.instanceTo(newCave) # if(int(color.getX() * 255.0) == 191): # newPlaneFront = self.planeFrontNP.attachNewNode("newPlaneFront") # newPlaneFront.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newPlaneFront.setScale(6) # planeFrontModel.instanceTo(newPlaneFront) # if(int(color.getX() * 255.0) == 179): # newPlaneWing = self.planeWingNP.attachNewNode("newPlaneWing") # newPlaneWing.setPos(i - texpk.getXSize() / 2, j - texpk.getYSize() / 2, self.hmTerrain.get_elevation(i, j) * self.hmHeight - self.hmHeight / 2) # newPlaneWing.setScale(6) # newPlaneWing.setH(250) # newPlaneWing.setR(180) # newPlaneWing.setP(135) # planeWingModel.instanceTo(newPlaneWing) self.snowflakes = [] for i in xrange(0, self.snowflakeCount): print("Call " + str(i)) sf = SMCollect(self.worldBullet, self.worldObj, self.snowflakePositions[i]) self.snowflakes.append(sf) # render.flattenStrong() self.hmTerrainNP.reparentTo(render) # Here begins the attribute mapping ts = TextureStage("stage-alpha") ts.setSort(0) ts.setPriority(1) ts.setMode(TextureStage.MReplace) ts.setSavedResult(True) self.hmTerrainNP.setTexture(ts, loader.loadTexture(imPath, smPath)) ts = TextureStage("stage-stone") ts.setSort(1) ts.setPriority(1) ts.setMode(TextureStage.MReplace) self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/stone_tex.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) ts = TextureStage("stage-ice") ts.setSort(2) ts.setPriority(1) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcColor) self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/ice_tex.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) ts = TextureStage("stage-snow") ts.setSort(3) ts.setPriority(0) ts.setCombineRgb(TextureStage.CMInterpolate, TextureStage.CSTexture, TextureStage.COSrcColor, TextureStage.CSPrevious, TextureStage.COSrcColor, TextureStage.CSLastSavedResult, TextureStage.COSrcAlpha) self.hmTerrainNP.setTexture(ts, loader.loadTexture("../res/textures/snow_tex_1.png")) self.hmTerrainNP.setTexScale(ts, 32, 32) # print(self.snowflakes) return hmNode #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Sets up and returns the death zone plane (returns its NodePath) with the specified height. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupDeathzone(self, height): planeShape = BulletPlaneShape(Vec3(0, 0, 1), 1) planeNode = BulletRigidBodyNode('DeathZone') planeNode.addShape(planeShape) planeNP = render.attachNewNode(planeNode) planeNP.setPos(0, 0, height) self.worldBullet.attachRigidBody(planeNode) return planeNP #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Sets up and returns the collision handler. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def setupCollisionHandler(self): colHand = SMCollisionHandler(self.worldBullet) return colHand #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Toggles showing bounding boxes. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def toggleDebug(self): if self.debugNode.isHidden(): self.debugNode.show() else: self.debugNode.hide() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Returns the terrain height of the nearest vertical descending raycast from the passed Point3. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def getTerrainHeight(self, pos): result = 0 x = pos.getX() y = pos.getY() z = pos.getZ() rayTerrA = Point3(x, y, z) rayTerrB = Point3(x, y, z - 256) rayTest = self.worldBullet.rayTestClosest(rayTerrA, rayTerrB) rayNode = rayTest.getNode() if (rayTest.hasHit()): rayPos = rayTest.getHitPos() result = rayPos.getZ() else: self.playerObj.respawn() return result # return self.hmTerrain.get_elevation(x + self.hmOffset, y + self.hmOffset) * self.hmHeight #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Handles player movement #------------------------------------------------------------------------------------------------------------------------------------------------------------ def playerMove(self): # Go through the collision and flag tests, and update them self.doPlayerTests() # Rotation and camera movement if self.kh.poll(self.keymap['Left']): self.playerObj.turn(True) elif self.kh.poll(self.keymap['Right']): self.playerObj.turn(False) elif(self.cameraControl): newMousePos = self.kh.getMouse() mx = newMousePos.getX() self.camObj.rotateCamera(mx) self.camObj.calculatePosition() # Movement if self.kh.poll(self.keymap['Forward']): self.playerObj.move(True) self.camObj.rotateTowards(90) elif self.kh.poll(self.keymap['Back']): self.playerObj.move(False) else: self.playerObj.stop() # Jump if(self.kh.poll(self.keymap['Space']) and self.terrSteepness < 0.25): #and not(self.ballObj.isRolling())): self.playerObj.jump() else: self.playerObj.resetJump() # Air Dash if(self.kh.poll(self.keymap['airDash'])): #and self.playerObj.getAirborneFlag() == True and self.canAirDash == True): self.canAirDash = False self.playerObj.airDash() # Shift-based actions if(self.kh.poll("lshift") and not(self.sbCollideFlag) and not(self.playerObj.getAirborneFlag()) and self.canUseShift): # If there's another snowball already placed if(self.ballObj.exists() and not(self.ballObj.isRolling())): self.ballObj.respawn() # If we're rolling a snowball elif(self.ballObj.isRolling()): # Absorb snowball if(self.kh.poll("v")): self.canUseShift = False snowAmt = self.ballObj.getSnowAmount() self.playerObj.addSnow(snowAmt) # self.snowMeter.fillBy(snowAmt) self.ballObj.destroy() # Go to iceball throwing mode elif(self.kh.poll("b")): print("TODO: Ice ball throwing mode.") # Grow the snowball elif(self.kh.poll("w")): self.ballObj.grow() # Spawn a new snowball elif(self.ballObj.exists() == False): self.ballObj.respawn() # If the player is not pressing shift else: if(self.ballObj.isRolling()): self.ballObj.dropBall() base.win.movePointer(0, 400, 300) # So updating the stats is VERY expensive. if (self.debugNode.isHidden() == False): self.updateStats() #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Various tests concerning the player flags and collisions. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def doPlayerTests(self): # Player's position plPos = self.playerObj.getPosition() px = plPos.getX() py = plPos.getY() pz = plPos.getZ() # Raycast directly down for terrain steepness rayYetiA = Point3(px, py, pz) rayYetiB = Point3(px, py, pz - 300) self.downRayTest = self.worldBullet.rayTestClosest(rayYetiA, rayYetiB).getHitNormal() rx = self.downRayTest.getX() ry = self.downRayTest.getY() rz = self.downRayTest.getZ() self.terrSteepness = 1.0 - rz # Redo collision flags later objCollisionFlag = False # Snow/Ice height adjust self.playerObj.updateTerrain() # Collision: Player x Objects for i in xrange(0, self.colObjectCount): if(self.colObj.didCollide(self.playerNP.node(), self.colObjects[i].AINode)): objCollisionFlag = True self.playerObj.setAirborneFlag(False) self.canAirDash = True self.playerObj.setFactor(1,1,1) # Collision: Player x Snowball if(self.ballObj.exists() and self.colObj.didCollide(self.playerNP.node(), self.ballObj.getRigidbody())): self.sbCollideFlag = True self.playerObj.setAirborneFlag(False) self.playerObj.setFactor(1, 1, 1) else: self.sbCollideFlag = False # Collision: Player x Terrain if(self.colObj.didCollide(self.playerNP.node(), self.heightMap)): if(self.playerObj.getAirborneFlag()): self.audioMgr.playSFX("snowCrunch01") self.playerObj.setAirborneFlag(False) self.canAirDash = True self.playerObj.setFactor(1, 1, 1) objCollisionFlag = False # Collision: Player x Death Zone # if(pz - 7 <= self.deathHeight or (self.colObj.didCollide(self.playerNP.node(), self.deathZone.node()))): if(self.colObj.didCollide(self.playerNP.node(), self.deathZone.node())): print("Player confirmed #REKT") self.playerObj.respawn() # Out of bounds checking if(abs(px) > 254 or abs(py) > 254): print("Player out of bounds!") self.playerObj.respawn() # Snap to terrain if... something. I need to restructure this. Don't read it. if(not(self.playerObj.getAirborneFlag()) and not(self.sbCollideFlag) and not(objCollisionFlag)): z = self.getTerrainHeight(Point3(px, py, pz)) self.playerObj.snapToTerrain(z) # self.playerObj.snapToTerrain(th, self.hmHeight) # Collision: Player x Snowflakes for i in xrange(0, self.snowflakeCount): if(self.snowflakes[i].exists() and self.colObj.didCollide(self.playerNP.node(), self.snowflakes[i].getNode())): self.snowflakes[i].destroy() self.snowflakeCounter.increment() self.snowCount += 1 self.snowMeter.updateSnow(self.playerObj) #Check if there is a "next" level. If there is, load it. Otherwise display end game screen. if(self.snowCount >= self.snowflakeCount): file_path="../maps/map" + str(self.mapID+1) + "/map" + str(self.mapID+1) + ".yetimap" if os.path.lexists(file_path): self.snowCount = 0 self.snowflakeCount = 0 self.snowflakeCounter.setValue(0) self.snowflakeCounter.setState(2) #Loading Screen self.transition.fadeScreen(0.7) self.loadingText=OnscreenText("Loading...",1,fg=(1,1,1,0),pos=(0,0),align=TextNode.ACenter,scale=.07,mayChange=1) base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() base.graphicsEngine.renderFrame() self.transition.noFade() #destroy objects self.worldBullet.removeRigidBody(self.heightMap) self.hmTerrainNP.removeNode() self.objNP.removeNode() self.treeNP.removeNode() self.rockNP.removeNode() self.rock2NP.removeNode() self.rock3NP.removeNode() # self.caveNP.removeNode() # self.planeFrontNP.removeNode() # self.planeWingNP.removeNode() self.hmNP.removeNode() if(int(self.mapID) == 1): self.ropeBridge.AIChar.setPos(-200,-300,-200) # self.ropeBridge.AIChar.removeNode() self.planeFront.AIChar.removeNode() self.planeTail.AIChar.setPos(-200,-200,-200) # self.planeTail.AIChar.removeNode() self.caveNew.AIChar.setPos(-1000,-1000,-1000); self.caveModel.AIChar.removeNode() #Added More Props here! self.boulder = SMCollide("../res/models/rock_3.egg", self.worldBullet, self.worldObj, Point3(117, 123, 17), 15, Vec3(0,0,0)) elif(int(self.mapID) == 2): self.boulder.AIChar.setPos(-222,-222,-222) self.caveNew.AIChar.setScale(150) self.caveNew.AIChar.setPos(-50, 95, -50) # self.skybox.setScale(600) # self.caveNew.setH(0) # self.boulder.removeNode() self.mapID += 1 print self.mapID # EX: maps/map-1/map-1.yetimap metaFile = open("../maps/map" + str(self.mapID) + "/map" + str(self.mapID) + ".yetimap", 'r') metaLines = metaFile.readlines() lineCount = len(metaLines) self.snowflakeCount = lineCount - 2 # First Line: Player's starting position # EX: 50,50,50 (NO SPACES) playerLine = metaLines[0] playerPosList = playerLine.split(",") playerInitX = int(playerPosList[0]) playerInitY = int(playerPosList[1]) playerInitZ = int(playerPosList[2]) self.playerObj.playerNP.setPos(playerInitX, playerInitY, playerInitZ) self.playerObj.startX = playerInitX self.playerObj.startY = playerInitY self.playerObj.startZ = playerInitZ # 2nd Line: Deathzone Height # ONE INTEGER self.deathHeight = int(metaLines[1]) self.snowflakePositions = [] print("Snowflake Count: " + str(self.snowflakeCount)) for i in xrange(0, self.snowflakeCount): sfline = metaLines[i+2] sfList = sfline.split(",") sfx = int(sfList[0]) sfy = int(sfList[1]) sfz = int(sfList[2]) self.snowflakePositions.append(Point3(sfx, sfy, sfz)) print("New snowflake to add: (" + str(sfx) + "," + str(sfy) + "," + str(sfz) + ")") self.snowflakeCounter.setMaxValue(self.snowflakeCount) #load new map self.mapName = str(self.mapID) self.heightMap = self.setupHeightmap(self.mapName) self.deathZone = self.setupDeathzone(self.deathHeight) self.loadingText.cleanup() else: taskMgr.remove('UpdateTask') self.endImage=OnscreenImage(image = "../res/icons/endgame1.png", pos = (0.0, 0.0, 0.0), scale = (1.35, 2, 1)) #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Update the debug text. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def updateStats(self): pos = self.playerObj.getPosition() x = pos.getX() y = pos.getY() z = pos.getZ() vel = self.playerObj.getVelocity() vx = str(round(vel.getX(), 1)) vy = str(round(vel.getY(), 1)) vz = str(round(vel.getZ(), 1)) sx = str(round(x, 1)) sy = str(round(y, 1)) sz = str(round(z, 1)) rx = str(round(self.downRayTest.getX(), 2)) ry = str(round(self.downRayTest.getY(), 2)) rz = str(round(self.terrSteepness, 2)) fric = str(round(self.playerObj.getFriction(), 2)) ip = str(round(self.playerObj.getIceCoefficient(), 2)) sp = str(round(self.playerObj.getSnowCoefficient(), 2)) tHeight = str(round(self.getTerrainHeight(Point3(x, y, z)), 1)) self.textObj.editText("yetiPos", "Position: (" + sx + ", " + sy + ", " + sz + ")") self.textObj.editText("yetiVel", "Velocity: (" + vx + ", " + vy + ", " + vz + ")") self.textObj.editText("yetiFric", "Friction: " + fric) self.textObj.editText("onIce", "Ice(%): " + ip) self.textObj.editText("onSnow", "Snow(%): " + sp) self.textObj.editText("terrHeight", "T Height: " + tHeight) self.textObj.editText("terrSteepness", "Steepness: " + rz) #------------------------------------------------------------------------------------------------------------------------------------------------------------ # throw Snowball #------------------------------------------------------------------------------------------------------------------------------------------------------------ def throw(self): self.throwing = True size = self.ballObj.getSize() #zoom camera and grab pos you wish to throw self.camObj.aimMode() taskMgr.add(self.controlCamera, "camera-task") rotation = self.camObj.getH() pitch =self.camObj.getP() self.ballObj.throwBall(size, pitch, rotation) #fix camera #self.throwing = False #------------------------------------------------------------------------------------------------------------------------------------------------------------ # Update the world. Called every frame. #------------------------------------------------------------------------------------------------------------------------------------------------------------ def update(self, task): dt = globalClock.getDt() self.worldBullet.doPhysics(dt) # self.goat1.AIUpdate() # self.goat2.AIUpdate() self.playerMove() return task.cont
class TerrainCell(DirectObject): def __init__(self): self.settings = {} def configure(self, name, heightmap, texture, posx, posy): self.settings["name"] = name self.settings["heightmap"] = heightmap self.settings["texture"] = texture self.settings["x"] = posx self.settings["y"] = posy def create(self): self.test_texture = base.loader.loadTexture(self.settings["texture"]) self.terrain = GeoMipTerrain(self.settings["name"]) self.terrain.setHeightfield(self.settings["heightmap"]) # Set terrain properties self.terrain.setBruteforce(False) self.terrain.setBlockSize(32) self.terrain.setNear(40) self.terrain.setFar(100) #self.terrain.setMinLevel(16) self.terrain.setFocalPoint(base.camera) self.terrain.setBorderStitching(True) self.terrain.getRoot().setSz(300) self.terrain.getRoot().setSx(Globals.TERRAIN_MULT) self.terrain.getRoot().setSy(Globals.TERRAIN_MULT) self.terrain.getRoot().setPos((self.settings["x"]*512)*Globals.TERRAIN_MULT, \ (self.settings["y"]*512)*Globals.TERRAIN_MULT, 0) self.terrain.getRoot().setTexture(self.test_texture) self.terrain.generate() #self.fast_cols(16, 16) #self.generate_collisions() #self.ode_cols() def ode_cols(self): world = OdeWorld() world.setGravity(0, 0, -9) world.initSurfaceTable(1) world.setSurfaceEntry(0, 0, 150, 0.0, 9.1, 0.9, 0.00001, 0.0, 0.002) # Create a space and add a contactgroup to it to add the contact joints space = OdeSimpleSpace() space.setAutoCollideWorld(world) contactgroup = OdeJointGroup() space.setAutoCollideJointGroup(contactgroup) space.autoCollide() #try ODE for collisions t_trimesh = OdeTriMeshData(self.terrain.getRoot(), True) t_geom = OdeTriMeshGeom(space, t_trimesh) def fast_cols(self, x, y): #simpler, and faster return (self.terrain.getElevation(x, y), self.terrain.getNormal(x, y)) def generate_collisions(self): #try panda's collisions print("generating collisions...") x = 512 y = 512 while x: z = self.terrain.getElevation(x, y) cap = CollisionCapsule(0, 0, 1, 1) self.collision_node = base.render.attachNewNode( CollisionNode('cap1')) self.collision_node.node().addSolid(cap) #self.collision_node.show() #self.accept('into-cap1', self.hanev) #self.accept('out-cap1', self.hanev) self.collision_node.setPos(x, y, z * 300) x -= 16 y = 512 while y: z = self.terrain.getElevation(x, y) cap = CollisionCapsule(0, 0, 0, 0, 0, 1, 1) self.collision_node = base.render.attachNewNode( CollisionNode('cap1')) self.collision_node.node().addSolid(cap) self.collision_node.show() #self.accept('into-cap1', self.hanev) #self.accept('out-cap1', self.hanev) self.collision_node.setPos(x, y, z * 300) y -= 16 base.cTrav.addCollider(self.collision_node, base.mchandler) self.collision_node.setPos(10, 0, -3) def json_encode(self): with open("terrains.json", "a") as write_file: json.dump(self.settings, write_file, indent=4) write_file.write("\n") def json_decode(self, name): with open("terrains.json", "r") as read_file: terrains = json.load(read_file) try: self.settings = terrains[name] except KeyError: print("Key not found in json: " + name) return (False) else: return (True) def bam_encode(self): self.terrain.getRoot().writeBamFile(self.settings["name"])
class Simulation(ShowBase): def __init__(self): # Heightfield (static) self.height = 38.0 ShowBase.__init__(self) base.setBackgroundColor(0.1, 0.1, 0.8, 1) base.setFrameRateMeter(True) base.cam.setPos(0, -150, 200) base.cam.lookAt(0, 0, 0) # Light alight = AmbientLight('ambientLight') alight.setColor(Vec4(0.5, 0.5, 0.5, 1)) alightNP = render.attachNewNode(alight) dlight = DirectionalLight('directionalLight') dlight.setDirection(Vec3(1, 1, -1)) dlight.setColor(Vec4(0.7, 0.7, 0.7, 1)) dlightNP = render.attachNewNode(dlight) render.clearLight() render.setLight(alightNP) render.setLight(dlightNP) # Input self.accept('escape', self.doExit) inputState.watchWithModifiers('forward', 'w') inputState.watchWithModifiers('left', 'a') inputState.watchWithModifiers('reverse', 's') inputState.watchWithModifiers('backward', 'x') inputState.watchWithModifiers('right', 'd') # Task taskMgr.add(self.update, 'updateWorld') # Physics self.setup() # _____HANDLER_____ def doExit(self): self.cleanup() sys.exit(1) # ____TASK___ def processInput(self, dt): for vehicle in self.controlVehicles: engineForce = 0.0 brakeForce = 0.0 if inputState.isSet('forward'): engineForce = 1000.0 brakeForce = 0.0 if inputState.isSet('backward'): engineForce = -1000.0 brakeForce = 0.0 if inputState.isSet('reverse'): engineForce = 0.0 brakeForce = 100.0 if inputState.isSet('left'): vehicle.setAngle(True, dt) if inputState.isSet('right'): vehicle.setAngle(False, dt) # Apply engine and brake to rear wheels vehicle.setEngineForce(engineForce) vehicle.setBrakeForce(brakeForce) #print(vehicle.getAngle()) def update(self, task): dt = globalClock.getDt() self.processInput(dt) self.world.doPhysics(dt, 10, 0.008) self.terrain.update() return task.cont def cleanup(self): self.world = None self.worldNP.removeNode() def setup(self): self.worldNP = render.attachNewNode('World') # World self.world = BulletWorld() self.world.setGravity(Vec3(0, 0, -9.81)) #height map # Filename: # small -> 'Maps/HeightMapSmall.png' # big -> 'Maps/HeightMapBig.png' img = PNMImage(Filename('Maps/HeightMapSmall.png')) shape = BulletHeightfieldShape(img, self.height, ZUp) shape.setUseDiamondSubdivision(True) np = self.worldNP.attachNewNode(BulletRigidBodyNode('Heightfield')) np.node().addShape(shape) np.setPos(0, 0, 0) np.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(np.node()) #adding Texture #setColorMap: #small -> 'Maps/TextureMapSmall.jpg' #big -> 'Maps/TextureMapBig.jpg' self.terrain = GeoMipTerrain('terrain') self.terrain.setHeightfield(img) self.terrain.setColorMap('Maps/TextureMapSmall.jpg') self.terrain.setBruteforce(True) # level of detail self.terrain.setBlockSize(32) self.terrain.setNear(50) self.terrain.setFar(100) self.terrain.setFocalPoint(base.camera) rootNP = self.terrain.getRoot() rootNP.reparentTo(render) rootNP.setSz(self.height) offset = img.getXSize() / 2.0 - 0.5 rootNP.setPos(-offset, -offset, -self.height / 2.0) self.makeMapBorders(offset) self.terrain.generate() # creating vehicles #controlled vehicles self.controlVehicles = [] self.controlVehicles.append( Vehicle(0, 00, 40, "B", self.worldNP, self.world)) #vehicles goint to a specific point #self.squareVeh = Vehicle(0, 50, 40, "G", self.worldNP, self.world) #thread.start_new_thread(self.goSquare, (self.squareVeh, 100)) #vehicles following user #self.followVehicles = [] #self.followVehicles.append(Vehicle(-offset+10, -offset+10, 40, "R", self.worldNP, self.world)) #self.followVehicles.append(Vehicle(offset-10, offset-10, 60, "R", self.worldNP, self.world)) #for veh in self.followVehicles: # thread.start_new_thread(follow, (veh, self.controlVehicles[0])) #vehicles for hill climbing self.hillVehicles = [] self.hillVehicles.append( Vehicle(-offset + 10, -offset + 10, 40, "R", self.worldNP, self.world)) self.hillVehicles.append( Vehicle(offset - 10, offset - 10, 60, "R", self.worldNP, self.world)) for veh in self.hillVehicles: thread.start_new_thread(blindClimb, (veh, )) #function that navigates a vehicle to go in a square def goSquare(self, vehicle, size): while (True): goTo([size, size], vehicle) goTo([size, -size], vehicle) goTo([-size, -size], vehicle) goTo([-size, size], vehicle) #Borders around the map that vehicles won't fall from terrain def makeMapBorders(self, offset): plane1 = BulletPlaneShape(Vec3(1, 0, 0), 0) np = self.worldNP.attachNewNode(BulletRigidBodyNode('border1')) np.node().addShape(plane1) np.setPos(-offset, -offset, -self.height / 2.0) np.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(np.node()) plane2 = BulletPlaneShape(Vec3(0, 1, 0), 0) np = self.worldNP.attachNewNode(BulletRigidBodyNode('border2')) np.node().addShape(plane2) np.setPos(-offset, -offset, -self.height / 2.0) np.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(np.node()) plane3 = BulletPlaneShape(Vec3(0, -1, 0), 0) np = self.worldNP.attachNewNode(BulletRigidBodyNode('border3')) np.node().addShape(plane3) np.setPos(offset, offset, self.height / 2.0) np.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(np.node()) plane4 = BulletPlaneShape(Vec3(-1, 0, 0), 0) np = self.worldNP.attachNewNode(BulletRigidBodyNode('border4')) np.node().addShape(plane4) np.setPos(offset, offset, self.height / 2.0) np.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(np.node()) #getting height of map at some point def getHeight(self): line = CollisionLine(ox, oy, oz, dx, dy, dz)
class MyApp(ShowBase): def __init__(self): ShowBase.__init__(self) # Load the environment model. self.setup_environment() #self.scene = self.loader.loadModel("models/environment") # Reparent the model to render. #self.scene.reparentTo(self.render) # Apply scale and position transforms on the model. #self.scene.setScale(0.25, 0.25, 0.25) #self.scene.setPos(-8, 42, 0) # Needed for camera image self.dr = self.camNode.getDisplayRegion(0) # Needed for camera depth image winprops = WindowProperties.size(self.win.getXSize(), self.win.getYSize()) fbprops = FrameBufferProperties() fbprops.setDepthBits(1) self.depthBuffer = self.graphicsEngine.makeOutput( self.pipe, "depth buffer", -2, fbprops, winprops, GraphicsPipe.BFRefuseWindow, self.win.getGsg(), self.win) self.depthTex = Texture() self.depthTex.setFormat(Texture.FDepthComponent) self.depthBuffer.addRenderTexture(self.depthTex, GraphicsOutput.RTMCopyRam, GraphicsOutput.RTPDepth) lens = self.cam.node().getLens() lens.setFov(90.0, 90.0) # the near and far clipping distances can be changed if desired # lens.setNear(5.0) # lens.setFar(500.0) self.depthCam = self.makeCamera(self.depthBuffer, lens=lens, scene=self.render) self.depthCam.reparentTo(self.cam) # TODO: Scene is rendered twice: once for rgb and once for depth image. # How can both images be obtained in one rendering pass? self.render.setAntialias(AntialiasAttrib.MAuto) def setup_environment(self): # encapsulate some stuff # set up ambient lighting self.alight = AmbientLight('alight') self.alight.setColor(VBase4(0.1, 0.1, 0.1, 1)) self.alnp = self.render.attachNewNode(self.alight) self.render.setLight(self.alnp) # set up a point light self.plight = PointLight('plight') self.plight.setColor(VBase4(0.8, 0.8, 0.8, 1)) self.plnp = self.render.attachNewNode(self.plight) self.plnp.setPos(0, 0, 100) self.render.setLight(self.plnp) # set up terrain model self.terr_material = Material() self.terr_material.setShininess(1.0) self.terr_material.setAmbient(VBase4(0, 0, 0, 0)) self.terr_material.setDiffuse(VBase4(1, 1, 1, 1)) self.terr_material.setEmission(VBase4(0, 0, 0, 0)) self.terr_material.setSpecular(VBase4(0, 0, 0, 0)) # general scaling self.trrHorzSc = 4.0 self.trrVertSc = 4.0 # was 4.0 # Create sky #terrctr = self.trrHorzSc*65.0 #self.setup_skybox(terrctr,800.0,2.0,0.3) self.skysphere = self.loader.loadModel("sky-forest/SkySphere.bam") self.skysphere.setBin('background', 1) self.skysphere.setDepthWrite(0) self.skysphere.reparentTo(self.render) # Load some textures self.grsTxtSc = 5 self.numTreeTexts = 7 # ground texture self.txtGrass = self.loader.loadTexture('tex/ground005.png') self.txtGrass.setWrapU(Texture.WM_mirror) self.txtGrass.setWrapV(Texture.WM_mirror) self.txtGrass.setMagfilter(Texture.FTLinear) self.txtGrass.setMinfilter(Texture.FTLinearMipmapLinear) # set up terrain texture stages self.TS1 = TextureStage('terrtext') self.TS1.setSort(0) self.TS1.setMode(TextureStage.MReplace) # Set up the GeoMipTerrain self.terrain = GeoMipTerrain("myDynamicTerrain") img = PNMImage(Filename('tex/bowl_height_map.png')) self.terrain.setHeightfield(img) self.terrain.setBruteforce(0) self.terrain.setAutoFlatten(GeoMipTerrain.AFMMedium) # Set terrain properties self.terrain.setBlockSize(32) self.terrain.setNear(50) self.terrain.setFar(500) self.terrain.setFocalPoint(self.camera) # Store the root NodePath for convenience self.root = self.terrain.getRoot() self.root.clearTexture() self.root.setTwoSided(0) self.root.setCollideMask(BitMask32.bit(0)) self.root.setSz(self.trrVertSc) self.root.setSx(self.trrHorzSc) self.root.setSy(self.trrHorzSc) self.root.setMaterial(self.terr_material) self.root.setTexture(self.TS1, self.txtGrass) self.root.setTexScale(self.TS1, self.grsTxtSc, self.grsTxtSc) offset = 0.5 * img.getXSize() * self.trrHorzSc - 0.5 self.root.setPos(-offset, -offset, 0) self.terrain.generate() self.root.reparentTo(self.render) # load tree billboards self.txtTreeBillBoards = [] for a in range(self.numTreeTexts): fstr = 'trees/tree' + '%03d' % (a + 991) self.txtTreeBillBoards.append( \ self.loader.loadTexture(fstr + '-color.png', fstr + '-opacity.png')) self.txtTreeBillBoards[a].setMinfilter( Texture.FTLinearMipmapLinear) #self.placePlantOnTerrain('trees',300,0,20,20,self.trrHorzSc,self.trrVertSc, \ # self.numTreeTexts,self.txtTreeBillBoards,'scene-def/trees.txt') self.setup_house() self.setup_vehicle() self.taskMgr.add(self.skysphereTask, "SkySphere Task") def setup_house(self): # place farmhouse on terrain self.house = ModelNode('house1') self.loadModelOntoTerrain(self.render, self.terrain, self.house, 43.0, 0.275, 0.0, 0.0, self.trrHorzSc, self.trrVertSc, 'models/FarmHouse', Vec3(0, 0, 0), Point3(-12.0567, -29.1724, 0.0837742), Point3(12.2229, 21.1915, 21.3668)) def setup_vehicle(self): # place HMMWV on terrain self.hmmwv = ModelNode('hmmwv1') self.loadModelOntoTerrain(self.render, self.terrain, self.hmmwv, 33.0, 1.0, 20.0, 24.0, self.trrHorzSc, self.trrVertSc, 'models/hmmwv', Vec3(0, -90, 0), Point3(-1.21273, -2.49153, -1.10753), Point3(1.21273, 2.49153, 1.10753)) def setup_skybox(self, terrctr=645.0, boxsz=1000.0, aspect=1.0, uplift=0.0): vsz = boxsz / aspect self.bckgtx = [] self.bckgtx.append(self.loader.loadTexture('sky/Back2.png')) self.bckgtx.append(self.loader.loadTexture('sky/Right2.png')) self.bckgtx.append(self.loader.loadTexture('sky/Front2.png')) self.bckgtx.append(self.loader.loadTexture('sky/Left2.png')) self.bckgtx.append(self.loader.loadTexture('sky/Up.png')) for a in range(4): self.bckg = CardMaker('bkcard') lr = Point3(0.5 * boxsz, 0.5 * boxsz, -0.5 * vsz) ur = Point3(0.5 * boxsz, 0.5 * boxsz, 0.5 * vsz) ul = Point3(-0.5 * boxsz, 0.5 * boxsz, 0.5 * vsz) ll = Point3(-0.5 * boxsz, 0.5 * boxsz, -0.5 * vsz) self.bckg.setFrame(ll, lr, ur, ul) self.bckg.setHasNormals(0) self.bckg.setHasUvs(1) #self.bckg.setUvRange(self.bckgtx[a]) bkcrd = self.render.attachNewNode(self.bckg.generate()) bkcrd.setTexture(self.bckgtx[a]) self.bckgtx[a].setWrapU(Texture.WMClamp) self.bckgtx[a].setWrapV(Texture.WMClamp) bkcrd.setLightOff() bkcrd.setFogOff() bkcrd.setHpr(90.0 * a, 0, 0) cz = 0.5 * boxsz * uplift #print 'set card at:', terrctr,terrctr,cz, ' with points: ', lr,ur,ul,ll bkcrd.setPos(terrctr, terrctr, cz) self.top = CardMaker('bkcard') lr = Point3(0.5 * boxsz, -0.5 * boxsz, 0) ur = Point3(0.5 * boxsz, 0.5 * boxsz, 0) ul = Point3(-0.5 * boxsz, 0.5 * boxsz, 0) ll = Point3(-0.5 * boxsz, -0.5 * boxsz, 0) self.top.setFrame(ll, lr, ur, ul) self.top.setHasNormals(0) self.top.setHasUvs(1) #self.top.setUvRange(self.bckgtx[4]) bkcrd = self.render.attachNewNode(self.bckg.generate()) bkcrd.setTexture(self.bckgtx[4]) self.bckgtx[4].setWrapU(Texture.WMClamp) self.bckgtx[4].setWrapV(Texture.WMClamp) bkcrd.setLightOff() bkcrd.setFogOff() bkcrd.setHpr(0, 90, 90) bkcrd.setPos(terrctr, terrctr, 0.5 * vsz + 0.5 * boxsz * uplift) def placePlantOnTerrain(self, itemStr, itemCnt, Mode, typItemWidth, typItemHeight, trrHorzSc, trrVertSc, numTxtTypes, txtList, planFileName): # Billboarding plants crd = CardMaker('mycard') crd.setColor(0.5, 0.5, 0.5, 1) ll = Point3(-0.5 * typItemWidth, 0, 0) lr = Point3(0.5 * typItemWidth, 0, 0) ur = Point3(0.5 * typItemWidth, 0, typItemHeight) ul = Point3(-0.5 * typItemWidth, 0, typItemHeight) crd.setFrame(ll, lr, ur, ul) crd.setHasNormals(False) crd.setHasUvs(True) # generate/save/load locations try: plan_data_fp = open(planFileName, 'r') item_list = [] for line in plan_data_fp: toks = line.split(',') px = float(toks[0].strip(' ')) py = float(toks[1].strip(' ')) ang = float(toks[2].strip(' ')) dht = float(toks[3].strip(' ')) scl = float(toks[4].strip(' ')) idx = int(toks[5].strip(' ')) item_list.append((px, py, ang, dht, scl, idx)) plan_data_fp.close() print 'loaded ', itemStr, ' data file of size:', len(item_list) except IOError: # generate list and try to save item_list = [] for a in range(itemCnt): px = random.randrange(-self.trrHorzSc * 64, self.trrHorzSc * 64) py = random.randrange(-self.trrHorzSc * 64, self.trrHorzSc * 64) ang = 180 * random.random() dht = 0.0 scl = 0.75 + 0.25 * (random.random() + random.random()) idx = random.randrange(0, numTxtTypes) item_list.append([px, py, ang, dht, scl, idx]) try: plan_data_fp = open(planFileName, 'w') for c in item_list: print >> plan_data_fp, c[0], ',', c[1], ',', c[2], ',', c[ 3], ',', c[4], ',', c[5] plan_data_fp.close() print 'saved ', itemStr, ' data of size: ', len(item_list) except IOError: print 'unable to store ', itemStr, ' data of size: ', len( item_list) # define each plant for c in item_list: px = c[0] py = c[1] ang = c[2] dht = c[3] scl = c[4] idx = c[5] if idx >= numTxtTypes: idx = 0 if Mode > 0: for b in range(Mode): crdNP = self.render.attachNewNode(crd.generate()) crdNP.setTexture(txtList[idx]) crdNP.setScale(scl) crdNP.setTwoSided(True) ht = self.terrain.getElevation(px / trrHorzSc, py / trrHorzSc) crdNP.setPos(px, py, ht * trrVertSc + dht) crdNP.setHpr(ang + (180 / Mode) * b, 0, 0) crdNP.setTransparency(TransparencyAttrib.MAlpha) crdNP.setLightOff() else: # set up item as defined crd.setUvRange(txtList[idx]) crdNP = self.render.attachNewNode(crd.generate()) crdNP.setBillboardAxis() crdNP.setTexture(txtList[idx]) crdNP.setScale(scl) ht = self.terrain.getElevation(px / trrHorzSc, py / trrHorzSc) crdNP.setPos(px, py, ht * trrVertSc) crdNP.setTransparency(TransparencyAttrib.MAlpha) crdNP.setLightOff() def loadModelOntoTerrain(self, render_node, terr_obj, model_obj, hdg, scl, xctr, yctr, terr_horz_sc, terr_vert_sc, model_path, rotA, minP, maxP): # load model onto terrain hdg_rads = hdg * math.pi / 180.0 model_obj = self.loader.loadModel(model_path) rotAll = rotA rotAll.setX(rotAll.getX() + hdg) model_obj.setHpr(rotA) model_obj.setLightOff() # if model changes, these will have to be recomputed # minP = Point3(0,0,0) # maxP = Point3(0,0,0) # model_obj.calcTightBounds(minP,maxP) print minP print maxP htl = [] maxzofs = -1000.0 for xi in [minP[0], maxP[0]]: for yi in [minP[1], maxP[1]]: tx = xctr + scl * xi * math.cos(hdg_rads) ty = yctr + scl * yi * math.sin(hdg_rads) tht = self.terrain.getElevation(tx / terr_horz_sc, ty / terr_horz_sc) print 'tx=', tx, ', ty=', ty, ', tht=', tht htl.append(tht * terr_vert_sc - minP.getZ()) for hi in htl: if hi > maxzofs: maxzofs = hi print maxzofs model_obj.setPos(xctr, yctr, maxzofs) model_obj.setHpr(rotAll) model_obj.setScale(scl) model_obj.reparentTo(render_node) return maxzofs, minP, maxP def get_camera_image(self, requested_format=None): """ Returns the camera's image, which is of type uint8 and has values between 0 and 255. The 'requested_format' argument should specify in which order the components of the image must be. For example, valid format strings are "RGBA" and "BGRA". By default, Panda's internal format "BGRA" is used, in which case no data is copied over. """ tex = self.dr.getScreenshot() if requested_format is None: data = tex.getRamImage() else: data = tex.getRamImageAs(requested_format) image = np.frombuffer( data.get_data(), np.uint8) # use data.get_data() instead of data in python 2 image.shape = (tex.getYSize(), tex.getXSize(), tex.getNumComponents()) image = np.flipud(image) return image def get_camera_depth_image(self): """ Returns the camera's depth image, which is of type float32 and has values between 0.0 and 1.0. """ data = self.depthTex.getRamImage() depth_image = np.frombuffer(data.get_data(), np.float32) depth_image.shape = (self.depthTex.getYSize(), self.depthTex.getXSize(), self.depthTex.getNumComponents()) depth_image = np.flipud(depth_image) ''' Surface position can be inferred by calculating backward from the depth buffer. Each pixel on the screen represents a ray from the camera into the scene, and the depth value in the pixel indicates a distance along the ray. Because of this, it is not actually necessary to store surface position explicitly - it is only necessary to store depth values. Of course, OpenGL does that for free. So the framebuffer now needs to store surface normal, diffuse color, and depth value (to infer surface position). In practice, most ordinary framebuffers can only store color and depth - they don't have any place to store a third value. So we need to use a special offscreen buffer with an "auxiliary" bitplane. The auxiliary bitplane stores the surface normal. So then, there's the final postprocessing pass. This involves combining the diffuse color texture, the surface normal texture, the depth texture, and the light parameters into a final rendered output. The light parameters are passed into the postprocessing shader as constants, not as textures. If there are a lot of lights, things get interesting. You use one postprocessing pass per light. Each pass only needs to scan those framebuffer pixels that are actually in range of the light in question. To traverse only the pixels that are affected by the light, just render the illuminated area's convex bounding volume. The shader to store the diffuse color and surface normal is trivial. But the final postprocessing shader is a little complicated. What makes it tricky is that it needs to regenerate the original surface position from the screen position and depth value. The math for that deserves some explanation. We need to take a clip-space coordinate and depth-buffer value (ClipX,ClipY,ClipZ,ClipW) and unproject it back to a view-space (ViewX,ViewY,ViewZ) coordinate. Lighting is then done in view-space. Okay, so here's the math. Panda uses the projection matrix to transform view-space into clip-space. But in practice, the projection matrix for a perspective camera always contains four nonzero constants, and they're always in the same place: -- here are the non-zero elements of the projection matrix -- A 0 0 0 0 0 B 1 0 C 0 0 0 0 D 0 -- precompute these from above projection matrix -- ''' proj = self.cam.node().getLens().getProjectionMat() proj_x = 0.5 * proj.getCell(3, 2) / proj.getCell(0, 0) proj_y = 0.5 * proj.getCell(3, 2) proj_z = 0.5 * proj.getCell(3, 2) / proj.getCell(2, 1) proj_w = -0.5 - 0.5 * proj.getCell(1, 2) ''' -- now for each pixel compute viewpoint coordinates -- viewx = (screenx * projx) / (depth + projw) viewy = (1 * projy) / (depth + projw) viewz = (screeny * projz) / (depth + projw) ''' grid = np.mgrid[0:depth_image.shape[0], 0:depth_image.shape[1]] ygrid = np.float32(np.squeeze( grid[0, :, :])) / float(depth_image.shape[0] - 1) ygrid -= 0.5 xgrid = np.float32(np.squeeze( grid[1, :, :])) / float(depth_image.shape[1] - 1) xgrid -= 0.5 xview = 2.0 * xgrid * proj_x zview = 2.0 * ygrid * proj_z denom = np.squeeze(depth_image) + proj_w xview = xview / denom yview = proj_y / denom zview = zview / denom sqrng = xview**2 + yview**2 + zview**2 range_image = np.sqrt(sqrng) range_image_1 = np.expand_dims(range_image, axis=2) return depth_image, range_image_1 def compute_sample_pattern(self, limg_shape, res_factor): # assume velocity is XYZ and we are looking +X up and towards -Z pattern = [] lens = self.cam.node().getLens() sx = self.win.getXSize() sy = self.win.getYSize() ifov_vert = 2.0 * math.tan( 0.5 * math.radians(lens.getVfov())) / float(sy - 1) ifov_horz = 2.0 * math.tan( 0.5 * math.radians(lens.getHfov())) / float(sx - 1) #ifov_vert = lens.getVfov() / float(sy-1) #ifov_horz = lens.getHfov() / float(sy-1) for ldr_row in range(limg_shape[0]): theta = -10.0 - 41.33 * ( float(ldr_row) / float(limg_shape[0] - 1) - 0.5) for ldr_col in range(limg_shape[1]): psi = 60.0 * (float(ldr_col) / float(limg_shape[1] - 1) - 0.5) cpsi = math.cos(math.radians(psi)) vert_ang = theta / cpsi img_row_flt = (0.5 * float(sy - 1) - (math.tan(math.radians(vert_ang)) / ifov_vert)) #img_row_flt = 0.5*(sy-1) - (vert_ang / ifov_vert) if img_row_flt < 0: print('img_row_flt=%f' % img_row_flt) img_row_flt = 0.0 if img_row_flt >= sy: print('img_row_flt=%f' % img_row_flt) img_row_flt = float(sy - 1) img_col_flt = (0.5 * float(sx - 1) + (math.tan(math.radians(psi)) / ifov_horz)) #img_col_flt = 0.5*(sx-1) + (psi / ifov_horz) if img_col_flt < 0: print('img_col_flt=%f' % img_col_flt) img_col_flt = 0.0 if img_col_flt >= sx: print('img_col_flt=%f' % img_col_flt) img_col_flt = float(sx - 1) pattern.append((ldr_row, ldr_col, img_row_flt, img_col_flt)) return pattern def find_sorted_ladar_returns(self, rangearr, intensarr, ks_m): my_range = rangearr.copy() my_inten = intensarr.copy() ''' pixels data is organized by: [0] starting range of this return [1] ending range of this return [2] peak range of this return [3] total intensity of this return ''' int_mult = len(my_inten) pixels = map( list, zip(my_range.tolist(), my_range.tolist(), my_range.tolist(), my_inten.tolist())) spix = sorted(pixels, key=lambda x: x[0]) done = False while not done: mxpi = len(spix) if mxpi > 2: mindel = 1e20 mnidx = None for pidx in range(mxpi - 1): rdel = spix[pidx + 1][0] - spix[pidx][1] # must be within ks_m meters in range to merge if (rdel < ks_m) and (rdel < mindel): mindel = rdel mnidx = pidx # merge best two returns if mnidx is not None: # new range span for testing against neighbors spix[mnidx][1] = spix[mnidx + 1][1] # new peak range is range of max contributor if spix[mnidx + 1][3] > spix[mnidx][3]: spix[mnidx][2] = spix[mnidx + 1][2] # intensity of return is sum of contributors spix[mnidx][3] += spix[mnidx + 1][3] # remove one of the two merged del spix[mnidx + 1] else: done = True else: done = True # now eliminate all but max and last returns max_idx = None max_val = 0.0 for ci, pix in enumerate(spix): if pix[3] > max_val: max_val = pix[3] / int_mult max_idx = ci # if they are the same, return only one if spix[-1][3] >= spix[max_idx][3]: return [spix[-1]] else: return [spix[max_idx], spix[-1]] def sample_range_image(self, rng_img, int_img, limg_shape, vel_cam, pps, ldr_err, pattern): # depth image is set up as 512 x 512 and is 62.5 degrees vertical FOV # the center row is vertical, but we want to sample from the # region corresponding to HDL-32 FOV: from +10 to -30 degrees detailed_sensor_model = False fwd_vel = vel_cam[1] beam_div = 0.002 lens = self.cam.node().getLens() #sx = self.win.getXSize() sy = self.win.getYSize() ifov_vert = 2.0 * math.tan( 0.5 * math.radians(lens.getVfov())) / float(sy - 1) #ifov_horz = 2.0*math.tan(0.5*math.radians(lens.getHfov()))/float(sx-1) #ifov = math.radians(self.cam.node().getLens().getVfov() / self.win.getYSize()) sigma = beam_div / ifov_vert hs = int(2.0 * sigma + 1.0) gprof = gauss_kern(sigma, hs, normalize=False) rimg = np.zeros(limg_shape, dtype=np.float32) iimg = np.zeros(limg_shape, dtype=np.float32) margin = 10.0 for pidx, relation in enumerate(pattern): # get the usual scan pattern sample ldr_row, ldr_col, img_row_flt, img_col_flt = relation if ((img_row_flt > -margin) and (img_col_flt > -margin) and (img_row_flt < rng_img.shape[0] + margin) and (img_col_flt < rng_img.shape[1] + margin)): # within reasonable distance from image limits img_row = int(round(img_row_flt)) img_col = int(round(img_col_flt)) # motion compensation trng = np.float32(rng_img[img_row, img_col]) if trng > 0.0: # TODO: change this back to False done = True ic = 0 while not done: old_trng = trng del_row = pidx * fwd_vel / (ifov_vert * trng * pps) if (abs(del_row) > 1e-1) and (ic < 10): img_row_f = img_row_flt + del_row img_row = int(round(img_row_f)) trng = np.float32(rng_img[img_row, img_col]) ic += 1 if abs(trng - old_trng) < 0.5: done = True else: done = True # simple sensor processing: just sample from large images rimg[ldr_row, ldr_col] = np.float32(rng_img[img_row, img_col]) iimg[ldr_row, ldr_col] = np.float32(int_img[img_row, img_col]) if detailed_sensor_model: # detailed model subsamples whole beam width gpatch = copy_patch_centered((img_row, img_col), hs, int_img, 0.0) gpatch = np.float32(gpatch) gpatch *= gprof rpatch = copy_patch_centered((img_row, img_col), hs, rng_img, 0.0) rpatch = np.squeeze(rpatch) valid = rpatch > 1e-3 if np.count_nonzero(valid) > 0: rpatch_ts = rpatch[valid] gpatch_ts = gpatch[valid] returns = self.find_sorted_ladar_returns( rpatch_ts, gpatch_ts, 2.5) # for now we just take first return rimg[ldr_row, ldr_col] = returns[0][2] iimg[ldr_row, ldr_col] = returns[0][3] else: rimg[ldr_row, ldr_col] = 0.0 iimg[ldr_row, ldr_col] = np.float32(int_img[img_row, img_col]) rimg += ldr_err * np.random.standard_normal(rimg.shape) return rimg, iimg def skysphereTask(self, task): if self.base is not None: self.skysphere.setPos(self.base.camera, 0, 0, 0) self.terrain.generate() return task.cont