def play(): pygame.init() settings = Settings() window = pygame.display.set_mode((768, 672), 0, 32) # window's resolution screen = pygame.Surface( (settings.scr_width, settings.scr_height)) # real game's resolution pygame.display.set_caption("Mario") stats = GameStats() main_clock = pygame.time.Clock() cs = CreditsScreen(screen=window) go = GameoverScreen(screen=window) camera = Camera(screen=screen) sm = StageManager(screen=screen, settings=settings, stats=stats) hud = HUD(screen=window, settings=settings, stats=stats, stage_manager=sm) pc = Player(screen=screen, settings=settings, stats=stats, stage_manager=sm, camera=camera, hud=hud) sm.load_stage(stage=stats.current_stage, hud=hud) help_text = HelpText(screen=window, settings=settings) pygame.mouse.set_visible(False) # Main loop while True: # scale the game's resolution to window's resolution resized = pygame.transform.scale(screen, (768, 672)) window.blit(resized, (0, 0)) gf.check_inputs(player=pc) if stats.current_stage < stats.credits_stage and stats.current_stage != -1: camera.update(pc) if stats.current_stage != -1: gf.update_player(player=pc, platforms=sm.platforms, enemies=sm.enemies, warp_zones=sm.warp_zones, moving_platforms=sm.moving_platforms) sm.update(player=pc) # draw if stats.current_stage != -1: screen.fill(settings.bg_color) sm.draw(camera) pc.draw1() if stats.current_stage < stats.credits_stage and stats.current_stage != -1: hud.draw() if stats.current_stage == 1: help_text.draw(camera) elif stats.current_stage == stats.credits_stage: cs.draw() elif stats.current_stage == -1: go.draw() pygame.display.update() main_clock.tick(60)
class StateGame(Stete): generator = None unitManager = None running = True player = None HUD = None state_name = "GAME" delta_time_ticks = 0.0 delta_time_seconds = 0.0 obj_on_screen = [] def __init_screen_objects(self, resolution, screen): self.obj_on_screen = self.generator.create_objects() self.player = self.generator.get_spawned_player(START_POSITION, 100) self.unitManager = UnitManager(self.obj_on_screen, self.player, screen, resolution) self.HUD = HUD(screen, self.player) def __init__(self, resolution, name, screen): self.generator = ObjectsGenerator(screen, NUMBER_OF_ENEMIES, NUMBER_OF_OBSTACLES, Vector(resolution[0], resolution[1])) self.__init_screen_objects(resolution, screen) def draw(self): self.unitManager.draw() self.HUD.draw() def process_input(self, event): self.unitManager.process_input(event) self.HUD.process_event(event) def __calculate_delta_time(self): delta = pygame.time.get_ticks() - self.delta_time_ticks self.delta_time_ticks = delta self.delta_time_seconds = delta / 100000.0 def restart(self): return False def is_player_dead(self): return self.HUD.HP() == 0 def no_more_zombie(self): return len(self.unitManager.enemy_list) == 0 def update(self, delta): self.__calculate_delta_time() self.unitManager.process_physics(delta) self.HUD.update(delta)
class Game(object): modes = ['Waiting', 'In Play'] def __init__(self, fps=60, fullscreen=False): """ (int, int, int, bool) -> Game Instantiate Game object with expected properties of a tower defense game. """ pygame.init() # Parameter-based properties self.fps = fps self.fullscreen = fullscreen # Determine width and height self.screenW = pygame.display.list_modes()[0][0] self.screenH = pygame.display.list_modes()[0][1] if not self.fullscreen: self.screenW = floor(0.8 * self.screenW) self.screenH = floor(0.8 * self.screenH) # Display and framerate properties self.caption = GAME_NAME + ' - Left Mouse Button to select/place turret, drag by moving the mouse' self.displaySurf = None if self.fullscreen: self.flags = FULLSCREEN | DOUBLEBUF | HWACCEL else: self.flags = DOUBLEBUF | HWACCEL self.fpsClock = pygame.time.Clock() self.initializeDisplay() # Define and reset gameplay properties and objects self.money, self.wave, self.turrets, self.enemies, self.intersections, \ self.measuredFPS, self.tower, self.mode = [None] * 8 self.reset() # HUD object hudSize = 300 hudRect = pygame.Rect(self.screenW - hudSize, 0, hudSize, self.screenH) hudColour = GREY self.hud = HUD(hudRect, hudColour, Turret(), FourShotTurret(), GlueTurret(), FireTurret(), LongRange(), EightShotTurret()) # Collision-related properties self.pathRects = [] # Level appearance and elements self.intersectionSurface = pygame.Surface(self.displaySurf.get_size(), SRCALPHA | RLEACCEL, 32).convert_alpha() self.pathColour = ORANGE self.grassColour = LGREEN self.pathWidth = 50 # Mouse and events self.mouseX, self.mouseY = 0, 0 self.clicking = False self.dragging = False self.events = [] # Health increment self.healthIncrement = 1 # Menu object self.menu = Menu() # Background self.background = pygame.image.load(getDataFilepath(IMG_PATH_GRASS)).convert() self.pathImage = pygame.image.load(getDataFilepath(IMG_PATH_DIRT)).convert() # Sounds self.backgroundMusic = Sound(getDataFilepath('retro.wav'), True) self.hitSound = Sound(SOUND_PATH_SHOT, False) self.inPlay = True def reset(self, money=200, wave=1): """ ([int], [int]) -> None Reset money, wave number, and other similar game world properties. """ self.money = money self.wave = wave self.turrets = [] self.intersections = [] self.enemies = [] self.tower = Tower(IMG_PATH_TOWER, self.screenW / 2, self.screenH / 2) self.mode = self.modes[0] def incrementEnemyHealth(self, increment): for enemy in self.enemies: enemy.health *= increment def generateEnemies(self, x=1, separation=70): """ ([int], [int]) -> None Generate "x" number of enemies with the given separation for the tower defense game. """ # Return immediately if there are no intersections loaded. if not self.intersections: print('WARNING: Enemies not loaded! Intersections must be loaded first.') return # Clear the list of enemies to start with. self.enemies = [] # Gather information and create temporary variables. firstTurnX = self.intersections[0][0] firstTurnY = self.intersections[0][1] secondTurnX = self.intersections[1][0] secondTurnY = self.intersections[1][1] gap = x * separation xlist = [] ylist = [] direction = NODIR # Determine the starting direction and co-ordinate lists for the enemies. if firstTurnX == secondTurnX and firstTurnY > secondTurnY: xlist = [firstTurnX] ylist = xrange(firstTurnY, firstTurnY + gap, separation) direction = UP elif firstTurnX == secondTurnX: xlist = [firstTurnX] ylist = xrange(firstTurnY - gap, firstTurnY, separation) direction = DOWN elif firstTurnY == secondTurnY and firstTurnX > secondTurnX: xlist = xrange(firstTurnX, firstTurnX + gap, separation) ylist = [firstTurnY] direction = LEFT elif firstTurnY == secondTurnY: xlist = xrange(firstTurnX - gap, firstTurnX, separation) ylist = [firstTurnY] direction = RIGHT # Create enemies with the information determined above. w = Enemy(IMG_PATH_ENEMY1, 0, 0).w h = Enemy(IMG_PATH_ENEMY1, 0, 0).h assigned = False for x in xlist: for y in ylist: enemyType = random.randint(1, 5) if enemyType == 2 and not assigned: self.enemies.append(Enemy(IMG_PATH_ENEMY2, x - w // 2, y - h // 2, direction, 3, 200)) assigned = True elif enemyType == 3 and not assigned and self.wave >= 2: self.enemies.append(Enemy(IMG_PATH_ENEMY3, x - w // 2, y - h // 2, direction, 2, 300)) assigned = True elif enemyType == 4 and not assigned and self.wave >= 2: self.enemies.append(Plane(IMG_PATH_ENEMY4, x - w // 2, y - h // 2, direction, 6, 100)) assigned = True elif enemyType == 5 and not assigned and self.wave >= 10: self.enemies.append(HugeTank(IMG_PATH_ENEMY5, x - w // 2, y - h // 2, direction, 2, 500)) assigned = True else: self.enemies.append(Enemy(IMG_PATH_ENEMY1, x - w // 2, y - h // 2, direction, health=100)) assigned = True self.enemies[-1].setNextIntersection(self.intersections[0]) self.enemies[-1].initialDistanceFromWorld = distance((self.enemies[-1].x, self.enemies[-1].y), (firstTurnX, firstTurnY)) assigned = False if self.wave % 5 == 0: self.healthIncrement += 1 self.incrementEnemyHealth(self.healthIncrement) # Sort the list of enemies in terms of ascending distance away from the initial intersection. self.enemies.sort(key=lambda x: x.initialDistanceFromWorld) def makeStrSubstitutions(self, string): """ (str) -> str Return the input string but with human-readable keywords exchanged for co-ordinates and directions. """ substitutions = {'RIGHT': RIGHT, 'LEFT': LEFT, 'UP': UP, 'DOWN': DOWN, 'WIDTH': self.hud.left, 'HEIGHT': self.screenH} result = string[:] for word in string.split(): if word in substitutions: result = result.replace(word, str(substitutions[word])) return result def stretchIntersections(self): """ (None) -> None Stretch or compress intersection co-ordinates as necessary to fit them to screen. """ # Return immediately if there are no intersections if not self.intersections: return # Gather info about the needed scaling for horizontal and vertical co-ordinates of each intersection temp = self.intersections[:] temp.sort(key=lambda x: x[0]) horizontalStretch = (self.screenW - self.hud.width) / float(temp[-1][0] + self.pathWidth // 2) temp = self.intersections[:] temp.sort(key=lambda x: x[1]) verticalStretch = self.screenH / float(temp[-1][1] + self.pathWidth) # Make it happen and leave the intersection direction intact for i in xrange(len(self.intersections)): self.intersections[i] = ceil(self.intersections[i][0] * horizontalStretch), \ ceil(self.intersections[i][1] * verticalStretch), self.intersections[i][2] self.tower.x *= horizontalStretch self.tower.y *= verticalStretch def loadIntersections(self, filename): """ (None) -> tuple Load the saved intersections from file based on the current wave. Return the loaded intersection 3-tuples. """ self.intersections = [] data = open(getDataFilepath(filename), 'r') for line in data: intersection = self.makeStrSubstitutions(line).split() intersection = int(intersection[0]), int(intersection[1]), int(intersection[2]) self.intersections.append(intersection) self.stretchIntersections() return self.intersections def loadTowerLoc(self, filename): """ (None) -> None Load the co-ordinates of the tower to defend. """ data = open(getDataFilepath(filename), 'r').read().split() x = int(self.makeStrSubstitutions(data[-3])) y = int(self.makeStrSubstitutions(data[-2])) self.tower.x, self.tower.y = x - self.tower.w // 2, y - self.tower.h // 2 newRect = self.tower.getRect().clamp(pygame.Rect(0, 0, self.screenW - self.hud.width, self.screenH)) self.tower.x = newRect.x self.tower.y = newRect.y def incrementWave(self): """ (None) -> None Set up the level for the next wave. """ self.wave += 1 self.generateEnemies(4 * self.wave) for turret in self.turrets: turret.bullets = [] turret.angle = 0 def drawText(self, text, x=0, y=0): """ (str, [int], [int]) -> None Draw the given string such that the text matches up with the given top-left co-ordinates. Acts as a wrapper for the HUD drawText(). """ self.hud.drawText(self.displaySurf, text=text, left=x, top=y) def handleAI(self): """ (None) -> None Force the enemies to turn at each intersection. """ if not self.enemies or not self.intersections: return for enemy in self.enemies: nextTurn = enemy.getNextIntersection() if not enemy.getReducedRect().collidepoint(nextTurn[0:2]): continue if nextTurn[-1] == LEFT: enemy.startMovingLeft() elif nextTurn[-1] == RIGHT: enemy.startMovingRight() elif nextTurn[-1] == UP: enemy.startMovingUp() elif nextTurn[-1] == DOWN: enemy.startMovingDown() else: enemy.stop() intersectionIndex = self.intersections.index(nextTurn) if intersectionIndex + 1 < len(self.intersections): enemy.setNextIntersection(self.intersections[intersectionIndex + 1]) def drawIntersections(self, surface): """ (Surface) -> None Draw a sequence of paths joining all of the intersections onto the given surface. Update the list of path Rect objects for collision detection. """ if not self.intersections: return points, intersectionRects, joinRects, result = [], [], [], [] half = floor(self.pathWidth / 2.0) for intersection in self.intersections: points.append((intersection[0], intersection[1])) for point in points: intersectionRects.append(pygame.Rect(point[0] - half, point[1] - half, 2 * half, 2 * half)) for i in xrange(len(points) - 1): result.append(intersectionRects[i].union(intersectionRects[i + 1])) surface.blit(self.pathImage, (result[-1].x, result[-1].y), result[-1]) self.pathRects = result def onPath(self, other): """ (int, int) -> bool Return True if the x and y co-ordinates represent a spot on the paths, False otherwise. """ result = False if not self.pathRects: return result for rect in self.pathRects: if (isinstance(other, tuple) and rect.collidepoint(other)) or rect.colliderect(other): result = True return result def onGrass(self, other): """ (int, int) -> bool Return True if the x and y co-ordinates represent a spot on the grass, False otherwise. """ return not self.onPath(other) def hoveringSidebar(self): """ (None) -> bool Return True if the mouse is hovering over the HUD sidebar, False otherwise. """ return self.mouseX >= self.hud.left def initializeDisplay(self): """ (None) -> Surface Initialize the display Surface and update the caption and display settings. Only call once in __init__. """ self.displaySurf = pygame.display.set_mode((self.screenW, self.screenH), self.flags) pygame.display.set_caption(self.caption) return self.displaySurf def redrawAndProceedTick(self): """ (None) -> None Redraw the screen, and delay to enforce the FPS. Call on every update. """ pygame.display.flip() self.fpsClock.tick_busy_loop(self.fps) self.measuredFPS = self.fpsClock.get_fps() def terminate(self): """ (None) -> None Set the game to exit as soon as possible. """ print('Game closing...') self.inPlay = False def handleQuitEvents(self, events): """ (list-of-Events) -> None Exit the game if Escape is pressed or if the close button is used. """ for event in events: if event.type == QUIT or (event.type == KEYDOWN and event.key == K_ESCAPE): self.terminate() def updateState(self): """ (None) -> None Update the state of the game based on the user selection on the sidebar. """ if self.hud.shouldPause(): self.backgroundMusic.pause() if self.menu.drawPauseMenu(self.displaySurf): self.__init__(self.fps, self.fullscreen) self.execute() self.menu.drawPauseMenu(self.displaySurf) self.backgroundMusic.play(-1) if self.hud.shouldStart(): self.mode = self.modes[1] self.canRun() def updateEnemies(self): """ (None) -> None Update and draw all enemies and the central tower. """ levelComplete = True for enemy in self.enemies: if self.mode == self.modes[0]: enemy.pause() elif self.mode == self.modes[1]: enemy.unpause() if enemy.alive(): levelComplete = False enemy.update() self.tower.update(self.displaySurf, enemy) enemy.draw(self.displaySurf, enemy.x, enemy.y) if levelComplete and self.mode == self.modes[1]: self.mode = self.modes[0] self.incrementWave() def enemyIndex(self, enemy): try: return self.enemies.index(enemy) except IndexError: print('WARNING: Tried to access nonexistent enemy.') return 0 @staticmethod def inRange(enemy, turret): """ (Enemy, Turret) -> None Return True if the enemy is in range of the given turret, False otherwise. """ return distance(enemy.getRect().center, turret.getRect().center) < turret.range and enemy.active def setTarget(self, enemy, turret): """ (Enemy, Turret) -> None Lock onto a new enemy with the given turret. """ if not isinstance(turret, FourShotTurret) and turret.canShoot: turret.angle = getAngle(deltaX(enemy.x, turret.x), deltaY(enemy.y, turret.y)) turret.lockOn = True def provideReward(self, turret): """ (None, Turret) -> None Provide the player with a reward for each kill. """ self.money += turret.reward def updateTurrets(self): """ (None) -> None Update and draw all turrets and bullets. """ for turret in self.turrets: # Check if the turret is highlighted turret.highlighted = False if turret.getRect().collidepoint(self.mouseX, self.mouseY): turret.highlighted = True # Check for lock-on with enemies foundTarget = False for enemy in self.enemies: if self.inRange(enemy, turret): self.setTarget(enemy, turret) foundTarget = True break if not foundTarget: turret.lockOn = False turret.bullets = [] # Update and draw the turret turret.update(self.displaySurf) # Check for bullet collision with enemies for bullet in turret.bullets: for enemy in self.enemies: bulletEnemyCollision = bullet.getRect().colliderect(enemy.getRect()) if bulletEnemyCollision and not isinstance(turret, FourShotTurret): self.hitSound.play() bullet.dispose() turret.test = True if not isinstance(turret, GlueTurret) or \ (isinstance(enemy, Plane) and not isinstance(turret, FireTurret)): enemy.health -= bullet.damagePotential else: enemy.topSpeed *= bullet.slowFactor enemy.dispose() if enemy.health <= 0: self.provideReward(turret) elif bulletEnemyCollision: self.hitSound.play() enemy.health -= bullet.damagePotential enemy.dispose() bullet.dispose() if enemy.health <= 0: self.provideReward(turret) def updateHud(self): """ (None) -> None Update and draw the HUD sidebar. """ self.hud.update(self.tower.health, self.money, self.wave) self.hud.draw(self.displaySurf) def updateInputs(self): """ (None) -> None Get keyboard and mouse status and check for quit events. """ self.mouseX, self.mouseY = pygame.mouse.get_pos() self.clicking = pygame.mouse.get_pressed()[0] self.events = pygame.event.get() self.handleQuitEvents(self.events) def addTurret(self, index): """ (int) -> None Add a turret with the given index to the list of turrets. """ newTurret = copy.copy(self.hud.turrets[index]) newTurret.x = DEFAULT_VALUE newTurret.y = DEFAULT_VALUE self.turrets.append(newTurret) def handleDragging(self): """ (None) -> None Facilitate dragging of turrets from the HUD sidebar to the game field. """ overlapping = False index = self.hud.highlighted() clicked = False rects = [turret.getRect() for turret in self.turrets[0:-1]] if len(self.turrets) > 1: for rect in rects: if self.turrets[-1].getRect().colliderect(rect): overlapping = True for event in self.events: if event.type == MOUSEBUTTONDOWN: clicked = True if self.dragging and clicked and self.onGrass(self.turrets[-1].getRect()) and not overlapping: self.dragging = False self.turrets[-1].canShoot = True self.money -= self.turrets[-1].price if index >= 0 and clicked and not self.dragging and self.money >= self.hud.turrets[index].price: self.dragging = True self.addTurret(index) if self.dragging and not clicked: self.turrets[-1].x = self.mouseX - self.turrets[-1].width // 2 self.turrets[-1].y = self.mouseY - self.turrets[-1].height // 2 self.turrets[-1].canShoot = False def update(self): """ (None) -> None Update the entire game state and draws all objects on the screen. """ self.displaySurf.blit(self.background, ORIGIN) self.updateInputs() self.handleAI() self.updateEnemies() self.updateTurrets() self.updateHud() self.handleDragging() self.redrawAndProceedTick() self.updateState() def execute(self): """ (None) -> None Execute the Tower Defense game. """ # Play background music and enter the title screen self.backgroundMusic.play(-1) self.menu.drawTitleMenu(self.displaySurf) filename = self.menu.drawSelectLevelScreen(self.displaySurf) # Load the first level properties self.loadTowerLoc(filename) self.loadIntersections(filename) self.generateEnemies(5) # Blit the tower and paths onto the background Surface self.drawIntersections(self.intersectionSurface) self.background.blit(self.intersectionSurface, ORIGIN) self.tower.draw(self.background) # Play! while self.inPlay: self.update() self.menu.drawLosePanel (self.displaySurf) self.menu.drawCredits(self.displaySurf) pygame.quit() def getRect(self): """ (None) -> Rect Return a pygame Rect object defining the display surface boundaries. """ return self.displaySurf.get_rect() def canRun (self): if self.tower.health <= 0: self.terminate ()
class PlayState(GameState): TICK_LENGTH: float = 0.1 GRID_SIZE: int = 50 INITIAL_BODY_SIZE = 3 WHITE = (255, 255, 255) BLACK = (0, 0, 0) FOOD_COLOR = (0xFF, 0x90, 0x00) tick_time: float head: Head body: List[Body] food: Food hud: HUD def init(self): PlayState.TICK_LENGTH = 0.1 self.tick_time = 0 self.head = Head(PlayState.GRID_SIZE) self.body = [] for i in range(PlayState.INITIAL_BODY_SIZE): self.__add_body__() self.food = Food(PlayState.GRID_SIZE, self.head.pos) self.hud = HUD() pass def handle_input(self): if MyInput.key_check_pressed(MyInput.BACK): self.switch_state(GameStateType.TITLE) self.head.handle_input() pass def update(self, screen_size: Tuple[float, float], delta_time): self.tick_time += delta_time if self.tick_time >= PlayState.TICK_LENGTH: self.tick_time = 0 self.__tick__(delta_time) pass def __tick__(self, delta_time): for body in self.body: if body.colliding_with(self.head): Snake.score = len(self.body) - PlayState.INITIAL_BODY_SIZE self.switch_state(GameStateType.GAME_OVER) if len(self.body) >= 1: self.body[0].set_direction(self.head) for i in range(1, len(self.body)): self.body[i].set_direction(self.body[i - 1]) for body in self.body: body.update() self.head.update() if self.head.colliding_with(self.food): PlayState.TICK_LENGTH *= .95 self.food.reset(PlayState.GRID_SIZE, self.head.pos) self.__add_body__() if self.head.pos.x < 0 or self.head.pos.x > PlayState.GRID_SIZE - 1 or self.head.pos.y < 0 or self.head.pos.y > PlayState.GRID_SIZE - 1: Snake.score = len(self.body) - PlayState.INITIAL_BODY_SIZE self.switch_state(GameStateType.GAME_OVER) def draw(self, surface: Surface, screen_size: Tuple[float, float], delta_time): cell_width = 10 grid_width = cell_width * PlayState.GRID_SIZE start_x = (screen_size[0] * 0.5) - (grid_width * 0.5) start_y = (screen_size[1] * 0.5) - (grid_width * 0.5) pygame.draw.rect(surface, PlayState.WHITE, Rect(start_x, start_y, grid_width, grid_width), 1) self.head.draw(surface, PlayState.BLACK, start_x, start_y, cell_width, cell_width) for body in self.body: body.draw(surface, PlayState.BLACK, start_x, start_y, cell_width, cell_width) self.food.draw(surface, PlayState.FOOD_COLOR, start_x, start_y, cell_width, cell_width) score = len(self.body) - PlayState.INITIAL_BODY_SIZE self.hud.draw(surface, start_x, start_y, grid_width, score, PlayState.BLACK) def __add_body__(self): if len(self.body) < 1: self.body.append(Body(self.head)) else: self.body.append(Body(self.body[len(self.body) - 1]))
def _draw_hud(self): hud = HUD(self._screen()) hud.set_score(self.hero().score()) hud.draw()
class Game: """Main class which handles input, drawing, and updating.""" def __init__(self): """Init pygame and the map.""" self.WIDTH = 800 self.HEIGHT = 600 self.FPS = 60 self.MAP_SIZE = (100, 100) self.PLAYER_POS = (0.5, 0.5) self.PLAYER_SIZE = (1.5, 1.5) self.PLAYER_REACH = 4 self.HUD_HEIGHT = 50 pygame.init() pygame.font.init() pygame.display.set_caption("tilecollision prototype") self.screen_size = (self.WIDTH, self.HEIGHT) self.screen = pygame.display.set_mode(self.screen_size) self.clock = pygame.time.Clock() self.map = Map(self.MAP_SIZE) self.player = MapEntity(*(self.PLAYER_POS + self.PLAYER_SIZE + (0, 0))) self.map.entities.append(self.player) hud_rect = (0, self.screen_size[1] - self.HUD_HEIGHT, self.screen_size[0], self.HUD_HEIGHT) self.hud = HUD(hud_rect) self.topleft = (0, 0) # reset to center on player self.mouse_pos = (0, 0) def do_events(self): """Handle events from pygame.""" for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() exit(0) elif event.type == pygame.KEYDOWN: if event.key == 119: # w self.player.jump = True elif event.key == 100: # d self.player.walk_right = True elif event.key == 97: # a self.player.walk_left = True else: print event.key elif event.type == pygame.KEYUP: if event.key == 119: # w self.player.jump = False elif event.key == 100: # d self.player.walk_right = False elif event.key == 97: # a self.player.walk_left = False elif event.type == pygame.MOUSEMOTION: # save mouse pos to compute map cursor each frame self.mouse_pos = event.pos elif event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: # if mouse is in valid location to place/destory block if self.map.cursor_pos: (gx, gy) = self.map.px_to_grid(self.topleft, self.map.cursor_pos) (gx, gy) = (int(gx), int(gy)) block_id = self.map.get_block(gx, gy) if Block(block_id).is_solid: # remove block self.map.set_block(gx, gy, Block(name="air").id) self.hud.add_block(block_id) surf = Block(block_id).surf ps_pos = (particles.ParticleSystem(surf), (gx+0.5, gy+0.5)) self.map._particle_systems.append(ps_pos) angle = atan2(gx - self.player.x, gy - self.player.y) self.player.punch((180/3.141) * angle) else: # add block new_block = self.hud.get_selected_block() self.map.set_block(gx, gy, new_block) elif event.button == 4: # wheel up self.hud.rotate_selection(-1) elif event.button == 5: # wheel down self.hud.rotate_selection(1) def do_update(self, elapsed): """Update the game state.""" self.map.update(elapsed) # update the cursor # find grid distance from center of block under the mouse to # player's center (gx, gy) = self.map.px_to_grid(self.topleft, self.mouse_pos) (gx, gy) = (int(gx), int(gy)) dist = sqrt(pow(gx + 0.5 - self.player.x - self.player.width/2, 2) + pow(gy + 0.5 - self.player.y - self.player.height/2, 2)) # only show cursor if close enough and block doesn't collide if dist > self.PLAYER_REACH: self.map.cursor_pos = None elif self.map.rect_colliding(self.player.get_rect(), (gx, gy)): self.map.cursor_pos = None else: self.map.cursor_pos = self.mouse_pos def do_draw(self): """Draw the game.""" # fill bg red for now to show errors self.screen.fill((255, 0, 0)) # calculate top left coordinates such that player is draw on map center self.topleft = (self.player.x - self.WIDTH / 2 / self.map.TILE_SIZE, self.player.y - self.HEIGHT / 2 / self.map.TILE_SIZE) # modify top left coordinates so viewport does not leave map max_x = self.MAP_SIZE[0] - self.WIDTH / self.map.TILE_SIZE max_y = self.MAP_SIZE[1] - self.HEIGHT / self.map.TILE_SIZE if self.topleft[0] < 0: self.topleft = (0, self.topleft[1]) elif self.topleft[0] > max_x: self.topleft = (max_x, self.topleft[1]) if self.topleft[1] < 0: self.topleft = (self.topleft[0], 0) elif self.topleft[1] > max_y: self.topleft = (self.topleft[0], max_y) self.map.draw(self.screen, self.topleft) self.hud.draw(self.screen) pygame.display.flip() def main(self): """Run the main loop. The game state updates on a fixed timestep. The update method may be called a varying number of times to catch up to the current time. """ now = 0 show_fps = 0 update_time = 0 UPDATE_STEP = 1000/60.0 # 60 Hz # main loop while True: elapsed = pygame.time.get_ticks() - now now = pygame.time.get_ticks() # update as many times as needed to catch up to the current time while (now - (update_time + UPDATE_STEP) >= 0): update_time += UPDATE_STEP self.do_update(UPDATE_STEP) # draw and check events self.do_draw() self.do_events() # wait until it's time for next frame self.clock.tick(self.FPS) show_fps = show_fps + 1 if (show_fps % self.FPS == 0): print self.clock.get_fps()
def main(): """ Main Program """ pygame.init() pygame.font.init() # Play shitty annoying music pygame.mixer.init() # pygame.mixer.music.load('res/music.mp3') pygame.mixer.music.load('res/kingkhan.mp3') pygame.mixer.music.set_volume(0.1) pygame.mixer.music.play(-1) # Set the height and width of the screen size = [SCREEN_WIDTH, SCREEN_HEIGHT] pygame.display.set_mode(size) screen = pygame.display.get_surface() flags = screen.get_flags() pygame.display.set_caption("Marcio") pygame.display.set_icon(pygame.image.load("res/code.png")) # Create the player player = Player() # Create all the levels level_list = [] # TODO remove this in 'prod' #level_list.append(TestLevel(player)) level_list.append(HetLevelVanOnsSpel(player)) # Set the current level current_level_no = 0 current_level = level_list[current_level_no] active_sprite_list = pygame.sprite.Group() player.level = current_level player.rect.x = 5 * 30 player.rect.y = SCREEN_HEIGHT - 5 * 30 active_sprite_list.add(player) hud = HUD(player) # Loop until the user clicks the close button. done = False # Used to manage how fast the screen updates clock = pygame.time.Clock() # Controls (misschien met een GUI?) # Volgens marc kan dat wel als we tijd over hebben, voor nu eerst de spellen afmaken. controls_left = [pygame.K_LEFT, pygame.K_a] controls_right = [pygame.K_RIGHT, pygame.K_d] controls_up = [pygame.K_UP, pygame.K_w, pygame.K_SPACE] controls_shoot = [pygame.K_LCTRL, pygame.K_RCTRL] menu = GameMenu(screen, ('PLAY', 'EXIT', 'RESTART')) menu.run() # Dialogs gg = Dialog() gg.set_text(['Game over!!', '', 'Press any key to quit']) gg.onkeydown = lambda dialog, event: exit(1) win = Dialog() win.set_text(['You won the game!!! :D', '', 'Press any key to quit']) win.onkeydown = lambda dialog, event: exit(1) not_done = Dialog() not_done.set_text([ 'You haven\'t collected all of', 'the code yet. Come back later.', '', 'Press any key to continue' ]) not_done.onkeydown = lambda dialog, event: dialog.close() timerfont = pygame.font.Font('res/Pixeled.ttf', 12) # -------- Main Program Loop ----------- # while not done: for event in pygame.event.get(): if event.type == pygame.QUIT: done = True if event.type == pygame.KEYDOWN: if hud.show_controls: # Haal begin dialog weg, met uitleg. hud.show_controls = False if event.key == pygame.K_ESCAPE: menu = GameMenu(screen, ('RESUME', 'EXIT', 'RESTART')) menu.run() # Toggle fullscreen with F11 if event.key == pygame.K_F11: if flags & pygame.FULLSCREEN == False: flags |= pygame.FULLSCREEN pygame.display.set_mode(size, flags) else: flags ^= pygame.FULLSCREEN pygame.display.set_mode(size, flags) if event.key in controls_left: player.go_left() if event.key in controls_right: player.go_right() if event.key in controls_up: player.jump() if event.key in controls_shoot: player.shoot() if event.type == pygame.KEYUP: if event.key in controls_left and player.change_x < 0: player.stop() if event.key in controls_right and player.change_x > 0: player.stop() # Update the player. active_sprite_list.update() # Update items in the level current_level.update() # Keep the player in the center of the level if player.rect.centerx != SCREEN_CENTER: diff = SCREEN_CENTER - player.rect.centerx if current_level.world_shift < 0: player.rect.centerx = SCREEN_CENTER if current_level.world_shift + diff > 0: diff = -current_level.world_shift # De rechterkant van de map werkt dus niet lekker, maak de map maar # langer zodat je daar nooit kan komen, ez fix. if diff != 0: current_level.shift_world(diff) usenicefont = False if player.can_finish_level(): usenicefont = True dialog = 'Picked up all objectives' else: if player.next_objective > 0: dialog = player.level.objective_list.snippets[ player.next_objective - 1] else: dialog = None if player.hits_end(): if not player.can_finish_level(): # usenicefont = True # dialog = 'Not done yet!' player.rect.x -= player.change_x player.change_x = 0 not_done.show() else: # Increment the current level current_level_no += 1 if current_level_no + 1 > len(level_list): win.show() current_level = level_list[current_level_no] # Misschien moeten we hier ook die Bullets resetten.. # maar fck dat want we hebben toch maar 1 level. deze code # wordt nooit uitgevoerd lol player.level = current_level player.lives = constants.LIVES # If the player hits lava, # he will lose one heart and get teleported to the start of the level if player.in_lava(): # rip player.die() or gg.show() # TODO: vervang exit(1) door iets dat een dialog laat zien # TODO detect what block we just hit so we can show the code # TODO choose to accept the code by pressing `E` touching_objectives = player.get_touching_objectives() if len(touching_objectives) > 0: objective = touching_objectives[0] if player.next_objective != objective.index: # Verkeerd objective player.die() or gg.show() # TODO: vervang exit(1) door iets dat een dialog laat zien else: # Goed objective objective.kill() player.next_objective += 1 # ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT current_level.draw(screen) active_sprite_list.draw(screen) hud.draw(screen, dialog, usenicefont) timertext = timerfont.render("%.2f" % (pygame.time.get_ticks() / 1000), False, constants.WHITE) screen.blit(timertext, (constants.SCREEN_WIDTH - 75, 16)) # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT # Limit to 60 frames per second clock.tick(constants.TPS) # Go ahead and update the screen with what we've drawn. pygame.display.flip() # Be IDLE friendly. If you forget this line, the program will 'hang' # on exit. pygame.quit()
class Game(State): WHITE = (255, 255, 255) def __init__(self, screen): size = screen.get_size() self.active_pc = 0 self.active_skills = [] self.screen = screen self.clock = pygame.time.Clock() self.pcs = [] self.npcs = [] self.hud = HUD(self) for p in range(3): self.pcs.append(PC((100, 100), 10, screen)) for n in range(5): self.npcs.append(NPC((100 + n*100, 100 + n*20), 10, screen)) def update(self, user_input, mouse_position): for event in user_input: if event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: self.manager.go_to(Menu(self.screen)) elif event.key == pygame.K_TAB: self.active_pc = (self.active_pc + 1) % len(self.pcs) elif event.key == pygame.K_1: self.pcs[self.active_pc].active_skill = 0 elif event.key == pygame.K_2: self.pcs[self.active_pc].active_skill = 1 elif event.key == pygame.K_3: self.pcs[self.active_pc].active_skill = 2 elif event.type == pygame.MOUSEBUTTONDOWN: if event.button == 1: self.pcs[self.active_pc].target_dest = mouse_position elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 3: self.active_skills.append(self.pcs[self.active_pc].fire(mouse_position)) elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 4: skills_amt = len(self.pcs[self.active_pc].skills) self.pcs[self.active_pc].active_skill = (self.pcs[self.active_pc].active_skill + 1) % skills_amt elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 5: skills_amt = len(self.pcs[self.active_pc].skills) self.pcs[self.active_pc].active_skill = (self.pcs[self.active_pc].active_skill - 1) % skills_amt self.active_skills = [a for a in self.active_skills if a is not None] self.active_skills = [a for a in self.active_skills if a.active_countdown > 0] for p in self.pcs: p.update() for n in self.npcs: n.update() ''' Pass updated pcs and npcs to each skill to check for collisions. ''' for a in self.active_skills: a.update(self.pcs, self.npcs) def draw(self): self.screen.fill(self.WHITE) for a in self.active_skills: a.draw() for n in self.npcs: n.draw() for p in self.pcs: p.draw() self.hud.draw() pygame.display.flip()
class SpaceDominationMain(object): ''' classdocs ''' # game state constants GAMESTATE_NONE = 0 GAMESTATE_RUNNING = 1 GAMESTATE_PAUSED = 2 GAMESTATE_GAMEOVER = 3 gameState = GAMESTATE_NONE physics = None menuManager = None missionList = None weaponList = None shipList = None currentMission = None upgradeList = None playerShip = None fpstext = None lastTick = 0 timeTotal = 0 clock = None screen = None screen_buffer = None window = None background = None menuBackground = None defaultfont = None largefont = None medfont = None rootSprite = None shipSpriteGroup = None destroyedSpriteGroup = None backgroundSpriteGroup = None triggerList = None foregroundSpriteGroup = None elapsedTime = 0.0 messageList = None # Profile stuff profiles = None currentProfile = None HUD = None # Campaign manager campaignMgr = None def __init__(self): ''' Constructor ''' # before anything else, load the profiles self.profiles = ProfileXMLParser().loadProfiles(os.path.join('assets','profiles.xml')) for p in self.profiles: if 'active' in p and p['active']: self.currentProfile = p break if not self.currentProfile: if len(self.profiles) > 0: self.currentProfile = self.profiles[0] else: self.setActiveProfile(profile.create_fresh_profile(id = 0)) self.saveProfiles() #initialize managers pygame.init() random.seed() self.createDisplay() Utils.load_common_assets() pygame.display.set_caption("Space Domination (version %s) by Jami Couch" % VERSION) self.clock = pygame.time.Clock() self.screen = pygame.display.get_surface() self.background = pygame.Surface(self.screen.get_size()) self.background = self.background.convert() self.background.fill((0,0,0)) self.rootSprite = pygame.sprite.OrderedUpdates() self.shipSpriteGroup = pygame.sprite.RenderClear() self.backgroundSpriteGroup = pygame.sprite.RenderClear() self.foregroundSpriteGroup = pygame.sprite.RenderClear() self.triggerList = [] self.messageList = [] if pygame.font: self.defaultfont = pygame.font.Font(None, 20) self.largefont = pygame.font.Font(os.path.join("assets", "PLANM___.TTF"), 40) self.medfont = pygame.font.Font(None, 30) # load & display splash screen self.showSplash() splashTime = pygame.time.get_ticks() # show the splash for up to 5 seconds or until a key is pressed event = None keypress = False while (not keypress) and pygame.time.get_ticks() < splashTime + SPLASH_TIME: for event in pygame.event.get(): if event.type == pygame.KEYDOWN: keypress = True # remove the splash screen self.removeSplash() # load the mission list self.missionList = self.loadMissionList() # load weapons self.weaponList = WeaponListXMLParser().loadWeaponList() # load ships self.shipList = ShipListXMLParser().loadShipList() # load upgrades self.upgradeList = UpgradeListXMLParser().load_upgrades() # initialize physics manager self.physics = Physics() # setup keymap self.keys = {"turnLeft" : 0, "turnRight" : 0, "accel" : 0, "brake" : 0, "fire" : 0, "alt-fire" : 0} # load the HUD self.HUD = HUD() # load the Campaign mangager self.campaignMgr = CampaignManager(self) # load the menus #self.menuManager = MenuManager(self.screen, self) self.menuManager = SpaceDominationGUI(self) self.gameState = SpaceDominationMain.GAMESTATE_NONE self.menuBackground = load_image("background.PNG")[0] #self.menuManager.menu_state_parse(Menu.MENU_MAIN) self.menuManager.set_active(True) self.menuManager.main_menu_click() # TODO: show the menu # eventually the menu will lead to... #self.gameState = SpaceDominationMain.GAMESTATE_RUNNING #self.currentMission = self.loadMission("mission01.xml") #self.buildMission(self.currentMission) def run(self): rect_list = [] while True: # handle input events = pygame.event.get() for event in events: if event.type == QUIT: sys.exit(0) elif self.menuManager.is_active(): self.menuManager.update(event) elif event.type == KEYDOWN: if event.key == K_ESCAPE: if self.gameState == self.GAMESTATE_RUNNING: self.pause_game() # movement elif event.key == K_UP: self.setKey("accel", 1) elif event.key == K_DOWN: self.setKey("brake", 1) elif event.key == K_LEFT: self.setKey("turnLeft", 1) elif event.key == K_RIGHT: self.setKey("turnRight", 1) elif event.key == K_SPACE: self.setKey("fire", 1) # weapon swapping elif event.key >= pygame.K_1 and event.key <= pygame.K_9: wp = event.key - pygame.K_1 if len(self.playerShip.weapons) >= wp + 1: self.playerShip.selected_weapon = wp elif event.type == KEYUP: # movement if event.key == K_UP: self.setKey("accel", 0) elif event.key == K_DOWN: self.setKey("brake", 0) elif event.key == K_LEFT: self.setKey("turnLeft", 0) elif event.key == K_RIGHT: self.setKey("turnRight", 0) elif event.key == K_SPACE: self.setKey("fire",0) elif event.type == pygame.ACTIVEEVENT: if event.state == STATE_LOSE_FOCUS: if self.gameState == self.GAMESTATE_RUNNING: self.pause_game() '''elif event.type == MOUSEBUTTONDOWN: if event.button == 1: self.setKey("fire", 1) print event.button elif event.type == MOUSEBUTTONUP: if event.button == 1: self.setKey("fire", 0)''' # clear the background (blit a blank screen) then draw everything in the background then the sprite groups then the foreground group self.screen.blit(self.background, (0,0)) # game loop self.gameLoop() if self.gameState == self.GAMESTATE_NONE: #drawSurf = pygame.transform.scale(self.menuBackground, self.screen.get_size()) self.screen.blit(self.menuBackground, ((self.screen.get_width() - self.menuBackground.get_width()) * 0.5, (self.screen.get_height() - self.menuBackground.get_height()) * 0.5)) if self.menuManager.is_active(): self.menuManager.draw() pygame.display.flip() return def pause_game(self): self.gameState = self.GAMESTATE_PAUSED self.menuManager.pause_menu_click() def unpause_game(self): self.gameState = self.GAMESTATE_RUNNING self.menuManager.close() def quit_mission(self): self.gameState = self.GAMESTATE_GAMEOVER self.menuManager.main_menu_click() def setKey(self, key, val): self.keys[key] = val def showSplash(self): self.screen.blit(self.background, (0, 0)) splashImage, splashRect = Utils.load_image("splash.png") centerScreen = (self.screen.get_size()[0] * 0.5, self.screen.get_size()[1] * 0.5) self.screen.blit(splashImage, (centerScreen[0] - splashRect.width * 0.5, centerScreen[1] - splashRect.height * 0.5)) pygame.display.flip() return def removeSplash(self): self.screen.blit(self.background, (0, 0)) pygame.display.flip() return def loadMissionList(self): return MissionListXMLParser().loadMissionList() def loadMission(self, filename): return MissionXMLParser().loadMission(filename) def startMission(self, mission): if isinstance(mission, Mission): self.currentMission = mission else: self.currentMission = self.loadMission(mission[0]) self.buildMission(self.currentMission) self.pause_game() def getPlayerSpawn(self): if 'ship' in self.currentProfile and int(self.currentProfile['ship']) >= 0 and int(self.currentProfile['ship']) < len(self.shipList): proto = self.shipList[int(self.currentProfile['ship'])] else: proto = self.shipList[0] return proto def buildMission(self, mission): self.elapsedTime = 0.0 #add the trigger list self.triggerList = mission.triggerList[:] #self.rootSprite = pygame.sprite.OrderedUpdates() self.shipSpriteGroup = OrderedUpdatesRect() self.destroyedSpriteGroup = OrderedUpdatesRect() self.backgroundSpriteGroup = OrderedUpdatesRect() #pygame.sprite.OrderedUpdates() self.foregroundSpriteGroup = OrderedUpdatesRect() #pygame.sprite.OrderedUpdates() self.physics = Physics() self.messageList = [] for key in self.keys: self.setKey(key, 0) #convert spawns to player or enemy for spawn in mission.spawnList: if spawn.type == 'player': # this is the player ship tp = self.getPlayerSpawn() tempShip = PlayerShip(proto = tp, context = self) tempShip.team = spawn.team self.playerShip = tempShip self.linkTriggers(spawn, tempShip) else: if spawn.id >= 0 and spawn.id < len(self.shipList): if self.shipList[spawn.id].hard_points: tempShip = StationShip(spawn.x, spawn.y, proto = self.shipList[spawn.id], context = self) for pt in self.shipList[spawn.id].hard_points: hpt = AIShip(spawn.x + pt['x'], spawn.y + pt['y'], spawn.r + pt['rot'], proto = self.shipList[pt['id']], parent = tempShip, context = self) hpt.team = tempShip.team tempShip.hard_points.append(hpt) else: tempShip = AIShip(spawn.x, spawn.y, spawn.r, proto = self.shipList[spawn.id], context = self) tempShip.team = spawn.team self.linkTriggers(spawn, tempShip) elif spawn.id == -1: if spawn.hard_points: tempShip = StationShip(spawn.x, spawn.y, spawn.r, proto = spawn.proto, context = self) for pt in spawn.hard_points: if pt.id >= 0 and pt.id < len(self.shipList): hpt = AIShip(spawn.x + pt.x, spawn.y + pt.y, spawn.r + pt.r, proto = self.shipList[pt.id], parent = tempShip, context = self) hpt.team = tempShip.team tempShip.hard_points.append(hpt) else: tempShip = AIShip(spawn.x, spawn.y, spawn.r, proto = spawn.proto, context = self) tempShip.team = spawn.team self.linkTriggers(spawn, tempShip) if spawn.squad: spawn.squad.append(tempShip) tempShip.squad = spawn.squad self.shipSpriteGroup.add(tempShip) self.foregroundSpriteGroup.add(tempShip.hard_points) self.physics.addChild(tempShip) tempShip.set_position(spawn.x, spawn.y) tempShip.set_rotation(spawn.r) tempShip.tag = spawn.tag tempShip.spawn = spawn tempShip.apply_upgrade(spawn.upgrade) # first, set up any auto-backgrounds if mission.background_style == 'tiled': # set up a tiled background using background_file and width, height x = 0 y = 0 mission.background_image, dfrect = Utils.load_image(mission.background_file) #convert bglist to backgrounds for bg in mission.backgroundList: tempBg = pygame.sprite.Sprite() tempBg.image, tempBg.rect = Utils.load_image(bg.filename) tempBg.rect.topleft = (bg.x, bg.y) self.backgroundSpriteGroup.add(tempBg) self.updateTriggers() def endMission(self): self.gameState = self.GAMESTATE_GAMEOVER #self.menuManager.main_menu_click() # put together the results for the mission results menu destroyedSpawns = self.currentMission.get_losses(self.destroyedSpriteGroup) destroyedLabels = {'ally': {}, 'enemy': {}} for sp in destroyedSpawns: if sp.team == Ship.TEAM_DEFAULT_FRIENDLY: update = destroyedLabels['ally'] else: update = destroyedLabels['enemy'] if not sp.id in update.keys(): # create a new entry lb = "Unknown" img = None if sp.id == -1 and sp.type == "player": lb = self.shipList[int(self.currentProfile['ship'])].name img = self.shipList[int(self.currentProfile['ship'])].image elif sp.id >= 0 and sp.id < len(self.shipList): lb = self.shipList[sp.id].name img = self.shipList[sp.id].image update[sp.id] = {'num': 1, 'label': lb, 'image': img} else: # update the existing entry update[sp.id]['num'] += 1 results = {'win': self.updateTriggers(), 'labels': destroyedLabels, 'spawns': destroyedSpawns, 'ships': self.destroyedSpriteGroup} if self.currentMission.isCampaignMission: self.campaignMgr.mission_ended(results, self.currentMission) self.menuManager.mission_results_show(results, self.currentMission) return results['win'] def linkTriggers(self, spawn, ship): for tg in self.triggerList: if tg.parent == spawn: tg.parent = ship def updateTriggers(self): # update triggers primObjComplete = True for tg in self.triggerList: tg.update(self) if not tg.completed and tg.type.count("objective-primary") > 0: primObjComplete = False return primObjComplete def gameLoop(self): dt = self.clock.tick(consts.FRAMERATE) self.timeTotal += dt # display the FPS if dt > 0: self.fpstext = self.defaultfont.render("FPS: " + str(float(int(10000.0 / dt)) / 10), 1, (0, 250, 0)) if self.gameState == self.GAMESTATE_RUNNING: # do physics if self.lastTick == 0: self.lastTick = pygame.time.get_ticks() #if pygame.time.get_ticks() - self.lastTick > 33: # self.physics.updatePhysics(self) # self.lastTick = pygame.time.get_ticks() timestep = float(dt) * consts.GAMESPEED * 0.001 self.elapsedTime += dt self.physics.updatePhysics(self, timestep) vel = Vec2(0,0) vel.setXY(*self.playerShip.velocity) #print "Ship: %f / Vel: %f (%f, %f) / timestep: %f" % (self.playerShip.get_rotation(), vel.theta, self.playerShip.velocity[0], self.playerShip.velocity[1], timestep) # update all sprites for sprite in self.backgroundSpriteGroup: sprite.update(self) for sprite in self.shipSpriteGroup: sprite.update(self, timestep) for sprite in self.foregroundSpriteGroup: sprite.update(self, timestep) if self.updateTriggers(): # player completed all primary objectives - mission should end with a victory status now self.endMission() else: failed = False for tg in self.triggerList: if not tg.completed and tg.type.count("objective-primary") > 0 and tg.condition.count("survive") > 0: failed = True if failed: self.endMission() if not self.playerShip in self.shipSpriteGroup: # player ship died - game over :( #self.gameState = self.GAMESTATE_GAMEOVER #self.menuManager.main_menu_click() self.endMission() if self.gameState == self.GAMESTATE_GAMEOVER: # TODO the game is ending, save the profile stats if not 'shots-fired' in self.currentProfile: self.currentProfile['shots-fired'] = 0 self.currentProfile['shots-fired'] = int(self.currentProfile['shots-fired']) + int(self.playerShip.stats['shots-fired']) if not 'shots-hit' in self.currentProfile: self.currentProfile['shots-hit'] = 0 self.currentProfile['shots-hit'] = int(self.currentProfile['shots-hit']) + int(self.playerShip.stats['shots-hit']) if not 'damage-dealt' in self.currentProfile: self.currentProfile['damage-dealt'] = 0 self.currentProfile['damage-dealt'] = int(self.currentProfile['damage-dealt']) + int(self.playerShip.stats['damage-dealt']) if not 'damage-taken' in self.currentProfile: self.currentProfile['damage-taken'] = 0 self.currentProfile['damage-taken'] = int(self.currentProfile['damage-taken']) + int(self.playerShip.stats['damage-taken']) if not 'kills' in self.currentProfile: self.currentProfile['kills'] = 0 self.currentProfile['kills'] = int(self.currentProfile['kills']) + int(self.playerShip.stats['kills']) death = 0 if not self.playerShip in self.shipSpriteGroup: death = 1 if not 'deaths' in self.currentProfile: self.currentProfile['deaths'] = 0 self.currentProfile['deaths'] = int(self.currentProfile['deaths']) + death self.saveProfiles() elif self.gameState == self.GAMESTATE_GAMEOVER: for sprite in self.foregroundSpriteGroup: if isinstance(sprite, Particle): sprite.update(self) self.updateTriggers() if self.gameState != self.GAMESTATE_NONE: # use the given mission width/height and the backgrounds to determine the boundaries maxrect = Rect(0,0,self.currentMission.width,self.currentMission.height) for sprite in self.backgroundSpriteGroup: # backgrounds will define the boundaries if sprite.rect.left + sprite.rect.width > maxrect.width: maxrect.width = sprite.rect.left + sprite.rect.width if sprite.rect.top + sprite.rect.height > maxrect.height: maxrect.height = sprite.rect.top + sprite.rect.height # now render to the screen using the playerShip to decide on coords render = (-1 * self.playerShip.rect.center[0] + (self.screen.get_width() * 0.5), -1 * self.playerShip.rect.center[1] + (self.screen.get_height() * 0.5)) if render[0] > 0: render = (0, render[1]) if render[1] > 0: render = (render[0], 0) if render[0] < -1 * maxrect.width + self.screen.get_width(): render = (-1 * maxrect.width + self.screen.get_width(), render[1]) if render[1] < -1 * maxrect.height + self.screen.get_height(): render = (render[0], -1 * maxrect.height + self.screen.get_height()) # draw a tiled background if necessary if self.currentMission and self.currentMission.background_style == 'tiled' and self.currentMission.background_image: # we will always assume that 0,0 is the starting point for the tiling bgimg = self.currentMission.background_image # set the offset to start at the closest tiling position to the top/left of the current area offset = [-1 * render[0], -1 * render[1]] # set up parralax offset[0] -= (bgimg.get_width() - consts.PARALLAX * render[0] % bgimg.get_width()) offset[1] -= (bgimg.get_height() - consts.PARALLAX * render[1] % bgimg.get_height()) #offset[0] = int(offset[0] / bgimg.get_width()) * bgimg.get_width() #offset[1] = int(offset[1] / bgimg.get_height()) * bgimg.get_height() start = [offset[0], offset[1]] end = [-1 * render[0] + self.screen.get_width(), -1 * render[1] + self.screen.get_height()] # render the tiles until off the screen while offset[0] < end[0] and offset[1] < end[1]: self.screen.blit(bgimg, (offset[0] + render[0], offset[1] + render[1])) offset[0] += bgimg.get_width() if offset[0] >= end[0]: offset[0] = start[0] offset[1] += bgimg.get_height() # now draw the sprites drawrect = pygame.rect.Rect(-1 * render[0], -1 * render[1], self.screen.get_width(), self.screen.get_height()) self.backgroundSpriteGroup.draw(self.screen, drawrect, render) self.shipSpriteGroup.draw(self.screen, drawrect, render) self.foregroundSpriteGroup.draw(self.screen, drawrect, render) # TODO display HUD things self.screen.blit(self.fpstext, (10,30)) #if isinstance(sprite, AIShip): # rect = pygame.rect.Rect(0,0,10,10) # rect.center = (sprite.waypoint[0] + render[0], sprite.waypoint[1] + render[1]) # pygame.gfxdraw.box(self.screen, rect, (0, 0, 250)) self.HUD.draw(self.screen, self, render) #if self.gameState == self.GAMESTATE_GAMEOVER: # if self.updateTriggers(): # text_surf = self.largefont.render("MISSION COMPLETE", 1, (0, 255, 0)) # self.screen.blit( text_surf, (self.screen.get_width() * 0.5 - text_surf.get_width() * 0.5, 100)) # else: # text_surf = self.largefont.render("MISSION FAILED", 1, (255, 0, 0)) # self.screen.blit( text_surf, (self.screen.get_width() * 0.5 - text_surf.get_width() * 0.5, 100)) return True def createDisplay(self): '''creates a display from the current profile settings''' try: if 'width' in self.currentProfile and int(self.currentProfile['width']) >= MIN_WINDOW_WIDTH: self.currentProfile['width'] = int(self.currentProfile['width']) else: self.currentProfile['width'] = MIN_WINDOW_WIDTH if 'height' in self.currentProfile and int(self.currentProfile['height']) >= MIN_WINDOW_HEIGHT: self.currentProfile['height'] = int(self.currentProfile['height']) else: self.currentProfile['height'] = MIN_WINDOW_HEIGHT if not 'fullscreen' in self.currentProfile: self.currentProfile['fullscreen'] = 0 flags = 0 if int(self.currentProfile['fullscreen']): flags = pygame.FULLSCREEN self.window = pygame.display.set_mode((self.currentProfile['width'],self.currentProfile['height']), flags) except pygame.error, msg: print "Error in profile video mode: %s" % msg self.window = pygame.display.set_mode((1024, 768))
class Game(object): def __init__(self): self._running = False self.camera = Vector2f(0,5) def init(self, size, fullscreen=False): flags = OPENGL|DOUBLEBUF if fullscreen: flags |= FULLSCREEN pygame.display.set_mode(size.xy, flags) pygame.display.set_caption('Super Chainsaw Food Adventure') i = pygame.display.Info() self.size = Vector2i(i.current_w, i.current_h) glMatrixMode(GL_MODELVIEW) glEnable(GL_TEXTURE_2D) glDisable(GL_CULL_FACE) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA) self.stage = 1 self.projection = Matrix.perspective(75, self.size, 0.1, 100) self.ortho = Matrix.ortho(self.size) v = np.array([ 0,0,0, 0,0, 1,0,0, 1,0, 1,1,0, 1,1, 0,1,0, 0,1, ], np.float32) i = np.array([0,1,2,3], np.uint32) self.quad = VBO(GL_QUADS, v, i) # parallax self.parallax_rep = 25 v = np.array([ 0,0,0, 0,1, 1,0,0, self.parallax_rep, 1, 1,1,0, self.parallax_rep,0, 0,1,0, 0,0, ], np.float32) i = np.array([0,1,2,3], np.uint32) self.repquad = VBO(GL_QUADS, v, i) self.parallax = Image('texture/sky.png', wrap=GL_REPEAT) self.parallax2 = Image('texture/sky2.png', wrap=GL_REPEAT) self.fbo = FBO(self.size, format=GL_RGB8, depth=True) self.shader = Shader('derp') self.passthru = Shader('passtru') self.herp = Shader('herp') self.map = Map('map.json') self.player = Player(Vector2f(55,-9)) self.clock = pygame.time.Clock() self.hud = HUD(Vector2i(500,100)) self.hpmeter = HUD(Vector2i(20, 500)) self.font = self.hud.create_font(size=16) self.font2 = self.hud.create_font(size=12) self.land = pygame.mixer.Sound('data/sound/land.wav') self.ding = pygame.mixer.Sound('data/sound/ding.wav') self.eat = pygame.mixer.Sound('data/sound/eat.wav') self.wind = pygame.mixer.Sound('data/sound/wind.wav') self.wind.play(loops=-1) self.set_stage(1) self.killfade = None self.killfade2 = 1.0 # fade amount self.textbuf = [] self.texttime = -10.0 self.message('<b>Welcome adventurer!</b>\nYou can start exploring the world but beware of wandering away too far.') self.message('When outside of lights your <i>HP</i> will drain and you will get lost in the woods.') self.message('Eat food to temporary increase your <i>HP</i>.') self.message('Quest started: "Find the chainsaw".') self.message('Quest started: "Frobnicate something".') with self.hud: self.hud.clear((0,1,1,1)) def running(self): return self._running @event(pygame.QUIT) def quit(self, event=None): self._running = False @event(pygame.KEYDOWN) def on_keypress(self, event): if event.key == 113 and event.mod & KMOD_CTRL: # ctrl+q return self.quit() if event.key == 27: # esc return self.quit() if event.key == 119: self.player.jump() @event(pygame.KEYUP) def on_keyrelease(self, event): if event.key == 119: self.player.unjump() def poll(self): global event_table for event in pygame.event.get(): func = event_table.get(event.type, None) if func is None: continue func(self, event) def update(self): if self.killfade is not None: t = pygame.time.get_ticks() / 1000.0 s = (t - self.killfade) / 2.5 self.killfade2 = 1.0 - s if s > 1.0: self.quit() # so player keeps falling dt = 1.0 / self.clock.tick(60) self.player.vel.y = 0 self.player.update(dt, self.map) return key = pygame.key.get_pressed() self.player.vel.x = 0 if key[97 ]: self.player.vel.x = -0.15 if key[100]: self.player.vel.x = 0.15 if key[260]: self.camera.x -= 0.1 if key[262]: self.camera.x += 0.1 if key[258]: self.camera.y -= 0.1 if key[264]: self.camera.y += 0.1 dt = 1.0 / self.clock.tick(60) self.player.update(dt, self.map) self.player.frobnicate(self.map.pickups) self.map.update() def render(self): glClearColor(1,0,1,1) glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) with self.hpmeter as hud: hud.clear((0.3,0,0,1)) hud.cr.identity_matrix() hud.rectangle(0,0, hud.width, hud.height * self.player.hp_ratio, (0,0.3,0,1)) hud.cr.translate(18,0) hud.cr.rotate(math.pi*0.5) hud.text(' Energy: %d / %d' % (int(math.ceil(self.player.hp/10)) * 10, Player.max_hp), self.font2, color=(1,0.8,0,1)) with self.hud: self.hud.clear((0,0,0,0)) self.hud.cr.identity_matrix() t = pygame.time.get_ticks() / 1000.0 s = (t - self.texttime) / 4.0 if s > 1.0: if len(self.textbuf) > 0: self.texttime = pygame.time.get_ticks() / 1000.0 self.text = self.textbuf.pop(0) else: a = min(1.0-s, 0.2) * 5 self.hud.cr.translate(0,25) self.hud.text(self.text, self.font, color=(1,0.8,0,a), width=self.hud.width, alignment=ALIGN_CENTER) view = Matrix.lookat( self.player.pos.x, self.player.pos.y+7, 15, self.player.pos.x, self.player.pos.y+7, 0, 0,1,0) with self.fbo as frame: frame.clear(0,0.03,0.15,1) Shader.upload_projection_view(self.projection, view) Shader.upload_player(self.player) self.shader.bind() # parallax background pm1 = Matrix.identity() pm1[3,0] = self.player.pos.x * 0.35 - 20 pm1[3,1] = self.player.pos.y * 0.5 - 20 pm1[0,0] = 42.0 * self.parallax_rep pm1[1,1] = 42.0 self.parallax.texture_bind() Shader.upload_model(pm1) self.repquad.draw() Shader.upload_projection_view(self.projection, view) self.map.draw() # entities for obj in self.map.pickups: obj.draw(self.quad) self.player.draw() # parallax 2 pm1 = Matrix.identity() pm1[3,0] = self.player.pos.x * -2.0 + 100 pm1[3,1] = self.player.pos.y * 0.5 - 45 * 3 + 10 pm1[0,0] = 45.0 * self.parallax_rep * 3 pm1[1,1] = 45 * 3 self.parallax2.texture_bind() Shader.upload_model(pm1) self.repquad.draw() mat = Matrix.identity() mat[0,0] = self.size.x mat[1,1] = self.size.y Shader.upload_projection_view(self.ortho, Matrix.identity()) Shader.upload_model(mat) self.fbo.bind_texture() self.herp.bind() self.quad.draw() # messagebox mat = Matrix.identity() mat[3,0] = self.size.x / 2 - self.hud.width / 2 mat[3,1] = self.size.y - self.hud.height Shader.upload_model(mat) self.hud.draw() # hpmeter mat = Matrix.identity() mat[3,1] = self.size.y / 2 - self.hpmeter.height / 2 Shader.upload_model(mat) self.hpmeter.draw() Shader.unbind() pygame.display.flip() def run(self): self._running = True while self.running(): self.poll() self.update() self.render() def message(self, text): self.textbuf.append(text) def set_stage(self, n): if n == 1: self.map.pickups.extend(self.map.obj1) elif n == 2: self.map.pickups.extend(self.map.obj2) elif n == 3: self.map.pickups.extend(self.map.obj3) def over(self): self.killfade = pygame.time.get_ticks() / 1000.0