示例#1
0
class CogdoFlyingLevelQuadrant:
    notify = directNotify.newCategory('CogdoFlyingLevelQuadrant')

    def __init__(self, serialNum, model, level, parent):
        self.serialNum = serialNum
        self._model = model
        self._level = level
        self._root = NodePath('Quadrant' + repr(serialNum))
        self._model.reparentTo(self._root)
        self._root.reparentTo(parent)
        self._visible = True
        self.platforms = {}
        self.gatherables = []
        self.obstacles = []
        self._playing = False
        self._obstaclesRoot = NodePath('obstacles')
        self._obstaclesRoot.reparentTo(self._root)
        self._initObstacles(self._obstaclesRoot)
        self._gatherablesRoot = NodePath('gatherables')
        self._gatherablesRoot.reparentTo(self._root)
        self._initGatherables(self._gatherablesRoot)
        self._platformsRoot = NodePath('platforms')
        self._platformsRoot.reparentTo(self._model)
        self._initPlatforms(self._platformsRoot)
        self._optimize()
        self.place()

    def _optimize(self):
        lightCones = NodePath('lightCones')
        for np in self._platformsRoot.findAllMatches('**/*lightCone*'):
            np.wrtReparentTo(lightCones)

        lightCones.reparentTo(self._model)
        node = self._model.find('**/ducts')
        if not node.isEmpty():
            node.flattenStrong()
            for np in node.getChildren():
                np.wrtReparentTo(self._model)

        node = self._model.find('**/nests')
        if not node.isEmpty():
            for np in node.getChildren():
                np.flattenStrong()
                np.wrtReparentTo(self._model)

        for np in self._model.findAllMatches('**/*LayerStack*'):
            np.wrtReparentTo(self._model)

        for np in self._model.find('**/static').getChildren():
            np.wrtReparentTo(self._model)

        self._model.flattenMedium()

    def _initPlatforms(self, parent):
        platformModels = self._model.findAllMatches('**/%s' % Globals.Level.PlatformName)
        for platformModel in platformModels:
            platform = CogdoFlyingPlatform(platformModel, parent=parent)
            self.platforms[platform.getName()] = platform

    def _destroyPlatforms(self):
        for platform in list(self.platforms.values()):
            platform.destroy()

        del self.platforms

    def _initGatherables(self, parent):
        self.generateGatherables(self._model, parent=parent)
        if Globals.Level.SpawnLaffPowerupsInNests:
            self.generateNestPowerups(self._model, parent=parent)

    def generateNestPowerups(self, gatherableModel, parent):
        nests = gatherableModel.findAllMatches('**/%s;+s' % Globals.Level.LegalEagleNestName)
        for nest in nests:
            offset = Globals.Level.LaffPowerupNestOffset
            pickup = self._level.gatherableFactory.createPowerup(Globals.Level.GatherableTypes.LaffPowerup)
            pickup.reparentTo(parent)
            pickup.setPos(parent, nest.getPos(parent) + offset)
            if Globals.Level.AddSparkleToPowerups:
                sparkles = self._level.gatherableFactory.createSparkles(Vec4(1, 1, 1, 1), Vec4(1, 1, 0, 1), 10.0)
                sparkles.reparentTo(pickup)
                sparkles.setPos(0, 0, 1)
                sparkles.start()
            self.gatherables.append(pickup)

    def generateGatherables(self, gatherableModel, parent = None, spread = Globals.Level.GatherablesDefaultSpread):
        parent = parent or self._root
        mopath = Mopath.Mopath(name='gatherables')

        def generateMemos():
            gatherPaths = gatherableModel.findAllMatches('**/%s' % Globals.Level.GatherablesPathName)
            for gatherPath in gatherPaths:
                mopath.loadNodePath(gatherPath)
                t = 0.0
                while t < mopath.getMaxT():
                    pickup = self._level.gatherableFactory.createMemo()
                    pickup.reparentTo(parent)
                    mopath.goTo(pickup, t)
                    self.gatherables.append(pickup)
                    t += spread

                gatherPath.removeNode()

            angleSpread = 360.0 / Globals.Level.NumMemosInRing
            gatherPaths = gatherableModel.findAllMatches('**/%s' % Globals.Level.GatherablesRingName)
            for gatherPath in gatherPaths:
                mopath.loadNodePath(gatherPath)
                t = 0.0
                while t < mopath.getMaxT():
                    angle = 0
                    r = 3
                    while angle < 360.0:
                        pickup = self._level.gatherableFactory.createMemo()
                        pickup.reparentTo(parent)
                        mopath.goTo(pickup, t)
                        pickup.setX(parent, pickup.getX() + r * math.cos(math.radians(angle)))
                        pickup.setZ(parent, pickup.getZ() + r * math.sin(math.radians(angle)))
                        self.gatherables.append(pickup)
                        angle += angleSpread

                    t += spread + 0.5

                gatherPath.removeNode()

        def generatePropellers():
            gatherables = gatherableModel.findAllMatches('**/%s' % Globals.Level.PropellerName)
            for gatherable in gatherables:
                pickup = self._level.gatherableFactory.createPropeller()
                pickup.reparentTo(gatherable.getParent())
                pickup.setPos(parent, gatherable.getPos(parent))
                self.gatherables.append(pickup)
                gatherable.removeNode()

        def generatePowerUps():
            for powerupType, locName in Globals.Level.PowerupType2Loc.items():
                if powerupType == Globals.Level.GatherableTypes.LaffPowerup and Globals.Level.IgnoreLaffPowerups:
                    continue
                gatherables = gatherableModel.findAllMatches('**/%s' % locName)
                for gatherable in gatherables:
                    pickup = self._level.gatherableFactory.createPowerup(powerupType)
                    pickup.reparentTo(parent)
                    pickup.setPos(parent, gatherable.getPos(parent))
                    if Globals.Level.AddSparkleToPowerups:
                        sparkles = self._level.gatherableFactory.createSparkles(Vec4(1, 1, 1, 1), Vec4(1, 1, 0, 1), 10.0)
                        sparkles.reparentTo(pickup)
                        sparkles.setPos(0, 0, 1)
                        sparkles.start()
                    self.gatherables.append(pickup)
                    gatherable.removeNode()

        generateMemos()
        generatePropellers()
        generatePowerUps()

    def _initObstacles(self, parent):

        def initWhirlwinds():
            obstacles = self._root.findAllMatches('**/%s' % Globals.Level.WhirlwindName)
            for obstacleLoc in obstacles:
                motionPath = self._model.find('**/%s%s' % (obstacleLoc.getName(), Globals.Level.WhirlwindPathName))
                if motionPath.isEmpty():
                    motionPath = None
                obstacle = self._level.obstacleFactory.createWhirlwind(motionPath=motionPath)
                obstacle.model.reparentTo(parent)
                obstacle.model.setPos(parent, obstacleLoc.getPos(parent))
                self.obstacles.append(obstacle)
                obstacleLoc.removeNode()

            return

        def initStreamers():
            obstacles = self._model.findAllMatches('**/%s' % Globals.Level.StreamerName)
            for obstacleLoc in obstacles:
                obstacle = self._level.obstacleFactory.createFan()
                obstacle.model.reparentTo(parent)
                obstacle.model.setPos(parent, obstacleLoc.getPos(parent))
                obstacle.model.setHpr(parent, obstacleLoc.getHpr(parent))
                obstacle.model.setScale(parent, obstacleLoc.getScale(parent))
                obstacle.setBlowDirection()
                if Globals.Level.AddParticlesToStreamers:
                    particles = self._level.obstacleFactory.createStreamerParticles(Vec4(1, 1, 1, 1), Vec4(1, 1, 1, 1), 10.0)
                    particles.reparentTo(obstacle.model)
                    particles.start()
                self.obstacles.append(obstacle)
                obstacleLoc.removeNode()

        def initWalkingMinions():
            motionPaths = self._model.findAllMatches('**/%s' % Globals.Level.MinionWalkingPathName)
            for motionPath in motionPaths:
                obstacle = self._level.obstacleFactory.createWalkingMinion(motionPath=motionPath)
                obstacle.model.reparentTo(parent)
                obstacle.model.setPos(parent, motionPath.getPos(parent))
                self.obstacles.append(obstacle)

        def initFlyingMinions():
            motionPaths = self._model.findAllMatches('**/%s' % Globals.Level.MinionFlyingPathName)
            for motionPath in motionPaths:
                obstacle = self._level.obstacleFactory.createFlyingMinion(motionPath=motionPath)
                obstacle.model.reparentTo(parent)
                obstacle.model.setPos(parent, motionPath.getPos(parent))
                self.obstacles.append(obstacle)

        initWhirlwinds()
        initStreamers()
        initWalkingMinions()
        initFlyingMinions()

    def place(self):
        self._root.setPos(0, self._level.convertQuadNumToY(self.serialNum), 0)

    def destroy(self):
        if self._visible:
            self.offstage()
        self._destroyPlatforms()
        for obstacle in self.obstacles:
            obstacle.destroy()

        for gatherable in self.gatherables:
            gatherable.destroy()

        self._root.removeNode()
        del self._root
        del self._gatherablesRoot
        del self._obstaclesRoot
        del self._platformsRoot
        del self._level

    def onstage(self, elapsedTime = 0.0):
        if self._visible:
            return
        self._root.unstash()
        for obstacle in self.obstacles:
            obstacle.startMoving(elapsedTime)

        for gatherable in self.gatherables:
            gatherable.show()

        self._visible = True

    def offstage(self):
        if not self._visible:
            return
        self._root.stash()
        for obstacle in self.obstacles:
            obstacle.stopMoving()

        for gatherable in self.gatherables:
            gatherable.hide()

        self._visible = False

    def update(self, dt):
        if self._visible:
            for gatherable in self.gatherables:
                gatherable.update(dt)

            for obstacle in self.obstacles:
                obstacle.update(dt)

    def getModel(self):
        return self._root
