22. PyGame
Защо искаме да правим игри?
- Забавни са
- Предлагат ни изцяло нов начин на мислене
Колко точно различно е?
- Дребните детайли са критични
- Зависите от ресурсите на потребителската машина
- Физика, Изкуство, Музика, Математика...
Основните ни занимания
- Показваме неща на екрана
- Обработваме потребителски вход
- Механика
- Звуци и музика
- Завършена архитектура на една игра
Показваме неща на екрана
- Отваряме прозорец
- Чертаем разни неща
- Местим вече налични такива
- И за всичко това ще ни трябват event-и
Безкрайният цикъл
Цялата ни игра е един безкраен цикъл, в който обработваме 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)
Чертаене
- Координатна система
- fill & blit
- flip
- pygame.time.Clock
- Scene construction
FPS
Различни машини - различни възможности.
- pygame.time.Clock
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
- Events
- State dictionary
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
- Player Controls
- Timed rules - кога се появяват обекти, как се движат по полето и кога са излишни
- Интеракция с другите обекти(collision detections)
- Строго следене за важните събития
Collision detection
4 основни подхода
- Axis-Aligned Bounding Box
- Circle-Circle
- HashMap
- Pixel-Perfect
Препядствия
Ще добавим стени, че да не ни бяга човечето, също биха били полезни
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
И още...
Още въпроси?
- Пишете ни на fmi@py-bg.net
- Страница на курса: http://fmi.py-bg.net/
- Форуми на курса: http://fmi.py-bg.net/topics
- Курсът в Twitter: http://twitter.com/pyfmi
- Курсът във Facebook: http://www.facebook.com/group.php?gid=104970619536589