def __init__(self): self.is_running = False self.screen = pygame.display.set_mode(config.SCREEN_SIZE, pygame.RESIZABLE) self.world = World() self.player = Player()
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()
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)
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)
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)
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()
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)