Lekce 6 - Skákačka v Pygame - Plánujeme hru
V minulé lekci, Pygame - Pong - Logika stavů hry a dokončení, jsme programovali logiku jednotlivých stavů hry a dokončili tak hru Pong.
V následujícím tutoriálu Pygame zahájíme větší
projekt. Ukážeme si postupně, jak naprogramovat první pořádnou hru pomocí
knihovny Pygame
- Skákačku. V této lekci se zaměříme na
složkovou strukturu a herní smyčku. Hra
bude vypadat následovně:

Plánujeme Skákačku v
Pygame
Před každým velkým projektem je nejprve potřeba ujasnit si naše představy o něm. Nejprve si tedy rozebereme, co vlastně definuje takovou „pořádnou“ hru:
- herní engine, co řídí celou hru,
- grafické objekty jako je zeď nebo figurka hráče, schopné detekovat kolize s jinými objekty, či pohybovat se,
- různě obtížné levely,
- hudba v pozadí.
Nyní zkusíme propojit tuto představu s tím, co již známe z
předchozích lekcí. Pod herním enginem si můžeme představit objekt typu
Game
. Ten bude obsahovat herní smyčku, která bude operovat s
Pygame `eventy. Se zvukem jsme již také pracovali. V knihovně `Pygame
s ním operuje modul pygame.mixer
a jeho podtřída
pygame.mixer.Sound
, kterým musíme předat zdrojový soubor zvuku.
Co přidáme nově, budou grafické objekty a levely.
Grafika
Grafické objekty jsou v lecčem podobné zvukům. V Pygame
je
sice nereprezentuje samotná třída, avšak stejně jako u
pygame.mixer.Sound
je k jejich operování potřeba ta grafická
část – obrázek v paměti. Protože je budeme muset ovládat sami,
zaslouží si vlastní třídu. Nejlépe jednu pro obrázky obecně a pak pro
každý typ jednu podtřídu, která bude dědit z třídy sobě
nadřazené.
Levely
Co se levelů týče, ty si také budeme muset uložit externě mimo kód. Aby se nám jednotlivé úrovně dobře vymýšlely, hodilo by se je mít graficky. Jenže to by se zase hodně špatně četlo počítači. Zvolme proto kompromis a zpracujme je jako text. Zavedeme klíčová slova/znaky pro jednotlivé objekty, ze kterých se bude skládat daná herní plocha. K přenosu tohoto typu dat se momentálně používají tři formáty.
CSV a XML
CSV je zkratka z anglického comma separated values, neboli čárkami
oddělené hodnoty. Název je v tomto případě velmi výstižný: čárkami
oddělené hodnoty jsou totiž zhruba vše, co v tomto formátu najdeme.
Kdybychom si tedy chtěli uložit náš level, vypadalo by to například takto:
zeď, hráč, vzduch, vzduch, cíl
.
No dobrá, ale co kdybychom chtěli víceřádkové levely? A jak bychom úrovně vůbec odlišili od sebe? CSV je skvělé, když potřebujeme přenášet obrovské množství dat, protože jediné, co obsahuje, jsou data samotná. To se nám ale příliš nehodí.
Naproti tomu XML tohle má vyřešené pěkně. Používá totiž
hierarchickou strukturu podobnou HTML. Díky tomu však znatelně narůstá
objem dat. Už jen pro uložení jednoho prvku bychom potřebovali tři
„slova“: počáteční tag, vlastní prvek a koncový tag. My však nebudeme
potřebovat tolik hierarchických oddílů, aby se nám XML
vyplatilo. Takže co s tím?
JSON
JSON je formát, který kombinuje přednosti jak CSV tak XML – má dobře vyvinutou hierarchii a není tak paměťově rozsáhlý. Nabízí se otázka, proč se tedy nepoužívá jenom JSON. Je to proto, že obě z těchto výhod dělá o něco hůře než původní formáty. Pro naše účely je však JSON ideálním kompromisem. Data totiž řadí do struktur podobných slovníkům a seznamům v Pythonu. To nám výrazně usnadní vytváření jejich alternativ v programu.
Logování
Formáty všeho máme rozhodnuty, zbývá tedy už jen poslední krok do
začátku programování. Pouštíme se do velikého projektu a v těch je
občas složité se vyznat. Proto do našeho kódu zahrneme i knihovnu
logging
. Ta umožňuje programu poslat upozornění, že nastala
určitá situace. Ta bývá obvykle popsána, přičemž tento popis může
obsahovat i hodnoty proměnných. Navíc tato knihovna umožňuje zavést
samostatný soubor, kam se tyto zprávy budou ukládat, či rozlišit
důležitost a úroveň hlášení.
Struktura
Pojďme si tedy připravit strukturu našeho kódu. Vytvoříme si složku
našeho projektu a pojmenujeme ji Skakacka/
. V ní vytvoříme
soubor main.py
, který bude první, co se spustí. Pro další kód
přidáme podsložky engine/
a game_scr/
, kde budou
zdroje objektů hry, a res/
(zkratka z resources), kam budeme
ukládat všechny nekódové části naší hry – obrázky, zvuky, nebo i
fonty. Podle těchto zdrojů vytvoříme i podsložky v res/
:
fonts/
, imgs/
, sounds/
a
music/
. Rozlišíme tak zároveň i zvuky, jenž se přehrají
jednou při nějaké akci (sounds) a hudbu, co bude hrát v pozadí (music).
Herní smyčka
Nyní už se můžeme vrhnout na samotné programování. V složce
engine/
vytvoříme soubor game.py
. Zde bude hlavní
část celého programu – třída Game. Naimportujeme sem tedy knihovnu Pygame
a vytvoříme zatím prázdnou třídu Game
. V jejím konstruktoru
zároveň zinicializujeme samotnou instanci pygame
:
import pygame class Game: def __init__(self): pygame.init()
Do konstruktoru také přidáme parametr self._is_running
,
který zde nastavíme na True
. Protože tento parametr by se měl
ovlivňovat pouze skrz metody třídy (jelikož má podtržítko na začátku
názvu – v Pythonu nám to sice nikdo nezakáže, ale je to programátorská
konvence), odpovídající metodu musíme vytvořit. Vzhledem k tomu, že
self._is_running
nám říká, jestli hra běží nebo ne, naši
metodu pojmenujeme end()
, aby bylo jasné, že naši hru
ukončuje:
class Game: def __init__(self): self._running = True pygame.init() def end(self): self._running = False
Poslední metoda, kterou si v této lekci vytvoříme, bude
run()
. Jak už název napovídá, v této metodě poběží
samotná hra. Bude se zde tedy nacházet naše stará známá herní smyčka. Ta
jako obvykle poběží, dokud bude self._is_running
rovno
True
a pro každý průchod smyčkou načte seznam vygenerovaných
eventů. Pokud jeden z nich bude pygame.QUIT
, pak zavolá
self.end()
a zavře pygame
:
class Game: def __init__(self): self._running = True pygame.init() def end(self): self._running = False def run(self) -> None: while self._running: for event in pygame.event.get(): if event.type == pygame.QUIT: self.end() pygame.quit()
Pokud bychom si teď vytvořili instanci Game
a zavolali na ní
metodu run()
, dojdeme k zajímavému závěru: nic se nestane To proto, že knihovna
pygame
se pouze úspěšně zinicializovala a nic jiného podle
programu dělat neměla. Abychom se však ujistili, že vše děláme správně,
vytvoříme si ještě okno, které na nás po začátku hry vyskočí. Do
konstruktoru třídy Game
přidáme tedy
self.display: pygame.Surface = pygame.display.set_mode((600, 600))
a do naší smyčky pod for
cyklus přidáme
pygame.display.flip()
. Celý program tedy momentálně vypadá
takto:
import pygame class Game: def __init__(self): self._running = True pygame.init() self.display: pygame.Surface = pygame.display.set_mode((600, 600)) def end(self): self._running = False def run(self) -> None: while self._running: for event in pygame.event.get(): if event.type == pygame.QUIT: self.end() pygame.display.flip() pygame.quit() game = Game() game.run()
Tento program po spuštění vytvoří černé okno, které budeme moct zavřít. Příště se ve tvorbě naší hry zase posuneme o kus dál. Zdrojový kód včetně adresářové struktury Skákačky najdete na konci lekce.
V další lekci Skákačka v Pygame - Logging zjistíme, jak si udržet přehled o průběhu
projektu naší Skákačky pomocí knihovny logging
.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 14x (4.7 kB)
Aplikace je včetně zdrojových kódů v jazyce Python