示例#1
0
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)
示例#2
0
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)
示例#3
0
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 ()
示例#4
0
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]))
示例#5
0
	def _draw_hud(self):
		hud = HUD(self._screen())
		hud.set_score(self.hero().score())
		hud.draw()
示例#6
0
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()
示例#7
0
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()
示例#8
0
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))
示例#10
0
文件: game.py 项目: ext/scfa
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