コード例 #1
0
ファイル: Game.py プロジェクト: JoepDriesen/Township
 def __init__(self):
     self.is_running = False
     
     self.screen = pygame.display.set_mode(config.SCREEN_SIZE, pygame.RESIZABLE)
     
     self.world = World()
     self.player = Player()
コード例 #2
0
ファイル: Game.py プロジェクト: JoepDriesen/Township
class Game(object):
    
    def __init__(self):
        self.is_running = False
        
        self.screen = pygame.display.set_mode(config.SCREEN_SIZE, pygame.RESIZABLE)
        
        self.world = World()
        self.player = Player()
        
    
    
    def handle_input(self):
        pass
    
    def update(self, dt):
        self.world.update(dt=dt)
        self.player.update(dt=dt)
    
    def render(self, surface):
        pass
    
    
    
    def run(self, debug=True, profile=True):
        """ 
        Run the game loop
        
        """
        clock = pygame.time.Clock()
        fps = 60
        playtime = 0
        
        self.running = True
        
        if profile:
            import time
            idles, inputs, updates, renders, nidles = [], [], [], [], []
            avg_len = 60

        while self.running:
            if profile:
                t_0 = time.clock()
                
            dt = clock.tick(fps) / 1000.
            playtime += dt
            
            if profile:
                t_idle = time.clock()
                dt_idle = t_idle - t_0
                idles.append(dt_idle)
            
            self.handle_input()
            if profile:
                t_input = time.clock()
                dt_input = t_input - t_idle
                inputs.append(dt_input)
            
            self.update(dt)
            if profile:
                t_update = time.clock()
                dt_update = t_update - t_input
                updates.append(dt_update)
                
            self.render(self.screen)
            if profile:
                t_render = time.clock()
                dt_render = t_render - t_update
                renders.append(dt_render)
                nidles.append(dt_input + dt_update + dt_render)
            
            if debug:
                caption = 'FPS: {: >2.2f}        Playtime: {: >10.2f}s'.format(clock.get_fps(), playtime)
                
            if profile:
                if len(idles) > avg_len:
                    idles.pop(0)
                    nidles.pop(0)
                    inputs.pop(0)
                    updates.pop(0)
                    renders.pop(0)
                
                if debug:
                    caption += '        '
                
                idle_avg = sum(idles) / avg_len
                nidle_avg = sum(nidles) / avg_len
                input_avg = sum(inputs) / avg_len
                update_avg = sum(updates) / avg_len
                render_avg = sum(renders) / avg_len
                caption += 'Idle: {: >3.0f}%        i: {: >5.0f}µs    |    u: {: >5.0f}µs    |    r: {: >5.0f}µs'.format(100 * (idle_avg / (idle_avg + nidle_avg)), 1000000 * input_avg, 1000000 * update_avg, 1000000 * render_avg)
            
            if debug or profile: 
                pygame.display.set_caption(caption)

            pygame.display.flip()
