Beispiel #1
0
class HLevel():
    def __init__(self, showbase, physicsDebug=True):
        """


        :type self.Base: direct.showbase.ShowBase.ShowBase
        :type showbase: direct.showbase.ShowBase.ShowBase
        :type physicsDebug: bool
        """
        print "Creating level"
        self.Base = showbase
        self.debugDrawing = physicsDebug
        self.pause = False
        self.bulletSubstep = 0.008
        self.activeLog = False

    def loadAssets(self):
        print "Loading Assets"

    def renderAssets(self):
        print "Rendering assets"

    def setCamera(self):
        print "Setting camera"

    def setLights(self):
        print "Setting lights"

    def destroy(self):
        print "Destroying level"

    def loadEgg(self, egg):
        """
        :type egg: str
        :rtype : panda3d.core.NodePath
        """
        return self.Base.loader.loadModel(egg)

    def renderModel(self, model):
        """

        :type model: str
        """
        model.reparentTo(self.Base.render)

    def renderEgg(self, egg):
        """

        :type egg: str
        :return pada3d.core.NodePath
        """
        m = self.loadEgg(egg)
        self.renderModel(m)
        return m

    def setPhysics(self):
        print "Setting physics"
        self.world = BulletWorld()
        self.world.setGravity(Vec3(0, 0, -10))
        self.Base.taskMgr.add(self.physicsUpdate, "physicsUpdate", priority=0)
        if self.debugDrawing:
            print "Debug drawing"
            self.debug = BulletDebugNode("debug")
            self.debug.showWireframe(True)
            self.debug.showBoundingBoxes(False)
            self.debug.showNormals(True)
            self.debugNP = self.Base.render.attachNewNode(self.debug)
            self.debugNP.show()
            self.world.setDebugNode(self.debug)

    def physicsUpdate(self, task):
        if not self.pause:
            dt = globalClock.getDt()
            self.world.doPhysics(dt, 2, self.bulletSubstep)  # #0.009-0.008
            # print "Physics step"
        return task.cont

    def cameraShake(self, amplitud=0.01, frecuencia=5):
        """

        :type amplitud: float
        :type frecuencia: float
        """
        self.Base.camera.setZ(
            self.Base.camera,
            sin(globalClock.getRealTime() * frecuencia) * amplitud)

    def eggToStatic(self, egg, parent, margin=0.01, name="static"):
        """

        :type egg: str
        :type parent: panda3d.core.NodePath
        :type margin: float
        :type name: str
        :return: tuple(pada3d.bullet.BulletRigidBodyNode,panda3d.core.NodePath)
        """
        m = self.Base.loader.loadModel(egg)
        sTuple = modelToShape(m)
        sTuple[0].setMargin(margin)
        static = BulletRigidBodyNode(name)  # H
        static.addShape(sTuple[0], sTuple[1])
        np = parent.attachNewNode(egg)
        self.world.attachRigidBody(static)
        return static, np

    def togglePause(self):
        """

        """
        if self.pause:
            self.pause = False
        else:
            self.pause = True
        print "Toggle pause", self.pause

    def activateLog(self):
        self.activeLog = True
        self.logText = OnscreenText("NO LOG",
                                    scale=0.07,
                                    fg=(1, 0, 0, 0.8),
                                    bg=(0, 0, 1, 0.2),
                                    frame=(0, 1, 0, 0.2),
                                    pos=(-1.05, .9),
                                    mayChange=True,
                                    align=0)
        self.__logTextLenght = 0
        self.__logAbsoluteLenght = 0
        self.__logText = ""
        self.logText.reparentTo(self.Base.aspect2d)

    def log(self, *args):
        if self.activeLog is False:
            return None
        s = str(self.__logAbsoluteLenght) + ":"
        for a in args:
            s += str(a) + " "
        if self.__logTextLenght < 10:
            self.logText.appendText("\n" + s)
        else:
            self.__logTextLenght = 0
            self.logText.clearText()
            self.logText.setText(s)
        self.__logTextLenght += 1
        self.__logAbsoluteLenght += 1
        self.__logText.join(s)

    def loadFont(self, string):
        return self.Base.loader.loadFont(string)

    def drawLine(self,
                 fromP,
                 toP,
                 thickness=2,
                 color=(1, 0, 0, 1),
                 autoClear=True):
        if autoClear:
            try:
                self.debugLineNP.removeNode()
            except:
                pass
        self.debugLine = LineSegs("DebugLine")
        self.debugLine.reset()
        self.debugLine.setThickness(thickness)
        self.debugLine.setColor(color)
        self.debugLine.moveTo(fromP)
        self.debugLine.drawTo(toP)
        self.debugLineNode = self.debugLine.create()
        self.debugLineNP = NodePath(self.debugLineNode)
        self.debugLineNP.reparentTo(self.Base.render)
        return self.debugLineNP
