Beispiel #1
0
def loadTerrain(name, widthScale = 0.5, heightScale = 10.0):
    """load terrain stuff"""

    global app, terrain, terrainRootNetPos
        
    steerMgr = OSSteerManager.get_global_ptr()

    terrain = GeoMipTerrain("terrain")
    heightField = PNMImage(Filename(dataDir + "/heightfield.png"))
    terrain.set_heightfield(heightField)
    # sizing
    environmentWidthX = (heightField.get_x_size() - 1) * widthScale
    environmentWidthY = (heightField.get_y_size() - 1) * widthScale
    environmentWidth = (environmentWidthX + environmentWidthY) / 2.0
    terrain.get_root().set_sx(widthScale)
    terrain.get_root().set_sy(widthScale)
    terrain.get_root().set_sz(heightScale)
    # set other terrain's properties
    blockSize, minimumLevel = (64, 0)
    nearPercent, farPercent = (0.1, 0.7)
    terrainLODmin = min(minimumLevel, terrain.get_max_level())
    flattenMode = GeoMipTerrain.AFM_off
    terrain.set_block_size(blockSize)
    terrain.set_near(nearPercent * environmentWidth)
    terrain.set_far(farPercent * environmentWidth)
    terrain.set_min_level(terrainLODmin)
    terrain.set_auto_flatten(flattenMode)
    # terrain texturing
    textureStage0 = TextureStage("TextureStage0")
    textureImage = TexturePool.load_texture(Filename("terrain.png"))
    terrain.get_root().set_tex_scale(textureStage0, 1.0, 1.0)
    terrain.get_root().set_texture(textureStage0, textureImage, 1)
    # reparent this Terrain node path to the object node path
    terrain.get_root().reparent_to(steerMgr.get_reference_node_path())
    terrain.get_root().set_collide_mask(mask)
    terrain.get_root().set_name(name)
    # brute force generation
    bruteForce = True
    terrain.set_bruteforce(bruteForce)
    # Generate the terrain
    terrain.generate()
    # check if terrain needs update or not
    if not bruteForce:
        # save the net pos of terrain root
        terrainRootNetPos = terrain.get_root().get_net_transform().get_pos()
        # Add a task to keep updating the terrain
        app.taskMgr.add(terrainUpdate, "terrainUpdate", appendTask=True)
    #
    return terrain.get_root()