コード例 #3
0
ファイル: Tatch.py プロジェクト: gabrieljw1/Tatch
    def __init__(self, width=1080, height=720):
        # Tkinter initialization
        super().__init__()

        if winsoundAvailable:
            winsound.PlaySound(
                "tatchwave.wav",
                winsound.SND_LOOP + winsound.SND_ASYNC | winsound.SND_ALIAS)

        ### User customization

        # User View Variables
        self.fieldOfView = 90
        self.clippingPlanes = (0.1, 100)
        self.originVector = Vector(0, -14, 0)
        self.terrainDims = (54, 29)
        self.terrainScale = 6.4
        self.terrainOffsetVector = Vector(0, 0, 12)
        self.terrainSpread = 1.8

        # User Gameplay Variables
        self.targetFPS = 30
        self.movementSpeed = 1.0
        self.backgroundColor = "black"
        self.terrainColor = "white"
        self.enemyColor = "red"
        self.projectileColor = "green"
        self.playerShootTimeout = 50
        self.enemySpawnDelay = 450
        self.enemyShootDelay = 400
        self.maxEntityCount = 10

        self.ammoRegenDelay = 450
        self.shieldRegenDelay = 1250
        self.ammoRegenAmount = 1
        self.shieldRegenAmount = 5

        self.initAmmoCount = 5
        self.initHealthPoints = 100
        self.initShieldPoints = 60
        self.playerHitboxRadius = 5

        self.projectileHitboxRadius = 0.75
        self.projectileSpeed = 4
        self.playerProjectileDamage = 20
        self.enemyProjectileDamage = 14

        self.scoreIncrement = 100

        ### Game variables

        # Set the instance variables
        self.width = width
        self.height = height

        # Game state
        self.paused = False
        self.gameIsOver = False
        self.keysPressed = set()
        self.score = 0
        self.ammoCount = self.initAmmoCount
        self.healthPoints = self.initHealthPoints
        self.shieldPoints = self.initShieldPoints
        self.updateTerrain = True
        self.queueProjectileLaunch = False

        # Timing
        self.frameBufferTime = 25
        self.timerDelay = 1000 // self.targetFPS
        self.enemySpawnTimer = self.enemySpawnDelay  # Spawn instantly
        self.enemyShootTimer = 0
        self.playerShootTimer = 0
        self.ammoRegenTimer = 0
        self.shieldRegenTimer = 0

        # Drawing, terrain movement, entities
        self.terrainLineIdsList = []
        self.hitboxLineIdsList = []
        self.zStep, self.xStep = 0.0, 0.0
        self.xShift, self.zShift = 0.0, 0.0
        self.entities = []

        # Overlay specifications and state
        self.overlayMargin = 10
        self.overlayPauseSize = min(self.width // 20, self.height // 20)
        self.overlayPauseSizeSelectionModifier = 1.4
        self.overlayPauseSelected = False

        ### Operations

        # Create the frame, set window pos, set background color, set resizeable
        self.tatchFrame = TatchFrame(self, self.width, self.height)
        self.geometry(str(self.width) + "x" + str(self.height) + "+0+0")
        self.tatchFrame.tatchCanvas.config(background=self.backgroundColor)
        self.resizable(False, False)

        # Create the necessary game objects
        self.world = World((self.width, self.height), self.fieldOfView,
                           self.clippingPlanes, self.originVector,
                           self.terrainDims, self.terrainScale,
                           self.terrainOffsetVector, self.terrainSpread)
        self.overlay = Overlay(self.width, self.height,
                               self.tatchFrame.tatchCanvas, self.overlayMargin,
                               self.overlayPauseSize,
                               self.overlayPauseSizeSelectionModifier,
                               self.initHealthPoints, self.initShieldPoints,
                               self.initAmmoCount)

        # Bind keyPress/mouse events to their respective functions
        self.bind("<KeyPress>", self.keyDown)
        self.bind("<KeyRelease>", self.keyUp)
        self.bind("<Motion>", self.mouseMoved)
        self.bind("<Button>", self.mousePressed)

        # Bind window events
        self.protocol("WM_DELETE_WINDOW", self.closeWindow)

        # Create the player entity and spawn the first entity
        self.playerPosition = Vector(self.originVector.x,
                                     self.originVector.y / 4,
                                     self.originVector.z)
        self.playerEntity = self.generateEntity(self.playerPosition,
                                                self.playerHitboxRadius)
コード例 #4
0
ファイル: Tatch.py プロジェクト: gabrieljw1/Tatch
class Tatch(tk.Tk):
    def __init__(self, width=1080, height=720):
        # Tkinter initialization
        super().__init__()

        if winsoundAvailable:
            winsound.PlaySound(
                "tatchwave.wav",
                winsound.SND_LOOP + winsound.SND_ASYNC | winsound.SND_ALIAS)

        ### User customization

        # User View Variables
        self.fieldOfView = 90
        self.clippingPlanes = (0.1, 100)
        self.originVector = Vector(0, -14, 0)
        self.terrainDims = (54, 29)
        self.terrainScale = 6.4
        self.terrainOffsetVector = Vector(0, 0, 12)
        self.terrainSpread = 1.8

        # User Gameplay Variables
        self.targetFPS = 30
        self.movementSpeed = 1.0
        self.backgroundColor = "black"
        self.terrainColor = "white"
        self.enemyColor = "red"
        self.projectileColor = "green"
        self.playerShootTimeout = 50
        self.enemySpawnDelay = 450
        self.enemyShootDelay = 400
        self.maxEntityCount = 10

        self.ammoRegenDelay = 450
        self.shieldRegenDelay = 1250
        self.ammoRegenAmount = 1
        self.shieldRegenAmount = 5

        self.initAmmoCount = 5
        self.initHealthPoints = 100
        self.initShieldPoints = 60
        self.playerHitboxRadius = 5

        self.projectileHitboxRadius = 0.75
        self.projectileSpeed = 4
        self.playerProjectileDamage = 20
        self.enemyProjectileDamage = 14

        self.scoreIncrement = 100

        ### Game variables

        # Set the instance variables
        self.width = width
        self.height = height

        # Game state
        self.paused = False
        self.gameIsOver = False
        self.keysPressed = set()
        self.score = 0
        self.ammoCount = self.initAmmoCount
        self.healthPoints = self.initHealthPoints
        self.shieldPoints = self.initShieldPoints
        self.updateTerrain = True
        self.queueProjectileLaunch = False

        # Timing
        self.frameBufferTime = 25
        self.timerDelay = 1000 // self.targetFPS
        self.enemySpawnTimer = self.enemySpawnDelay  # Spawn instantly
        self.enemyShootTimer = 0
        self.playerShootTimer = 0
        self.ammoRegenTimer = 0
        self.shieldRegenTimer = 0

        # Drawing, terrain movement, entities
        self.terrainLineIdsList = []
        self.hitboxLineIdsList = []
        self.zStep, self.xStep = 0.0, 0.0
        self.xShift, self.zShift = 0.0, 0.0
        self.entities = []

        # Overlay specifications and state
        self.overlayMargin = 10
        self.overlayPauseSize = min(self.width // 20, self.height // 20)
        self.overlayPauseSizeSelectionModifier = 1.4
        self.overlayPauseSelected = False

        ### Operations

        # Create the frame, set window pos, set background color, set resizeable
        self.tatchFrame = TatchFrame(self, self.width, self.height)
        self.geometry(str(self.width) + "x" + str(self.height) + "+0+0")
        self.tatchFrame.tatchCanvas.config(background=self.backgroundColor)
        self.resizable(False, False)

        # Create the necessary game objects
        self.world = World((self.width, self.height), self.fieldOfView,
                           self.clippingPlanes, self.originVector,
                           self.terrainDims, self.terrainScale,
                           self.terrainOffsetVector, self.terrainSpread)
        self.overlay = Overlay(self.width, self.height,
                               self.tatchFrame.tatchCanvas, self.overlayMargin,
                               self.overlayPauseSize,
                               self.overlayPauseSizeSelectionModifier,
                               self.initHealthPoints, self.initShieldPoints,
                               self.initAmmoCount)

        # Bind keyPress/mouse events to their respective functions
        self.bind("<KeyPress>", self.keyDown)
        self.bind("<KeyRelease>", self.keyUp)
        self.bind("<Motion>", self.mouseMoved)
        self.bind("<Button>", self.mousePressed)

        # Bind window events
        self.protocol("WM_DELETE_WINDOW", self.closeWindow)

        # Create the player entity and spawn the first entity
        self.playerPosition = Vector(self.originVector.x,
                                     self.originVector.y / 4,
                                     self.originVector.z)
        self.playerEntity = self.generateEntity(self.playerPosition,
                                                self.playerHitboxRadius)

    ######
    # Entity Generation (Entity, Projectile, Enemy)
    ######

    # Generate an entity at a given position and hitbox radius.
    def generateEntity(self, positionVector, hitboxRadius):
        # Generate the entity-to-world transformation matrix
        entityAxes = [
            positionVector, self.world.axes[1], self.world.axes[2],
            self.world.axes[3]
        ]
        entityMatrix = Entity.generateEntityToWorldMatrix(entityAxes)

        # Define the hitbox vectors in $Object$ coordinates
        hitboxVectors = [Vector(-hitboxRadius, -hitboxRadius, -hitboxRadius),\
                         Vector(+hitboxRadius, +hitboxRadius, +hitboxRadius)]

        return Entity(entityMatrix, hitboxVectors)

    # Spawn an enemy at a given position and with given attributes
    def spawnEnemy(self,
                   positionVector,
                   hitboxRadius=5,
                   health=100,
                   projectileStrength=10):
        # Generate the entity-to-world transformation matrix
        enemyAxes = [
            positionVector, self.world.axes[1], self.world.axes[2],
            self.world.axes[3]
        ]
        enemyMatrix = Entity.generateEntityToWorldMatrix(enemyAxes)

        # Define the hitbox vectors in $Object$ coordinates
        hitboxVectors = [Vector(-hitboxRadius, -hitboxRadius, -hitboxRadius),\
                         Vector(+hitboxRadius, +hitboxRadius, +hitboxRadius)]

        self.entities.append(
            Enemy(enemyMatrix, hitboxVectors, health, projectileStrength))

    # Launch a projectile
    def launchProjectile(self,
                         positionVector,
                         velocityVector,
                         hitboxRadius,
                         damage,
                         launchedByEnemy=False):
        # Generate the projectile-to-world transformation matrix
        projectileAxes = [
            positionVector, self.world.axes[1], self.world.axes[2],
            self.world.axes[3]
        ]
        projectileMatrix = Entity.generateEntityToWorldMatrix(projectileAxes)

        # Define the hitbox vectors in $Object$ coordinates
        hitboxVectors = [Vector(-hitboxRadius, -hitboxRadius, -hitboxRadius),\
                         Vector(+hitboxRadius, +hitboxRadius, +hitboxRadius)]

        self.entities.append(
            Projectile(projectileMatrix, hitboxVectors, velocityVector, damage,
                       launchedByEnemy))

    # Launch a projectile from another Entity towards the player
    def launchProjectileFromEnemy(self, enemyEntity, hitboxRadius,
                                  velocityMagnitude, damage):
        # Get the velocity vector required to hit the player from the entity's
        #   position.
        velocityVector = Vector.getVelocityFromPointToPoint(
            enemyEntity.getPosition(), self.playerPosition, velocityMagnitude)

        self.launchProjectile(enemyEntity.getPosition(), velocityVector,
                              hitboxRadius, damage, True)

    ######
    # Terrain Movement
    ######

    # Shift the terrain over the X-Z (horizontal) plane and save it in the cache
    def shiftTerrain(self, dx, dz):
        self.xShift += dx
        self.zShift += dz

        self.world.setTerrainCache(self.world.terrainOffsetVector, self.xShift,
                                   self.zShift)

    ######
    # View Drawing
    ######

    # Clear the terrain lines then redraw from the terrain cache in the world
    def drawTerrain(self):
        self.tatchFrame.clearTerrainLines(self.terrainLineIdsList)
        self.terrainLineIdsList = self.tatchFrame.drawTerrainFromVectors(
            self.world.terrainCache, self.terrainColor)

    def drawEntityHitboxes(self):
        # Clear all hitboxes on the canvas
        self.tatchFrame.clearTerrainLines(self.hitboxLineIdsList)

        hitboxLineIdsList = []

        for entity in self.entities:
            if entity.visible:
                if (isinstance(entity, Enemy)):
                    color = self.enemyColor
                else:
                    color = self.projectileColor

                rasterPoints = self.world.generateRaster(
                    entity.getWorldHitboxVertexVectors())

                hitboxLineIdsList.extend(
                    self.tatchFrame.drawCube(rasterPoints, color))

        self.hitboxLineIdsList = hitboxLineIdsList

    # Draw all objects
    def drawAll(self,
                drawTerrain=False,
                drawHitboxes=False,
                drawOverlay=False):
        if drawTerrain:
            self.drawTerrain()

        if drawHitboxes:
            self.drawEntityHitboxes()

        if drawOverlay:
            self.overlay.redrawOverlay(self.overlayPauseSelected,
                                       self.healthPoints, self.shieldPoints,
                                       self.ammoCount, self.score, self.paused,
                                       self.gameIsOver)

    ######
    # User Interaction
    ######

    def positionInsidePauseButton(self, x, y):
        return (self.width - self.overlayMargin - self.overlayPauseSize <= x \
                and x <= self.width - self.overlayMargin\
                and self.overlayMargin <= y\
                and y <= self.overlayMargin + self.overlayPauseSize)

    def mouseMoved(self, event):
        self.overlayPauseSelected = self.positionInsidePauseButton(
            event.x, event.y)

    def mousePressed(self, event):
        if self.overlayPauseSelected and not self.gameIsOver:
            self.pause()

    def keyDown(self, event):
        if (not self.gameIsOver):
            if (event.char == "\x1b"):  # Escape
                self.pause()
            elif (event.char == " "):  # Space
                self.queueProjectileLaunch = True
            else:
                self.keysPressed.add(event.char)
        else:
            if (event.char in ["\x1b", " "]):
                self.restartGame()

    def keyUp(self, event):
        if (event.char in self.keysPressed):
            self.keysPressed.remove(event.char)

    ######
    # Game State
    ######

    def pause(self):
        self.paused = not self.paused

    def playerHit(self, power):
        if (self.shieldPoints > 0):
            self.shieldPoints -= power

            if (self.shieldPoints < 0):
                self.shieldPoints = 0
        else:
            self.healthPoints -= power

            if (self.healthPoints < 0):
                self.healthPoints = 0

        if (self.healthPoints <= 0):
            self.gameIsOver = True

    def gameOver(self):
        self.paused = False
        self.gameIsOver = True

    def restartGame(self):
        self.tatchFrame.clearTerrainLines(self.terrainLineIdsList)
        self.tatchFrame.clearTerrainLines(self.hitboxLineIdsList)

        self.keysPressed = set()
        self.score = 0
        self.ammoCount = self.initAmmoCount
        self.healthPoints = self.initHealthPoints
        self.shieldPoints = self.initShieldPoints
        self.updateTerrain = True
        self.queueProjectileLaunch = False

        self.terrainLineIdsList = []
        self.hitboxLineIdsList = []
        self.zStep, self.xStep = 0.0, 0.0
        self.xShift, self.zShift = 0.0, 0.0
        self.entities = []

        self.paused = False
        self.gameIsOver = False

    def closeWindow(self):
        self.gameIsOver = True
        winsound.PlaySound(None, winsound.SND_ASYNC)
        self.destroy()

    ######
    # Game Loop and Timing
    ######

    def updateTimers(self, timeShift):
        self.enemySpawnTimer += timeShift
        self.enemyShootTimer += timeShift
        self.playerShootTimer += timeShift
        self.ammoRegenTimer += timeShift
        self.shieldRegenTimer += timeShift

    def gameLoop(self):
        timeStartGameLoop = time.time()

        if "w" in self.keysPressed:
            self.zStep = +self.movementSpeed
        elif "s" in self.keysPressed:
            self.zStep = -self.movementSpeed
        else:
            self.zStep = 0

        if "a" in self.keysPressed:
            self.xStep = +self.movementSpeed
        elif "d" in self.keysPressed:
            self.xStep = -self.movementSpeed
        else:
            self.xStep = 0

        if not self.paused and not self.gameIsOver:
            (nearClip, farClip) = self.clippingPlanes

            # Move terrain
            if (self.xStep != 0 or self.zStep != 0):
                self.shiftTerrain(self.xStep, self.zStep)

                self.updateTerrain = True

            # Launch projectile
            if (self.queueProjectileLaunch
                    and self.playerShootTimer >= self.playerShootTimeout
                    and self.ammoCount > 0):
                self.launchProjectile(self.playerPosition,
                                      Vector(0, 0, -self.projectileSpeed),
                                      self.projectileHitboxRadius,
                                      self.playerProjectileDamage)
                self.ammoCount -= 1
                self.playerShootTimer = 0
            elif self.queueProjectileLaunch:
                self.queueProjectileLaunch = False

            # Spawn another enemy if the timer is done
            if (self.enemySpawnTimer >
                (len(self.entities)**0.4) * self.enemySpawnDelay
                    and len(self.entities) <= self.maxEntityCount):
                self.spawnEnemy(
                    Vector(random.randint(-30, 30), 0,
                           random.randint(-80, -35)))
                self.enemySpawnTimer = 0

            # Ammo regen
            if (self.ammoRegenTimer > self.ammoRegenDelay):
                self.ammoCount += self.ammoRegenAmount
                self.ammoRegenTimer = 0

                self.ammoCount = min(self.initAmmoCount, self.ammoCount)

            # Shield regen
            if (self.shieldRegenTimer > self.shieldRegenDelay
                    and self.shieldPoints > 0):
                self.shieldPoints += self.shieldRegenAmount
                self.shieldRegenTimer = 0

                self.shieldPoints = min(self.initShieldPoints,
                                        self.shieldPoints)

            for entity in self.entities:
                entityVelocity = entity.velocityVector
                entity.translate(entityVelocity.x - self.xStep,
                                 entityVelocity.y,
                                 entityVelocity.z + self.zStep)

                if (abs(entity.entityToWorldMatrix.values[3][2]) >
                        2 * farClip):  # Despawn condition
                    self.entities.remove(entity)
                elif (abs(entity.entityToWorldMatrix.values[3][2] > farClip)
                      ):  # Not visible condition
                    entity.visible = False
                elif not entity.visible:
                    entity.visible = True

                # Shoot on time if an enemy. If projectile, check collisions
                if isinstance(entity, Enemy):
                    if self.enemyShootTimer > self.enemyShootDelay:
                        self.launchProjectileFromEnemy(
                            entity, self.projectileHitboxRadius,
                            self.projectileSpeed, self.enemyProjectileDamage)
                        self.enemyShootTimer = 0
                else:
                    for otherEntity in self.entities:
                        if (entity != otherEntity
                                and not isinstance(otherEntity, Projectile)):
                            if entity.spawnedByEnemy:
                                if entity.collidesWith(
                                        self.playerEntity
                                ) or self.playerEntity.collidesWith(entity):
                                    self.playerHit(entity.strength)

                                    if entity in self.entities:
                                        self.entities.remove(entity)
                            else:
                                if entity.collidesWith(
                                        otherEntity
                                ) or otherEntity.collidesWith(entity):
                                    if (otherEntity in self.entities):
                                        self.entities.remove(otherEntity)

                                    if (entity in self.entities):
                                        self.entities.remove(entity)

                                    self.score += self.scoreIncrement

        # Draw with new information
        self.drawAll(drawTerrain=self.updateTerrain,
                     drawHitboxes=not self.paused and not self.gameIsOver,
                     drawOverlay=True)
        self.updateTerrain = False

        timeEndGameLoop = time.time()

        timeElapsedGameLoop = timeEndGameLoop - timeStartGameLoop

        # This is necessary just in case the game lags. If the game loop takes
        #   longer than the timer delay, then python will pin the CPU usage at
        #   100 unless a small buffer is added.
        if (timeElapsedGameLoop >= self.timerDelay):
            self.updateTimers(timeElapsedGameLoop + self.frameBufferTime)
            self.after(timeElapsedGameLoop + self.frameBufferTime,
                       self.gameLoop)
        else:
            self.updateTimers(self.timerDelay)
            self.after(self.timerDelay, self.gameLoop)
コード例 #5
0
ファイル: GameEngine.py プロジェクト: Archangelgray/fofix
 def startWorld(self, players, maxplayers = None, gameMode = 0, multiMode = 0, allowGuitar = True, allowDrum = True, allowMic = False, tutorial = False):
     self.world = World(self, players, maxplayers, gameMode, multiMode, allowGuitar, allowDrum, allowMic, tutorial)
コード例 #6
0
ファイル: GameEngine.py プロジェクト: Archangelgray/fofix
class GameEngine(object):
    """The main game engine."""
    def __init__(self, config = None):

        Log.debug("GameEngine class init (GameEngine.py)...")
        self.mainMenu = None    #placeholder for main menu object - to prevent reinstantiation

        self.currentScene = None

        self.versionString = version  #stump: other version stuff moved to allow full version string to be retrieved without instantiating GameEngine
        self.uploadVersion = "%s-4.0" % Version.PROGRAM_NAME #akedrou - the version passed to the upload site.

        self.dataPath = Version.dataPath()
        Log.debug(self.versionString + " starting up...")
        Log.debug("Python version: " + sys.version.split(' ')[0])
        Log.debug("Pygame version: " + str(pygame.version.ver) )
        Log.debug("PyOpenGL version: " + OpenGL.__version__)
        Log.debug("Numpy version: " + np.__version__)
        Log.debug("PIL version: " + Image.VERSION)
        Log.debug("sys.argv: " + repr(sys.argv))
        Log.debug("os.name: " + os.name)
        Log.debug("sys.platform: " + sys.platform)
        if os.name == 'nt':
            import win32api
            Log.debug("win32api.GetVersionEx(1): " + repr(win32api.GetVersionEx(1)))
        elif os.name == 'posix':
            Log.debug("os.uname(): " + repr(os.uname()))

        """
        Constructor.
        @param config:  L{Config} instance for settings
        """

        self.tutorialFolder = "tutorials"

        if not config:
            config = Config.load()

        self.config  = config

        fps          = self.config.get("video", "fps")

        self.tasks = []
        self.frameTasks = []
        self.fps = fps
        self.currentTask = None
        self.paused = []
        self.running = True
        self.clock = pygame.time.Clock()

        self.title             = self.versionString
        self.restartRequested  = False

        # evilynux - Check if theme icon exists first, then fallback on FoFiX icon.
        themename = self.config.get("coffee", "themename")
        themeicon = os.path.join(Version.dataPath(), "themes", themename, "icon.png")
        fofixicon = os.path.join(Version.dataPath(), "fofix_icon.png")
        icon = None
        if os.path.exists(themeicon):
            icon = themeicon
        elif os.path.exists(fofixicon):
            icon = fofixicon

        self.video             = Video(self.title, icon)
        if self.config.get("video", "disable_screensaver"):
            self.video.disableScreensaver()

        self.audio             = Audio()
        self.frames            = 0
        self.fpsEstimate       = 0
        self.priority          = self.config.get("engine", "highpriority")
        self.show_fps          = self.config.get("video", "show_fps")
        self.advSettings       = self.config.get("game", "adv_settings")
        self.restartRequired   = False
        self.quicksetRestart   = False
        self.quicksetPerf      = self.config.get("quickset", "performance")
        self.scrollRate        = self.config.get("game", "scroll_rate")
        self.scrollDelay       = self.config.get("game", "scroll_delay")

        Log.debug("Initializing audio.")
        frequency    = self.config.get("audio", "frequency")
        bits         = self.config.get("audio", "bits")
        stereo       = self.config.get("audio", "stereo")
        bufferSize   = self.config.get("audio", "buffersize")
        self.audio.open(frequency = frequency, bits = bits, stereo = stereo, bufferSize = bufferSize)

        self.cmdPlay           = 0
        self.cmdMode           = None
        self.cmdDiff           = None
        self.cmdPart           = None

        self.gameStarted       = False
        self.world             = None

        self.audioSpeedFactor  = 1.0

        Log.debug("Initializing video.")
        #myfingershurt: ensuring windowed mode starts up in center of the screen instead of cascading positions:
        os.environ['SDL_VIDEO_WINDOW_POS'] = 'center'

        width, height = [int(s) for s in self.config.get("video", "resolution").split("x")]
        fullscreen    = self.config.get("video", "fullscreen")
        multisamples  = self.config.get("video", "multisamples")
        self.video.setMode((width, height), fullscreen = fullscreen, multisamples = multisamples)
        Log.debug("OpenGL version: " + glGetString(GL_VERSION))
        Log.debug("OpenGL vendor: " + glGetString(GL_VENDOR))
        Log.debug("OpenGL renderer: " + glGetString(GL_RENDERER))
        Log.debug("OpenGL extensions: " + ' '.join(sorted(glGetString(GL_EXTENSIONS).split())))

        if self.video.default:
            self.config.set("video", "fullscreen", False)
            self.config.set("video", "resolution", "800x600")

        if self.config.get("video", "shader_use"):
            shaders.set(os.path.join(Version.dataPath(), "shaders"))

        # Enable the high priority timer if configured
        if self.priority:
            Log.debug("Enabling high priority timer.")
            self.fps = 0 # High priority

        # evilynux - This was generating an error on the first pass (at least under
        #            GNU/Linux) as the Viewport was not set yet.
        try:
            viewport = glGetIntegerv(GL_VIEWPORT)
        except:
            viewport = [0, 0, width, height]
        h = viewport[3] - viewport[1]
        w = viewport[2] - viewport[0]
        geometry = (0, 0, w, h)
        self.svg = SvgContext(geometry)
        glViewport(int(viewport[0]), int(viewport[1]), int(viewport[2]), int(viewport[3]))

        self.startupMessages   = self.video.error
        self.input     = Input()
        self.view      = View(self, geometry)
        self.resizeScreen(w, h)

        self.resource  = Resource(Version.dataPath())
        self.mainloop  = self.loading
        self.menuMusic = False

        self.setlistMsg = None


        # Load game modifications
        Mod.init(self)
        self.addTask(self.input, synchronized = False)

        self.addTask(self.view, synchronized = False)

        self.addTask(self.resource, synchronized = False)

        self.data = Data(self.resource, self.svg)

        ##MFH: Animated stage folder selection option
        #<themename>\Stages still contains the backgrounds for when stage rotation is off, and practice.png
        #subfolders under Stages\ will each be treated as a separate animated stage set

        self.stageFolders = []
        currentTheme = themename

        stagespath = os.path.join(Version.dataPath(), "themes", currentTheme, "backgrounds")
        themepath  = os.path.join(Version.dataPath(), "themes", currentTheme)
        if os.path.exists(stagespath):
            self.stageFolders = []
            allFolders = os.listdir(stagespath)   #this also includes all the stage files - so check to see if there is at least one .png file inside each folder to be sure it's an animated stage folder
            for name in allFolders:
                aniStageFolderListing = []
                thisIsAnAnimatedStageFolder = False
                try:
                    aniStageFolderListing = os.listdir(os.path.join(stagespath,name))
                except Exception:
                    thisIsAnAnimatedStageFolder = False
                for aniFile in aniStageFolderListing:
                    if os.path.splitext(aniFile)[1] == ".png" or os.path.splitext(aniFile)[1] ==  ".jpg" or os.path.splitext(aniFile)[1] == ".jpeg":  #we've found at least one .png file here, chances are this is a valid animated stage folder
                        thisIsAnAnimatedStageFolder = True
                if thisIsAnAnimatedStageFolder:
                    self.stageFolders.append(name)


            i = len(self.stageFolders)
            if i > 0: #only set default to first animated subfolder if one exists - otherwise use Normal!
                defaultAniStage = str(self.stageFolders[0])
            else:
                defaultAniStage = "Normal"
            Log.debug("Default animated stage for " + currentTheme + " theme = " + defaultAniStage)
            aniStageOptions = dict([(str(self.stageFolders[n]),self.stageFolders[n]) for n in range(0, i)])
            aniStageOptions.update({"Normal":_("Slideshow")})
            if i > 1:   #only add Random setting if more than one animated stage exists
                aniStageOptions.update({"Random":_("Random")})
            Config.define("game", "animated_stage_folder", str, defaultAniStage, text = _("Animated Stage"), options = aniStageOptions )

            #MFH: here, need to track and check a new ini entry for last theme - so when theme changes we can re-default animated stage to first found
            lastTheme = self.config.get("game","last_theme")
            if lastTheme == "" or lastTheme != currentTheme:   #MFH - no last theme, and theme just changed:
                self.config.set("game","animated_stage_folder",defaultAniStage)   #force defaultAniStage
            self.config.set("game","last_theme",currentTheme)

            selectedAnimatedStage = self.config.get("game", "animated_stage_folder")
            if selectedAnimatedStage != "Normal" and selectedAnimatedStage != "Random":
                if not os.path.exists(os.path.join(stagespath,selectedAnimatedStage)):
                    Log.warn("Selected animated stage folder " + selectedAnimatedStage + " does not exist, forcing Normal.")
                    self.config.set("game","animated_stage_folder","Normal") #MFH: force "Standard" currently selected animated stage folder is invalid
        else:
            Config.define("game", "animated_stage_folder", str, "None", text = _("Animated Stage"), options = ["None",_("None")])
            Log.warn("No stages\ folder found, forcing None setting for Animated Stage.")
            self.config.set("game","animated_stage_folder", "None") #MFH: force "None" when Stages folder can't be found



        try:
            fp, pathname, description = imp.find_module("CustomTheme",[themepath])
            theme = imp.load_module("CustomTheme", fp, pathname, description)
            self.theme = theme.CustomTheme(themepath, themename)
        except ImportError:
            self.theme = Theme(themepath, themename)

        self.addTask(self.theme)


        self.input.addKeyListener(FullScreenSwitcher(self), priority = True)
        self.input.addSystemEventListener(SystemEventHandler(self))

        self.debugLayer         = None
        self.startupLayer       = None
        self.loadingScreenShown = False
        self.graphicMenuShown   = False

        Log.debug("Ready.")


    # evilynux - This stops the crowd cheers if they're still playing (issue 317).
    def quit(self):
        # evilynux - self.audio.close() crashes when we attempt to restart
        if not self.restartRequested:
            self.audio.close()
        Player.savePlayers()
        for t in list(self.tasks + self.frameTasks):
            self.removeTask(t)
        self.running = False

    def setStartupLayer(self, startupLayer):
        """
        Set the L{Layer} that will be shown when the all
        the resources have been loaded. See L{Data}

        @param startupLayer:    Startup L{Layer}
        """
        self.startupLayer = startupLayer

    def isDebugModeEnabled(self):
        return bool(self.debugLayer)

    def setDebugModeEnabled(self, enabled):
        """
        Show or hide the debug layer.

        @type enabled: bool
        """
        if enabled:
            self.debugLayer = DebugLayer(self)
        else:
            self.debugLayer = None

    def toggleFullscreen(self):
        """
        Toggle between fullscreen and windowed mode.

        @return: True on success
        """
        if not self.video.toggleFullscreen():
            # on windows, the fullscreen toggle kills our textures, se we must restart the whole game
            self.input.broadcastSystemEvent("restartRequested")
            self.config.set("video", "fullscreen", not self.video.fullscreen)
            return True
        self.config.set("video", "fullscreen", self.video.fullscreen)
        return True

    def restart(self):
        """Restart the game."""
        if not self.restartRequested:
            self.restartRequested = True
            self.input.broadcastSystemEvent("restartRequested")
        else:
            self.quit()

    def resizeScreen(self, width, height):
        """
        Resize the game screen.

        @param width:   New width in pixels
        @param height:  New height in pixels
        """
        self.view.setGeometry((0, 0, width, height))
        self.svg.setGeometry((0, 0, width, height))

    def startWorld(self, players, maxplayers = None, gameMode = 0, multiMode = 0, allowGuitar = True, allowDrum = True, allowMic = False, tutorial = False):
        self.world = World(self, players, maxplayers, gameMode, multiMode, allowGuitar, allowDrum, allowMic, tutorial)

    def finishGame(self):
        if not self.world:
            Log.notice("GameEngine.finishGame called before World created.")
            return
        self.world.finishGame()
        self.world = None
        self.gameStarted = False
        self.view.pushLayer(self.mainMenu)

    def loadImgDrawing(self, target, name, fileName, textureSize = None):
        """
        Load an SVG drawing synchronously.

        @param target:      An object that will own the drawing
        @param name:        The name of the attribute the drawing will be assigned to
        @param fileName:    The name of the file in the data directory
        @param textureSize: Either None or (x, y), in which case the file will
                            be rendered to an x by y texture
        @return:            L{ImgDrawing} instance
        """
        return self.data.loadImgDrawing(target, name, fileName, textureSize)

    #volshebnyi
    def drawStarScore(self, screenwidth, screenheight, xpos, ypos, stars, scale = None, horiz_spacing = 1.2, space = 1.0, hqStar = False, align = LEFT):
        minScale = 0.02
        w = screenwidth
        h = screenheight
        if not scale:
            scale = minScale
        elif scale < minScale:
            scale = minScale
        if self.data.fcStars and stars == 7:
            star = self.data.starFC
        else:
            star = self.data.starPerfect
        wide = scale * horiz_spacing
        if align == CENTER: #center - akedrou (simplifying the alignment...)
            xpos  -= (2 * wide)
        elif align == RIGHT: #right
            xpos  -= (4 * wide)
        if stars > 5:
            for j in range(5):

                if self.data.maskStars:
                    if self.data.theme == 2:
                        drawImage(star, scale = (scale,-scale), coord = (w*(xpos+wide*j)*space**4,h*ypos), color = (1, 1, 0, 1), stretched = KEEP_ASPECT | FIT_WIDTH)
                    else:
                        drawImage(star, scale = (scale,-scale), coord = (w*(xpos+wide*j)*space**4,h*ypos), color = (0, 1, 0, 1), stretched = KEEP_ASPECT | FIT_WIDTH)
                else:
                    drawImage(star, scale = (scale,-scale), coord = (w*(xpos+wide*j)*space**4,h*ypos), stretched = KEEP_ASPECT | FIT_WIDTH)
        else:
            for j in range(5):
                if j < stars:
                    if hqStar:
                        star = self.data.star4
                    else:
                        star = self.data.star2
                else:
                    if hqStar:
                        star = self.data.star3
                    else:
                        star = self.data.star1
                drawImage(star, scale = (scale,-scale), coord = (w*(xpos+wide*j)*space**4,h*ypos), stretched = KEEP_ASPECT | FIT_WIDTH)

    #glorandwarf: renamed to retrieve the path of the file
    def fileExists(self, fileName):
        return self.data.fileExists(fileName)

    def getPath(self, fileName):
        return self.data.getPath(fileName)

    def loading(self):
        """Loading state loop."""
        done = self.doRun()
        self.clearScreen()

        if self.data.essentialResourcesLoaded():
            if not self.loadingScreenShown:
                self.loadingScreenShown = True
                Dialogs.showLoadingScreen(self, self.data.resourcesLoaded)
                if self.startupLayer:
                    self.view.pushLayer(self.startupLayer)
                self.mainloop = self.main
            self.view.render()
        self.video.flip()
        return done

    def clearScreen(self):
        self.svg.clear(*self.theme.backgroundColor)

    def fadeScreen(self, v):
        """
        Fade the screen to a dark color to make whatever is on top easier to read.

        @param v: Visibility factor [0..1], 0 is fully visible
        """
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glEnable(GL_COLOR_MATERIAL)

        glBegin(GL_TRIANGLE_STRIP)
        glColor4f(0, 0, 0, .3 - v * .3)
        glVertex2f(0, 0)
        glColor4f(0, 0, 0, .3 - v * .3)
        glVertex2f(1, 0)
        glColor4f(0, 0, 0, .9 - v * .9)
        glVertex2f(0, 1)
        glColor4f(0, 0, 0, .9 - v * .9)
        glVertex2f(1, 1)
        glEnd()

    def addTask(self, task, synchronized = True):
        """
        Add a task to the engine.

        @param task:          L{Task} to add
        @type  synchronized:  bool
        @param synchronized:  If True, the task will be run with small
                              timesteps tied to the engine clock.
                              Otherwise the task will be run once per frame.
        """
        if synchronized:
            queue = self.tasks
        else:
            queue = self.frameTasks

        if not task in queue:
            queue.append(task)
            task.started()

    def removeTask(self, task):
        """
        Remove a task from the engine.

        @param task:    L{Task} to remove
        """
        queues = self._getTaskQueues(task)
        for q in queues:
            q.remove(task)
        if queues:
            task.stopped()

    def _getTaskQueues(self, task):
        queues = []
        for queue in [self.tasks, self.frameTasks]:
            if task in queue:
                queues.append(queue)
        return queues

    def pauseTask(self, task):
        """
        Pause a task.

        @param task:  L{Task} to pause
        """
        self.paused.append(task)

    def resumeTask(self, task):
        """
        Resume a paused task.

        @param task:  L{Task} to resume
        """
        self.paused.remove(task)

    def enableGarbageCollection(self, enabled):
        """
        Enable or disable garbage collection whenever a random garbage
        collection run would be undesirable. Disabling the garbage collector
        has the unfortunate side-effect that your memory usage will skyrocket.
        """
        if enabled:
            gc.enable()
        else:
            gc.disable()

    def collectGarbage(self):
        """
        Run a garbage collection run.
        """
        gc.collect()

    def _runTask(self, task, ticks = 0):
        if not task in self.paused:
            self.currentTask = task
            task.run(ticks)
            self.currentTask = None

    def main(self):
        """Main state loop."""
        done = self.doRun()
        self.clearScreen()
        self.view.render()
        if self.debugLayer:
            self.debugLayer.render(1.0, True)
        self.video.flip()
        # evilynux - Estimate the rendered frames per second.
        self.frames = self.frames+1
        # Estimate every 120 frames when highpriority is True.
        # Estimate every 2*config.fps when highpriority is False,
        # if you are on target, that should be every 2 seconds.
        if( not self.priority and self.frames == (self.fps << 1) ) or ( self.priority and self.frames == 120 ):
            self.fpsEstimate = self.clock.get_fps()
            # evilynux - Printing on the console with a frozen binary may cause a crash.
            if self.show_fps and not Version.isWindowsExe():
                print("%.2f fps" % self.fpsEstimate)
            self.frames = 0
        return done

    def doRun(self):
        """Run one cycle of the task scheduler engine."""
        if not self.frameTasks and not self.tasks:
            return False

        for task in self.frameTasks:
            self._runTask(task)
        tick = self.clock.get_time()
        for task in self.tasks:
            self._runTask(task, tick)
        self.clock.tick(self.fps)
        return True

    def run(self):
        return self.mainloop()
コード例 #7
0
 def __init__(self):
     self.map = Map(Map.MEDIUM)
     self.world = World(self.map)
     self.window = Window(self.world)
     self.inputHandler = InputHandler(self.world, self.window)