Beispiel #2
0
class Tmx2Bam():
    def __init__(self, input_file, output_file=None, prefabs=""):
        self.dir = os.path.dirname(input_file)
        self.depth = 0
        self.cardmaker = CardMaker("image")
        self.cardmaker.set_frame(-0.5, 0.5, -0.5, 0.5)
        self.linesegs = LineSegs()
        self.textnode = TextNode("text")

        self.tilesheets = []  # Every tsx file loaded.
        self.tiles = {}  # Every unique tile/card.
        self.node = NodePath("tmx_root")

        # load prefab models
        self.prefabs = {}
        if prefabs:
            loader = Loader.get_global_ptr()
            for prefab_node in loader.load_sync(prefabs).get_children():
                prefab_node.clear_transform()
                self.prefabs[prefab_node.name] = NodePath(prefab_node)

        self.tmx = ET.parse(input_file).getroot()
        self.xscale = int(self.tmx.get("tilewidth"))
        self.yscale = int(self.tmx.get("tileheight"))
        self.size = [0, 0]

        self.load_group(self.tmx)
        if output_file:
            self.export_bam(output_file)

    def attributes_to_tags(self, node, element):
        if not element == None:
            for property in element:
                if property.get("name") and property.get("value"):
                    node.set_tag(property.get("name"), property.get("value"))
            for key in element.keys():
                node.set_tag(key, element.get(key))

    def build_text(self, object):
        self.textnode.set_text(object[0].text)
        # TODO: set color
        # TODO: set wrap
        return self.textnode.generate()

    def build_polygon(self, object):
        self.linesegs.reset()
        points = object[0].get("points").split(" ")
        points = [tuple(map(float, i.split(","))) for i in points]
        startx = points[0][0] / self.xscale
        starty = points[0][1] / self.yscale
        self.linesegs.move_to(startx, -starty, 0)
        for point in points:
            x, y = point[0] / self.xscale, point[1] / self.yscale
            self.linesegs.draw_to(x, -y, 0)
        self.linesegs.draw_to(startx, -starty, 0)
        return self.linesegs.create()

    def build_rectangle(self, w, h):
        self.linesegs.reset()
        self.linesegs.move_to(0, 0, 0)
        self.linesegs.draw_to(w, 0, 0)
        self.linesegs.draw_to(w, -h, 0)
        self.linesegs.draw_to(0, -h, 0)
        self.linesegs.draw_to(0, 0, 0)
        return self.linesegs.create()

    def build_tile(self, tsx, id):
        tile = None
        # Cross-reference with self.prefabs in case there's a shape
        # corresponding with a tile's type
        use_prefab = False
        for tile in tsx.findall("tile"):
            if int(tile.get("id")) == id:
                type = tile.get("type")
                if type in self.prefabs:
                    geometry_node = NodePath(str(id))
                    self.prefabs[type].copy_to(geometry_node)
                    use_prefab = True
                break
        # Else we generate a card
        if not use_prefab:
            geometry = self.cardmaker.generate()
            geometry_node = NodePath(geometry)
            geometry_node.set_texture(tsx.get("texture"), 1)
            geometry_node.set_p(-90)
        geometry_node.set_transparency(True)
        # scale and offset UVs for single sprite
        columns = int(tsx.get("columns"))
        rows = int(tsx.get("rows"))
        w, h = 1 / columns, 1 / rows
        tile_x, tile_y = int(id % columns), int(id / (columns))
        u, v = (tile_x * w), 1 - ((tile_y * h) + h)
        for stage in geometry_node.find_all_texture_stages():
            geometry_node.set_texture(stage, tsx.get("texture"), 1)
            geometry_node.set_tex_scale(stage, w, h)
            geometry_node.set_tex_offset(stage, (u, v))
        self.attributes_to_tags(geometry_node, tile)
        return geometry_node

    def animated_tile(self, tsx, tile):
        node = NodePath("animated tile")
        sequence = SequenceNode("animated tile")
        duration = int(tile[0][0].get("duration"))
        if duration >= 9000:
            sequence.set_frame_rate(0)
        else:
            sequence.set_frame_rate(1000 / duration)
        for frame in tile[0]:
            tileid = int(frame.get("tileid"))
            tile_node = self.build_tile(tsx, tileid)
            sequence.add_child(tile_node.node())
        sequence.loop(True)
        node.attach_new_node(sequence)
        return node

    def get_tile(self, map_id):
        tileset, set_id = self.get_tileset(map_id)
        tsx = tileset.get("tsx")
        if map_id in self.tiles:  # if card is already stored
            node = self.tiles[map_id]  # use that one
        else:  # else build and store it
            is_special = False
            node = self.build_tile(tsx, set_id)
            for element in tsx:
                if element.tag == "tile":
                    if int(element.get("id")) == set_id:
                        # if it contains an element, it's always an animation
                        if len(element) > 0:
                            node = self.animated_tile(tsx, element)
                        self.attributes_to_tags(node, element)
                        break
            self.tiles[map_id] = node
        return node

    def load_layer(self, layer):
        layer_node = NodePath(layer.get("name"))
        static_tiles = NodePath("static")  # Static tiles to flatten
        flat_animated_tiles = NodePath("animated")  # Animated tiles to flatten
        dynamic_tiles = NodePath(
            "dynamic")  # All tiles unless otherwise specified (don't flatten)
        tile_groups = {}
        # should we flatten this layer
        store_data = flatten = False
        properties = layer.find("properties")
        if properties:
            for property in properties:
                if property.get("name") == "flatten":
                    flatten = True
                if property.get("name") == "store_data":
                    store_data = True
        # build all tiles in data as a grid of cards
        data = layer.find("data").text
        data = data.replace('\n', '')
        data = data.split(",")
        collumns = int(layer.get("width"))
        rows = int(layer.get("height"))
        self.size = [collumns, rows]
        for y in range(rows):
            for x in range(collumns):
                id = int(data[(y * collumns) + (x % collumns)])
                data[(y * collumns) + (x % collumns)] = id
                if id > 0:
                    tile = NodePath("tile")
                    self.get_tile(id).copy_to(tile)
                    if flatten:
                        if tile.find("**/+SequenceNode"):
                            tile.reparent_to(flat_animated_tiles)
                        else:
                            tile.reparent_to(static_tiles)
                    else:
                        tile.reparent_to(layer_node)
                    tile.set_pos(x, -y, 0)

        if flatten:
            if static_tiles.get_num_children() > 0:
                clear_all_tags(static_tiles)
                static_tiles.flatten_strong()
            if flat_animated_tiles.get_num_children() > 0:
                clear_all_tags(flat_animated_tiles)
                flat_animated_tiles = self.flatten_animated_tiles(
                    flat_animated_tiles)
            for t in (static_tiles, flat_animated_tiles):
                t.reparent_to(layer_node)

        if store_data:
            layer_node.set_python_tag("data", data)
        self.append_layer(layer_node, properties)

    def flatten_animated_tiles(self, group_node):
        # FIXME: hard to read: get_child() everywhere
        # Makes a new node for each frame using all its tiles
        # flatten the s*** out of the node and add to a new SequenceNode.
        tiles = group_node.get_children()
        flattened_sequence = SequenceNode(tiles[0].name)
        for a, animation in enumerate(tiles[0].node().get_children()):
            for f, frame in enumerate(animation.get_child(0).get_children()):
                combined_frame = NodePath("frame " + str(f))
                for tile in tiles:
                    new_np = NodePath("frame")
                    new_np.set_pos(tile.get_pos())
                    animation = tile.node().get_child(a).get_child(0)
                    new_np.attach_new_node(animation.get_child(f))
                    new_np.reparent_to(combined_frame)
                combined_frame.flattenStrong()
                flattened_sequence.add_child(combined_frame.node())
        framerate = animation.get_frame_rate()
        flattened_sequence.set_frame_rate(framerate)
        flattened_sequence.loop(True)
        return NodePath(flattened_sequence)

    def load_objectgroup(self, objectgroup):
        layer_node = NodePath(objectgroup.get("name"))
        for object in objectgroup:
            name = object.get("name")
            if not name: name = "object"
            node = NodePath(name)
            if len(object) > 0:
                # Has a type, so it's either a polygon, text, point or ellipse
                # Points and ellipses are just an empty for now.
                kind = object[0].tag
                if kind == "polygon":
                    node.attach_new_node(self.build_polygon(object))
                elif kind == "text":
                    node.attach_new_node(self.build_text(object))
                    node.set_p(-90)
                self.attributes_to_tags(node, object[0])
            else:  # Doesn't have a type, so it's either an image or a rectangle
                node = NodePath(name)
                w = float(object.get("width")) / self.xscale
                h = float(object.get("height")) / self.yscale
                if object.get("gid"):  # Has a gid, so it's an image
                    self.get_tile(int(object.get("gid"))).copy_to(node)
                    node.set_scale(w, h, 1)
                else:  # It's none of the above, so it's a rectangle
                    node.attach_new_node(self.build_rectangle(w, h))
            x = y = 0
            if object.get("x"):
                x = float(object.get("x")) / self.xscale
            if object.get("y"):
                y = float(object.get("y")) / self.yscale
            node.set_pos(x, -y, 0)
            self.attributes_to_tags(node, object)
            node.reparent_to(layer_node)
        self.append_layer(layer_node, objectgroup.find("properties"))

    def load_imagelayer(self, imagelayer):
        # FIXME: A lot of this stuff is repeated in build_tilcard
        image = imagelayer[0]
        right = int(image.get("width")) / self.xscale
        down = int(image.get("height")) / self.yscale
        self.cardmaker.set_frame(0, right, -down, 0)
        node = NodePath(self.cardmaker.generate())
        self.cardmaker.set_frame(0, 1, -1, 0)
        texture = Texture()
        texture.read(os.path.join(self.dir, image.get("source")))
        texture.setMagfilter(SamplerState.FT_nearest)
        texture.setMinfilter(SamplerState.FT_nearest)
        node.set_texture(texture)
        node.set_transparency(True)
        node.reparent_to(self.node)
        ox = imagelayer.get("offsetx")
        x, y = 0, 0
        if ox:
            x = float(ox) / self.xscale
        oy = imagelayer.get("offsety")
        if oy:
            y = float(oy) / self.yscale
        node.set_pos((x, -y, self.depth))
        node.set_p(-90)

    def load_group(self, group):
        for layer in group:
            if layer.tag == "tileset":
                self.load_tsx(layer)
            elif layer.tag == "layer":
                self.load_layer(layer)
            elif layer.tag == "objectgroup":
                self.load_objectgroup(layer)
            elif layer.tag == "imagelayer":
                self.load_imagelayer(layer)
            elif layer.tag == "group":
                self.load_group(layer)

    def append_layer(self, node, properties):
        self.attributes_to_tags(node, properties)
        node.set_z(self.depth)
        self.depth += 1
        if properties:
            for property in properties:
                if property.get("name") == "z":
                    node.set_z(int(property.get("value")))
                    self.depth -= 1
                    break
        node.reparent_to(self.node)

    def get_tileset(self, id):
        for tilesheet in self.tilesheets:
            if int(tilesheet.get("firstgid")) > id:
                break
            else:
                last = tilesheet
        id_in_sheet = id - int(last.get("firstgid"))
        return last, id_in_sheet,

    def load_tsx(self, layer):
        tsx_filename = layer.get("source")
        tsx = ET.parse(os.path.join(self.dir, tsx_filename)).getroot()
        # Load texture and store in the element tree.
        img_filename = tsx[0].get("source")
        texture = Texture()
        dir = os.path.join(self.dir, tsx_filename)
        place = os.path.join(os.path.split(dir)[0], img_filename)
        texture.read(place)
        texture.setMagfilter(SamplerState.FT_nearest)
        texture.setMinfilter(SamplerState.FT_nearest)
        tsx.set("texture", texture)
        columns = int(tsx.get("columns"))
        rows = int(tsx.get("tilecount")) // columns
        tsx.set("rows", str(rows))
        layer.set("tsx", tsx)
        self.tilesheets.append(layer)

    def export_bam(self, filename):
        print("Exporting as {}".format(filename))
        self.node.writeBamFile("{}".format(filename))