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