Beispiel #2
0
class WorldManager(object):
    """A world manager for heightmapped worlds stored as XML."""
    def __init__(self):
        """Setup this world manager."""
        Logger.info("Initializing world manager...")

        self.terrain = None
        self.portals = []
        self.gates = []
        self.objects = []
        self.scenery = RigidBodyCombiner("scenery")
        self.scenery_np = render.attach_new_node(self.scenery)
        self.is_dirty = True

        base.task_mgr.add(self.run_logic)

        Logger.info("World manager initialized.")

    def load_map(self, map):
        """Load a map."""
        #Unload the current map first
        self.unload_map()

        #Locate the XML file for the map
        Logger.info("Loading map '{}'...".format(map))
        map_file = os.path.join(map, os.path.basename(map) + ".xml")

        if not os.path.exists(map_file):
            Logger.error("Failed to load map file '{}'.".format(map_file))
            return False

        #Load the map XML file
        xml = etree.parse(map_file)
        root = xml.getroot()

        for child in root:
            #Terrain?
            if child.tag == "terrain":
                #Validate terrain
                if not ("size" in child.attrib and "spawnpos" in child.attrib
                        and "heightmap" in child.attrib):
                    Logger.error(
                        "Terrain section must define 'size', 'spawnpos', and 'heightmap'."
                    )
                    return False

                #Load terrain
                self.size = parse_vec(child.attrib["size"], 3)
                self.spawnpos = parse_vec(child.attrib["spawnpos"], 2)
                heightmap = os.path.join(map, child.attrib["heightmap"])

                self.terrain = GeoMipTerrain("Terrain")
                self.terrain.set_block_size(64)
                self.terrain.set_bruteforce(True)

                if not self.terrain.set_heightfield(heightmap):
                    Logger.error("Failed to load heightmap for terrain.")
                    self.terrain = None
                    return False

                self.terrain_np = self.terrain.get_root()
                self.terrain_np.set_scale(self.size[0] / 512,
                                          self.size[1] / 512, self.size[2])
                tex = loader.load_texture(
                    "./data/textures/terrain/grass_tex2.png")
                self.terrain_np.set_texture(tex)
                self.terrain_np.set_tex_scale(TextureStage.get_default(),
                                              self.size[0] / 512,
                                              self.size[1] / 512)
                tex.set_wrap_u(Texture.WM_repeat)
                tex.set_wrap_v(Texture.WM_repeat)
                self.terrain_np.reparent_to(render)
                self.terrain.generate()

                base.camera.set_pos(self.size[0] / 2, self.size[1] / 2,
                                    self.size[2])

            #Portal?
            elif child.tag == "portal":
                #Validate portal
                if not ("pos" in child.attrib and "destmap" in child.attrib):
                    Logger.warning("Portal must define 'pos' and 'destmap'.")
                    continue

                #Load portal
                pos = parse_vec(child.attrib["pos"], 3)
                radius = parse_float(
                    child.attrib["radius"]) if "radius" in child.attrib else 1
                destmap = child.attrib["destmap"]
                self.add_portal(pos, radius, destmap)

            #Gate?
            elif child.tag == "gate":
                #Validate gate
                if not ("pos" in child.attrib and "destmap" in child.attrib
                        and "destvec" in child.attrib):
                    Logger.warning(
                        "Gate must define 'pos', 'destmap', and 'destvec'.")
                    continue

                #Load gate
                pos = parse_vec(child.attrib["pos"], 3)
                destmap = child.attrib["destmap"]
                destvec = parse_vec(child.attrib["destvec"], 3)
                material = child.attrib[
                    "material"] if "material" in child.attrib else ""
                self.add_gate(pos, destmap, destvec, material)

            #Object?
            elif child.tag == "object":
                #Validate object
                if not ("mesh" in child.attrib and "pos" in child.attrib):
                    Logger.warning("Object must define 'mesh' and 'pos'.")
                    continue

                #Load object
                mesh = child.attrib["mesh"]
                pos = parse_vec(child.attrib["pos"], 3)
                rot = parse_vec(child.attrib["rot"],
                                3) if "rot" in child.attrib else [0, 0, 0]
                scale = parse_vec(child.attrib["scale"],
                                  3) if "scale" in child.attrib else [1, 1, 1]
                material = child.attrib[
                    "material"] if "material" in child.attrib else ""
                sound = child.attrib["sound"] if "sound" in child.attrib else ""
                self.add_object(mesh, pos, rot, scale, material, sound)

            #Object Group?
            elif child.tag == "objectgroup":
                #Validate object group
                if not ("mesh" in child.attrib):
                    Logger.warning("Object group must define 'mesh'.")
                    continue

                #Load object group
                mesh = child.attrib["mesh"]
                material = child.attrib[
                    "material"] if "material" in child.attrib else ""
                self.load_object_group(child, mesh, material)

            #Unknown?
            else:
                Logger.warning(
                    "Unknown tag '{}' encountered in map '{}'.".format(
                        child.tag, map))

        #Map loaded
        Logger.info("Map '{}' loaded.".format(map))
        return True

    def unload_map(self):
        """Unload the current map."""
        if self.terrain is not None:
            self.terrain.get_root().remove_node()

        self.terrain = None
        self.size = [0, 0]
        self.spawnpos = [0, 0, 0]

        while len(self.portals) > 0:
            self.del_portal(self.portals[-1])

        while len(self.gates) > 0:
            self.del_gate(self.gates[-1])

        while len(self.objects) > 0:
            self.del_object(self.objects[-1])

    def load_object_group(self, group, mesh, material):
        """Load a group of objects."""
        for object in group:
            #Validate object
            if not ("pos" in object.attrib):
                Logger.warning("Group object must define 'pos'.")
                continue

            #Load object
            pos = parse_vec(object.attrib["pos"], 2)
            rot = parse_vec(object.attrib["rot"],
                            1) if "rot" in object.attrib else [0, 0, 0]
            scale = parse_vec(object.attrib["scale"],
                              1) if "scale" in object.attrib else [1, 1, 1]
            self.add_object(mesh, pos, rot, scale, material, "")

    def add_portal(self, pos, radius, dest):
        """Add a portal to this world."""
        self.portals.append(Portal(pos, radius, dest))
        self.is_dirty = True
        Logger.info("Added portal: pos = {}, radius = {}, dest = '{}'".format(
            pos, radius, dest))

    def del_portal(self, portal):
        """Remove a portal from this world."""
        self.portals.remove(portal)
        self.is_dirty = True
        Logger.info("Removed portal {}".format(portal))

    def add_gate(self, pos, dest, destvec, material):
        """Add a gate to this world."""
        self.gates.append(Gate(pos, dest, destvec, material))
        self.is_dirty = True
        Logger.info(
            "Added gate: pos = {}, dest = '{}', destvec = {}, material = '{}'".
            format(pos, dest, destvec, material))

    def del_gate(self, gate):
        """Remove a gate from this world."""
        self.gates.remove(gate)
        self.is_dirty = True
        Logger.info("Removed gate {}".format(gate))

    def add_object(self, mesh, pos, rot, scale, material, sound):
        """Add an object to this world."""
        #Handle 2 coordinate position
        if len(pos) == 2:
            pos = [pos[0], pos[1], self.get_terrain_height(pos)]

        #Handle single coordinate rotation
        if len(rot) == 1:
            rot = [rot[0], 0, 0]

        #Handle single or double coordinate scale
        if len(scale) == 1:
            scale = [scale[0], scale[0], scale[0]]

        elif len(scale) == 2:
            scale = [scale[0], scale[1], 1]

        #Add the object
        self.objects.append(Object(mesh, pos, rot, scale, material, sound))
        self.is_dirty = True
        Logger.info(
            "Added object: mesh = '{}', pos = {}, rot = {}, scale = {}, material = '{}', sound = '{}'"
            .format(mesh, pos, rot, scale, material, sound))

    def del_object(self, object):
        """Delete an object from this world."""
        self.objects.remove(object)
        self.is_dirty = True
        Logger.info("Removed object {}".format(object))

    def get_terrain_height(self, pos):
        """Get the height of the terrain at the given point."""
        #Is the position a list of 2 elements?
        if isinstance(pos, list) and len(pos) == 2:
            return self.terrain.get_elevation(
                pos[0] / (self.size[0] / 512), pos[1] /
                (self.size[1] / 512)) * self.size[2]

        #Assume it is a point object
        else:
            return self.terrain.get_elevation(
                pos[0] / (self.size[0] / 512), pos[1] /
                (self.size[1] / 512)) * self.size[2]

    def run_logic(self, task):
        """Run the logic for this world manager."""
        #Optimize the scenery
        if self.is_dirty:
            self.scenery.collect()
            self.is_dirty = False
            Logger.info("Optimized the scenery.")

        return Task.cont