Pokročílí 13: Pygame¶
Dnes si vysvetlíme základy knižnice Pygame a vytvoríme si jednoduchú 2D hru
Pygame¶
Pygame je knižnica pre tvorbu 2D hier v Pythone. Stránka tohto projektu je https://www.pygame.org. Obsahuje dokumentáciu a množstvo návodov.
Knižnicu Pygame vieme nainštalovať klasicky pomocou pip install pygame
Funkcionality tejto knižnice sú prístupné v module pygame. Pred prvým použitím knižnice je potrebné spustiť inicializáciu pomocou pygame.init()
Vytvorenie hlavného okna¶
V Pygame pracujeme s oknom, do ktorého budeme vykresľovať grafiku hry. Pri vytvorení okna je potrebné zadať jeho veľkosť. Premennú s objektom okna je potrebné si zapamätať, pretože funkcie na vykresľovanie vyžadujú okno ako prvý argument.
- okno vytvoríme pomocou
screen = pygame.display.set_mode((SIRKA, VYSKA)) - titulok okna zadefinujeme pomocou
pygame.display.set_caption("Titulok")
Farby¶
Farby sú reprezentované ako tuple s tromi alebo štyrmi hodnotami (RGB alebo RGBA). Hodnoty sú v rozsahu 0 až 255, pričom (0, 0, 0) predstavuje čiernu farbu a (255, 255, 255) predstavuje bielu farbu.
Prvý prvok je červená zložka, druhý zložka zelená a tretí zložka modrá. (Štvrty prvok je alfa zložka, ktorá určuje priehľadnosť farby)
Trieda Rect¶
Väčšina vecí v 2D hrách funguje na princípe obdĺžnikov. Či už ide o vykresľovanie, hitbox alebo písanie textu, väčšinou je k tomu potrebné mať obdĺžnik, ktorý určuje miesto na obrazovke.
V Pygame na reprezentáciu obdĺžnikov máme triedu Rect.
Vytvorenie nového rect objektu robíme pomocou konštruktora pygame.Rect(x, y, width, height). Táto trieda nám poskytuje rôzne atribúty, pomocou ktorých môžeme zistiť ale aj meniť jeho vlastnosti:
| Atribút | Typ | Popis |
|---|---|---|
x |
int | X-ová súradnica ľavého okraja. |
y |
int | Y-ová súradnica horného okraja. |
width (w) |
int | Šírka obdĺžnika. |
height (h) |
int | Výška obdĺžnika. |
topleft |
(x, y) | Horný-ľavý roh. |
topright |
(x, y) | Horný-pravý roh. |
bottomleft |
(x, y) | Dolný-ľavý roh. |
bottomright |
(x, y) | Dolný-pravý roh. |
center |
(x, y) | Stred obdĺžnika. |
centerx |
int | X-ová súradnica stredu. |
centery |
int | Y-ová súradnica stredu. |
top |
int | Y-ová súradnica hornej hrany. |
bottom |
int | Y-ová súradnica spodnej hrany. |
left |
int | X-ová súradnica ľavej hrany. |
right |
int | X-ová súradnica pravej hrany. |
Detekcia kolízie¶
Trieda Rect nám poskytuje metódy na detekciu kolízie dvoch obdĺžnikov.
rect.colliderect(other_rect)vráti true, ak sa obdĺžniky prekrývajúrect.contains(other_rect)vráti true, ak je obdĺžnikother_rectcelý vo vnútri obdĺžnikarect.collidepoint(x, y)vráti true, ak je bod(x, y)vo vnútri obdĺžnika
Vykresľovanie¶
Vykresľovanie tvarov¶
Vykresľovanie rôznych tvarov sa robí pomocou modulu pygame.draw
pygame.draw.rect(screen, color, rect)- vykreslí obdĺžnikpygame.draw.ellipse(screen, color, rect)- vykreslí elipsupygame.draw.line(screen, color, start_pos, end_pos, width = 1)- vykreslí čiaru
Vykresľovanie textu¶
Vykresľovanie textu sa robí pomocou modulu pygame.font. Najpr je potrebné mať vytvorený font.
font = pygame.font.SysFont(None, size)vráti defaultný systémový fontfont = pygame.font.SysFont(nazov, size)vráti systémový font s daným názvom, napr. "Times New Roman" alebo "Arial"
Ak máme objekt s fontom, vieme vykresliť text pomocou font.render a potom je potrebné vykreslený text umiestniť na obrazovku pomocou screen.blit:
Udalosti¶
Počas hry môžu nastať rôzne udalosti, napríklad môže byť stlačená klávesa alebo tlačítko myšky. Takéto jednorázové udalosti je možné zachytiť pomocou modulu pygame.event.
Držanie stlačenej klávesy¶
Okrem jednorázových udalostí je často potrebné vedieť, či je aktuálne nejaká klávesa stlačená alebo nie. To sa dá zistiť pomocou modulu pygame.key
Hlavná herná slučka¶
Hra zvyčajne beží v nekonečnom cykle. Jedna iterácia je jeden tick alebo frame - snímka. Aby sa herná slučka neopakovala veľmi rýchlo, je potrebné nastaviť počet snímkov za sekundu (FPS - frames per second) a použiť triedu Clock, ktorá nám spomalí hlavnú slučku na požadované FPS.
Úloha hlavnej slučky je zachytiť a spracovať udalosti, aktualizovať stav sveta hry a potom vykresliť hru na obrazovku.
Všetko ostatné je potrebné si pripraviť vopred. Je zbytočné vytvárať fonty a načítavať obrázky v každej iterácii slučky, v každom frame. Spomaľuje to vykresľovanie a môže to zaplniť pamäť alebo vnútorné úložisko zdrojov.
clock = pygame.time.Clock()
while True:
# 1. Spracovanie udalosti
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
...
# 2. Aktualizácia stavu hry, napr. pohyb objektov
update()
# 3. Vyčistiť obraz
screen.fill((0, 0, 0))
# 4. Vykresliť tvary, text a obrázky
draw()
# 5. Zobraziť na obrazovku
pygame.display.flip()
# 6. Spomaliť na dané FPS
clock.tick(60)
Úlohy na hodine¶
Dnes si vytvoríme hru Pong. Základné vlastnosti:
- hra pre dvoch hráčov
- každý hráč ovláda dosku na kraji obrazovky, ľavom a pravom
- hráč vie doskou pohybovať hore a dole
- po obrazovke lieta lopta a odráža sa od hornej a dolnej steny a od dosiek
- cieľom je dostať loptu za súperovú dosku, dať gól
Úloha 13.1: Hra Pong
-
V novom alebo v existujúcom projekte si nainštalujeme pygame pomocou
pip install pygame -
Vytvoríme si modul
pong.py -
V module si importneme modul
pygamea zavoláme metódupygame.init() -
V moduli si zadefinujeme nasledovné konštanty:
Úloha 13.2: Trieda Paddle
Vytvoríme si triedu Paddle, ktorá bude reprezentovať dosku. Táto trieda bude mať metódy na vykreslenie a na aktualizáciu stavu - pohyb - podľa toho, ktorá klávesa je stlačená
-
Vytvorte triedu
Paddlea v nej konštruktor s parametramix,y,sirka,vyska,rychlost. Niektorým parametrom dajte defaultné hodnoty:sirka=15,vyska=100,rychlost=8. Trieda nech má 2 atribúty:rychlosta obdĺžnikrect, ktorý vytvoríte zo vstupných argumentov konštruktora. -
Vytvorte metódu
draw(self, screen), ktorý vykreslí biely (WHITE) obdĺžnikrectna obrazovku pomocoupygame.draw. -
Vložte do triedy nasledovnú metódu na aktualizáciu stavu:
Úloha 13.3: Trieda Ball
Vytvoríme si triedu Ball, ktorá bude reprezentovať loptu. Táto trieda bude mať metódy na vykreslenie a na aktualizáciu stavu - pohyb, a taktiež metódu na resetovanie lopty po góle
-
Vytvorte triedu
Balla v nej konštruktor s parametramivelkostarychlost. Parametrom dajte defaultné hodnoty:velkost=25,rychlost=6. Trieda nech má 2 atribúty:rychlosta štvorecrect, ktorý bude mať veľkosť podľa vstupného argumentu. Na konci konštruktora zavolajte metódureset, ktorú si vložíme v ďalšom bode -
Importujte si modul
randoma vložte do triedy nasledovnú metódu na resetovanie stavu: -
Vytvorte metódu
draw(self, screen), ktorý vykreslí biely (WHITE) kruh na mieste štvorcarectna obrazovku pomocoupygame.draw.ellipse. -
Vytvorte metódu
move(self), ktorá pripočíta k atribútomxayštvorcerecthodnotyspeed_xa `speed_y
Úloha 13.4: Trieda PongGame
-
Vytvorte triedu
PongGames nasledovným kódom:class PongGame: def __init__(self): self.screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("Pong - OPGP") self.clock = pygame.time.Clock() # Game objects paddle_y = HEIGHT // 2 - 50 self.left_paddle = Paddle(30, paddle_y) self.right_paddle = Paddle(WIDTH - 45, paddle_y) self.ball = Ball() def handle_collision(self): # Top/Bottom walls if self.ball.rect.top <= 0 or self.ball.rect.bottom >= HEIGHT: self.ball.speed_y *= -1 # Paddle collisions if self.ball.rect.colliderect(self.left_paddle.rect) and self.ball.speed_x < 0: self.ball.speed_x *= -1 if self.ball.rect.colliderect(self.right_paddle.rect) and self.ball.speed_x > 0: self.ball.speed_x *= -1 def check_scoring(self): if self.ball.rect.left <= 0: self.ball.reset() if self.ball.rect.right >= WIDTH: self.ball.reset() def run(self): while True: for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() # Move ## TODO # Update self.handle_collision() self.check_scoring() # Draw ## TODO pygame.display.flip() self.clock.tick(FPS) -
V časti
# Moveje potrebné doplniť pohyb objektov nasledovne- zavolajte metódu pohybu ľavej dosky s klávesami
pygame.K_wapygame.K_s(pozrite si, ako je metóda na pohyb naimplementovaná) - zavolajte metódu pohybu pravej dosky s klávesami
pygame.K_UP,pygame.K_DOWN - zavolajte metódu pohybu lopty
- zavolajte metódu pohybu ľavej dosky s klávesami
-
V časti
# Drawje potrebné doplniť vykresľovanie objektov nasledovne- vyčistite obrazovku pomocou
self.screen.fill - vykreslite ľavú dosku
- vykreslite pravú dosku
- vykreslite loptu
- vyčistite obrazovku pomocou
Úloha 13.5: Spustenie hry
Hru vieme spustiť tak, že vytvoríme objekt triedy PongGame a zavoláme jeho metódu run.
Hru si môžete zahrať. Ak je príliš náročná alebo naopak ľahká, zmeňte rýchlosti a dĺžky dosiek.
Hra je funkčná, ale chýba jej veľa vecí. V ďalších úlohách ju vylepšíme.
Úlohy na precvičenie¶
Úloha 13.6: Pridanie stredovej čiary
-
V triede
PongGamevytvorte metódudraw_center_lines nasledovným kódom: -
Zavolajte túto metódu v hlavnej slučke pri vykresľovaní
Úloha 13.7: Počítanie skóre
Vytvoríme triedu, ktorá bude uchovávať skóre a vykresľovať ho na obrazovku.
-
Vytvorte triedu
Scores atribútmileft_scorearight_score. Obe inicializujte na 0. V konštruktore tiež vytvorte atribútfont, ktorý inicializujte napygame.font.SysFont(None, 74) -
Vytvorte metódy goal_left() a goal_right(), ktoré budú zvyšovať skóre odpovedajúcej strany.
-
Vložte do triedy nasledovnú metódu na vykresľovanie:
-
V konštruktore triedy
PongGamesi vytvorte atribútscores objektom triedyScore. V hlavnej slučke zavolajte vykresľovanie skóre. -
V metóde
check_scoringzavolajte metódugoal_left()alebogoal_right()podľa toho, kto vyhral
Úloha 13.8: Zmena uhla lopty
Lopta letí stále pod rovnakým uhlom. Tento uhol teraz zmeníme tak, že uhol bude závisieť od toho, v akom bode dosky sa lopta odrazila. Ak sa odrazila bližšie pri strede, uhol bude menší. Ak pri okraji, uhol bude väčší.
-
Pridajte do triedy
PongGamenasledovnú metódu: -
Zavolajte túto metódu v metóde
handle_collisionv situáciách, keď lopta narazila a otáča sa
Úloha 13.9: Game Over
Hra nemá koniec. Upravte kód tak, aby sa hra skončila ak niektorý z hráčov dosiahne určité skóre. Na konci vypíšte "Game Over" a kto hru vyhral.
Úloha 13.10: Hra pre troch hráčov
Upravte hru tak, aby bola pre troch hráčov. Tretí hráč bude mať dosku v dolnej časti obrazovky.
Zhrnutie cvičenia¶
- Pygame, knižnica na tvorbu 2D hier, https://www.pygame.org
- Inštalácia pomocou
pip install pygame - Modul
pygame - Pred prvým použitím knižnice je potrebné spustiť inicializáciu pomocou
pygame.init()
- Inštalácia pomocou
- Hlavné okno
- Okno vytvoríme pomocou
screen = pygame.display.set_mode((SIRKA, VYSKA)) - Titulok okna zadefinujeme pomocou
pygame.display.set_caption("Titulok")
- Okno vytvoríme pomocou
- Farby
- Farby sú reprezentované ako tuple s tromi alebo štyrmi hodnotami (RGB alebo RGBA)
- Hodnoty sú v rozsahu 0 až 255, pričom (0, 0, 0) predstavuje čiernu farbu a (255, 255, 255) predstavuje bielu farbu.
- Prvý prvok je červená zložka, druhý zložka zelená a tretí zložka modrá
- Trieda Rect - obdĺžnik
- Vytvorenie nového rect objektu robíme pomocou konštruktora
pygame.Rect(x, y, width, height) - Trieda poskytuje rôzne atribúty ako napr.
x,y,width,height, ... - Detekcia kolízie pomocou
rect.collidepoint(x, y)arect.colliderect(other_rect)
- Vytvorenie nového rect objektu robíme pomocou konštruktora
- Vykresľovanie tvarov pomocou
pygame.draw-
pygame.draw.rect(screen, color, rect)- vykreslí obdĺžnik -
pygame.draw.ellipse(screen, color, rect)- vykreslí elipsu -
pygame.draw.line(screen, color, start_pos, end_pos, width = 1)- vykreslí čiaru
-
- Vykresľovanie textu pomocou
pygame.font- Najpr je potrebné mať vytvorený font, pomocou
font = pygame.font.SysFont(nazov, size) - Vykresliť text vieme pomocou
font.rendera potom je potrebné vykreslený text umiestniť na obrazovku pomocouscreen.blit
- Najpr je potrebné mať vytvorený font, pomocou
- Udalosti - Jednorázové udalosti, napr. kliknutie myšou, stlačenie klávesy, ...
- Udalosti je možné zachytiť pomocou modulu
pygame.event - Udalosti získame pomocou
pygame.event.get()
- Udalosti je možné zachytiť pomocou modulu
- Držanie stlačenej klávesy - pretrvávajúce stavy
- Stav stlačenia kláves zistíme pomocou
klavesy = pygame.key.get_pressed()
- Stav stlačenia kláves zistíme pomocou
- Hlavná herná slučka - hra beží v nekonečnom cykle
- Jedna iterácia je jeden tick alebo frame - snímka
- Trieda
pygame.time.Clockumožňuje spomaliť cyklus na požadované FPS - Úloha hlavnej slučky je zachytiť a spracovať udalosti, aktualizovať stav sveta hry a potom vykresliť hru na obrazovku.
- Všetko ostatné je potrebné si pripraviť vopred. Je zbytočné vytvárať fonty a načítavať obrázky v každej iterácii slučky, v každom frame
Poznámky do zošita
V zošite je potrebné mať napísané aspoň tieto poznámky:
PYGAME
Knižnica na tvorbu 2D hier, https://www.pygame.org
Inicializácia pomocou pygame.init()
Okno pomocou pygame.display.set_mode((SIRKA, VYSKA))
Farby sú reprezentované ako tuple (R, G, B) v intervaloch 0-255
Trieda Rect - obdĺžnik, pygame.Rect(x, y, width, height)
Detekcia kolízie pomocou rect.colliderect(other_rect)
Vykresľovanie tvarov: pygame.draw.rect, pygame.draw.ellipse, pygame.draw.line
Vykresľovanie textu v 3 krokoch: pygame.font.SysFont, font.render, screen.blit
Jednorázové udalosti (klik myšou, stlačenie klávesy): pygame.event.get
Stav klávesnice - pygame.key.get_pressed()
Hlavná herná slučka - hra beží v nekonečnom cykle
Jedna iterácia je jeden tick alebo frame - snímka
pygame.time.Clock umožňuje spomaliť cyklus na požadované FPS
Úloha hlavnej slučky je zachytiť a spracovať udalosti,
aktualizovať stav sveta hry a potom vykresliť hru na obrazovku.
Všetko ostatné je potrebné si pripraviť vopred.
Je zbytočné vytvárať fonty a načítavať obrázky v každej iterácii slučky, v každom frame
Skúšanie a kontrola vedomostí
Okruhy otázok na test:
- Čo je pygame a na čo slúži
- Na čo je trieda Rect
- Čo je hlavná slučka a aké má použitie
- Čo sú udalosti a ako sa dajú spracovať