22. PyGame

Защо искаме да правим игри?

Колко точно различно е?

Основните ни занимания

Показваме неща на екрана

Безкрайният цикъл

Цялата ни игра е един безкраен цикъл, в който обработваме event-и

         import pygame

         pygame.init()
         screen = pygame.display.set_mode((640, 480))

         running = True
         while running
             for event in pygame.event.get():
                 if event.type == pygame.QUIT
                     running = False
    

Безкраен цикъл done right

        import pygame

        class Game(object)
            def main(self, screen):
                while 1
                    for event in pygame.event.get():
                        if event.type == pygame.QUIT
                            return

        if __name__ == '__main__'
            pygame.init()
            screen = pygame.display.set_mode((640, 480))
            Game().main(screen)
    

Чертаене

FPS

Различни машини - различни възможности.

        while 1
           clock.tick(30)

           for event in pygame.event.get()
               if event.type == pygame.QUIT:
                   return

           screen.fill((200, 200, 200))
           screen.blit(image, (320, 240))
           pygame.display.flip()
    

Анимации

Със всяка итерация променяме координатите на нещото, което се "движи"

и всеки път подаваме новите на screen.blit

screen.blit(image, (x, y))

User Input

        key = pygame.key.get_pressed()
        if key[pygame.K_LEFT]
            image_x -= 10
        if key[pygame.K_RIGHT]
            image_x += 10
        if key[pygame.K_UP]
            image_y -= 10
        if key[pygame.K_DOWN]
            image_y += 10
    

Sprites

Двуизмерна картинка или анимация, интегрирана в някакво пространство

        class Player(pygame.sprite.Sprite)
            def __init__(self, *groups):
                super(Player, self).__init__(*groups)
                self.image = pygame.image.load('player.png')
                self.rect = pygame.rect.Rect((320, 240), self.image.get_size())

            def update(self)
                key = pygame.key.get_pressed()
                if key[pygame.K_LEFT]
                    self.rect.x -= 10
                if key[pygame.K_RIGHT]
                    self.rect.x += 10
                if key[pygame.K_UP]
                    self.rect.y -= 10
                if key[pygame.K_DOWN]
                    self.rect.y += 10
    

Групи от спрайтове

В общия случай го раздаваме с десетки/стотици спрайтове.

Не искаме да се молим на всеки един по отделно да се пречертае

        class Game(object)
            def main(self, screen):
                clock = pygame.time.Clock()

                sprites = pygame.sprite.Group()
                self.player = Player(sprites)

                while 1
                    clock.tick(30)

                    for event in pygame.event.get()
                        if event.type == pygame.QUIT:
                            return

                    sprites.update()
                    screen.fill((200, 200, 200))
                    sprites.draw(screen)
                    pygame.display.flip()
    

Smoother!

Малко по-приятна сцена

screen.fill е полезно, но изключително куцо

Би било далеч по-приятно да имаме някакъв красив фон...като небе примерно

        def main(self, screen)
            clock = pygame.time.Clock()

            background = pygame.image.load('background.png')
            sprites = pygame.sprite.Group()
            self.player = Player(sprites)

            while 1
                dt = clock.tick(30)
                for event in pygame.event.get()
                [....]

                sprites.update(dt / 1000.)
                screen.blit(background, (0, 0))
                sprites.draw(screen)
                pygame.display.flip()
    

The real deal!

Gameplay Mechanics

Collision detection

4 основни подхода

Препядствия

Ще добавим стени, че да не ни бяга човечето, също биха били полезни

        self.walls = pygame.sprite.Group()
        block = pygame.image.load('block.png')
        for x in range(0, 640, 32)
            for y in range(0, 480, 32):
                if x in (0, 640-32) or y in (0, 480-32)
                    wall = pygame.sprite.Sprite(self.walls)
                    wall.image = block
                    wall.rect = pygame.rect.Rect((x, y), block.get_size())
        sprites.add(self.walls)
    

Сблъсъци с препядствията

        last = self.rect.copy()
        for cell in pygame.sprite.spritecollide(self, game.walls, dokill=False)
            self.rect = last
    

Прецизни сблъсъци

        new = self.rect
        for cell in pygame.sprite.spritecollide(self, game.walls, False)
            cell = cell.rect
            if last.right <= cell.left and new.right > cell.left
                new.right = cell.left
            if last.left >= cell.right and new.left < cell.right
                new.left = cell.right
            if last.bottom <= cell.top and new.bottom > cell.top
                new.bottom = cell.top
            if last.top >= cell.bottom and new.top < cell.bottom
                new.top = cell.bottom
    

И още...

Още въпроси?