示例#2
0
class CogdoMazeFactory:
    def __init__(self,
                 randomNumGen,
                 width,
                 height,
                 frameWallThickness=Globals.FrameWallThickness,
                 cogdoMazeData=CogdoMazeData):
        self._rng = RandomNumGen(randomNumGen)
        self.width = width
        self.height = height
        self.frameWallThickness = frameWallThickness
        self._cogdoMazeData = cogdoMazeData
        self.quadrantSize = self._cogdoMazeData.QuadrantSize
        self.cellWidth = self._cogdoMazeData.QuadrantCellWidth

    def getMazeData(self):
        if not hasattr(self, '_data'):
            self._generateMazeData()
        return self._data

    def createCogdoMaze(self, flattenModel=True):
        if not hasattr(self, '_maze'):
            self._loadAndBuildMazeModel(flatten=flattenModel)
        return CogdoMaze(self._model, self._data, self.cellWidth)

    def _gatherQuadrantData(self):
        self.openBarriers = []
        barrierItems = list(range(Globals.TotalBarriers))
        self._rng.shuffle(barrierItems)
        for i in barrierItems[0:len(barrierItems) - Globals.NumBarriers]:
            self.openBarriers.append(i)

        self.quadrantData = []
        quadrantKeys = list(self._cogdoMazeData.QuadrantCollisions.keys())
        self._rng.shuffle(quadrantKeys)
        i = 0
        for y in range(self.height):
            for x in range(self.width):
                key = quadrantKeys[i]
                collTable = self._cogdoMazeData.QuadrantCollisions[key]
                angle = self._cogdoMazeData.QuadrantAngles[self._rng.randint(
                    0,
                    len(self._cogdoMazeData.QuadrantAngles) - 1)]
                self.quadrantData.append((key, collTable[angle], angle))
                i += 1
                if x * y >= self._cogdoMazeData.NumQuadrants:
                    i = 0

    def _generateBarrierData(self):
        data = []
        for y in range(self.height):
            data.append([])
            for x in range(self.width):
                if x == self.width - 1:
                    ax = -1
                else:
                    ax = 1
                if y == self.height - 1:
                    ay = -1
                else:
                    ay = 1
                data[y].append([ax, ay])

        dirUp = 0
        dirDown = 1
        dirLeft = 2
        dirRight = 3

        def getAvailableDirections(ax, ay, ignore=None):
            dirs = []
            if ax - 1 >= 0 and data[ay][ax - 1][BARRIER_DATA_RIGHT] == 1 and (
                    ax, ay) != ignore:
                dirs.append(dirLeft)
            if ax + 1 < self.width and data[ay][ax][
                    BARRIER_DATA_RIGHT] == 1 and (ax, ay) != ignore:
                dirs.append(dirRight)
            if ay - 1 >= 0 and data[ay - 1][ax][BARRIER_DATA_TOP] == 1 and (
                    ax, ay) != ignore:
                dirs.append(dirDown)
            if ay + 1 < self.height and data[ay][ax][
                    BARRIER_DATA_TOP] == 1 and (ax, ay) != ignore:
                dirs.append(dirUp)
            return dirs

        visited = []

        def tryVisitNeighbor(ax, ay, ad):
            if ad == dirUp:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_TOP] = 0
                ay += 1
            elif ad == dirDown:
                if data[ay - 1][ax] in visited:
                    return None
                visited.append(data[ay - 1][ax])
                data[ay - 1][ax][BARRIER_DATA_TOP] = 0
                ay -= 1
            elif ad == dirLeft:
                if data[ay][ax - 1] in visited:
                    return None
                visited.append(data[ay][ax - 1])
                data[ay][ax - 1][BARRIER_DATA_RIGHT] = 0
                ax -= 1
            elif ad == dirRight:
                if data[ay][ax] in visited:
                    return None
                visited.append(data[ay][ax])
                data[ay][ax][BARRIER_DATA_RIGHT] = 0
                ax += 1
            return (ax, ay)

        def openBarriers(x, y):
            dirs = getAvailableDirections(x, y)
            for dir in dirs:
                next = tryVisitNeighbor(x, y, dir)
                if next is not None:
                    openBarriers(*next)

            return

        x = self._rng.randint(0, self.width - 1)
        y = self._rng.randint(0, self.height - 1)
        openBarriers(x, y)
        self._barrierData = data
        return

    def _generateMazeData(self):
        if not hasattr(self, 'quadrantData'):
            self._gatherQuadrantData()
        self._data = {}
        self._data['width'] = (
            self.width +
            1) * self.frameWallThickness + self.width * self.quadrantSize
        self._data['height'] = (
            self.height +
            1) * self.frameWallThickness + self.height * self.quadrantSize
        self._data['originX'] = int(self._data['width'] / 2)
        self._data['originY'] = int(self._data['height'] / 2)
        collisionTable = []
        horizontalWall = [1 for x in range(self._data['width'])]
        collisionTable.append(horizontalWall)
        for i in range(0, len(self.quadrantData), self.width):
            for y in range(self.quadrantSize):
                row = [1]
                for x in range(i, i + self.width):
                    if x == 1 and y < self.quadrantSize / 2 - 2:
                        newData = []
                        for j in self.quadrantData[x][1][y]:
                            if j == 0:
                                newData.append(2)
                            else:
                                newData.append(j + 0)

                        row += newData + [1]
                    else:
                        row += self.quadrantData[x][1][y] + [1]

                collisionTable.append(row)

            collisionTable.append(horizontalWall[:])

        barriers = Globals.MazeBarriers
        for i in range(len(barriers)):
            for coords in barriers[i]:
                collisionTable[coords[1]][coords[0]] = 0

        y = self._data['originY']
        for x in range(len(collisionTable[y])):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        x = self._data['originX']
        for y in range(len(collisionTable)):
            if collisionTable[y][x] == 0:
                collisionTable[y][x] = 2

        self._data['collisionTable'] = collisionTable

    def _loadAndBuildMazeModel(self, flatten=False):
        self.getMazeData()
        self._model = NodePath('CogdoMazeModel')
        levelModel = CogdoUtil.loadMazeModel('level')
        self.quadrants = []
        quadrantUnitSize = int(self.quadrantSize * self.cellWidth)
        frameActualSize = self.frameWallThickness * self.cellWidth
        size = quadrantUnitSize + frameActualSize
        halfWidth = int(self.width / 2)
        halfHeight = int(self.height / 2)
        i = 0
        for y in range(self.height):
            for x in range(self.width):
                ax = (x - halfWidth) * size
                ay = (y - halfHeight) * size
                extension = ''
                if hasattr(getBase(), 'air'):
                    extension = '.bam'
                filepath = self.quadrantData[i][0] + extension
                angle = self.quadrantData[i][2]
                m = self._createQuadrant(filepath, i, angle, quadrantUnitSize)
                m.setPos(ax, ay, 0)
                m.reparentTo(self._model)
                self.quadrants.append(m)
                i += 1

        quadrantHalfUnitSize = quadrantUnitSize * 0.5
        barrierModel = CogdoUtil.loadMazeModel('grouping_blockerDivider').find(
            '**/divider')
        y = 3
        for x in range(self.width):
            if x == (self.width - 1) / 2:
                continue
            ax = (x - halfWidth) * size
            ay = (y - halfHeight) * size - quadrantHalfUnitSize - (
                self.cellWidth - 0.5)
            b = NodePath('barrier')
            barrierModel.instanceTo(b)
            b.setPos(ax, ay, 0)
            b.reparentTo(self._model)

        offset = self.cellWidth - 0.5
        for x in (0, 3):
            for y in range(self.height):
                ax = (
                    x - halfWidth
                ) * size - quadrantHalfUnitSize - frameActualSize + offset
                ay = (y - halfHeight) * size
                b = NodePath('barrier')
                barrierModel.instanceTo(b)
                b.setPos(ax, ay, 0)
                b.setH(90)
                b.reparentTo(self._model)

            offset -= 2.0

        barrierModel.removeNode()
        levelModel.getChildren().reparentTo(self._model)
        for np in self._model.findAllMatches('**/*lightCone*'):
            CogdoUtil.initializeLightCone(np, 'fixed', 3)

        if flatten:
            self._model.flattenStrong()
        return self._model

    def _createQuadrant(self, filepath, serialNum, angle, size):
        root = NodePath('QuadrantRoot-%i' % serialNum)
        quadrant = loader.loadModel(filepath)
        quadrant.getChildren().reparentTo(root)
        root.setH(angle)
        return root