8. diel - Skákačka v Pygame - Obrázky
V minulej lekcii, Skákačka v Pygame - Tvorba okna a pohyb postavy , sme sa dozvedeli o tvorbe okna, vytvorení a pohybe postavy, alebo aj ako vkladať obrázky v Pygame.
V tomto tutoriále Pygame v Pythone v našom projekte
Skákačky pokročíme k práci s obrázkami. Vytvoríme si pre
nich triedu Image.
Súbor pre obrázky a zvuky
Aby sa nám s obrázkami dobre pracovalo, vytvoríme si pre nich vlastnú
triedu. Pretože ale z rozboru vieme, že podobným spôsobom budeme chcieť
pracovať aj so zvukmi, vytvoríme pre tieto dve triedy jeden súbor, aby boli
pohromade. Súbor pomenujeme media.py a vytvoríme ho v priečinku
engine/. Budeme tu používať knižnice pygame a
logging, takže ich naimportujeme:
import pygame import logging
Teraz krátko odbočíme na logovanie. Chceme vedieť, či nám hra hlási
niečo o priebehu z pohľadu hráča (napríklad posun jeho figúrky) alebo z
pohľadu programu (naimportovanie obrázku). Vytvoríme si preto novú
inštanciu triedy Logger, ktorú budeme používať na tieto
programové udalosti. Na začiatok súboru game.py (kde sa bude
odohrávať väčšina týchto udalostí) hneď pod import pridáme:
import logging GameEngineLogger = logging.getLogger("Engine")
Aby sme sa k tomuto objektu mohli dostať aj v media.py, musíme
ho tam tiež naimportovať:
from engine.game import GameEngineLogger
Trieda Image
Teraz sa konečne môžeme vrhnúť na samotnú triedu Image.
Napíšeme hlavičku class Image:, než sa však vrhneme na
konštruktor, pridáme ešte premenné. Tieto budú prístupné všetkým
inštanciám triedy Image a pôjdu zmeniť iba cez meno triedy.
Premenné triedy Image
Ako prvé pridáme premennú default_dir, z ktorej sa budú
načítavať obrázky. Uložíme do nej ., čiže zložku, v ktorej
sa momentálne nachádzame. Ďalšou bude _accepted_extensions, kam
uložíme zoznam možných prípon obrázkov. Poslednú premennú pomenujeme
_images_cache. Do nej budeme ukladať už načítané obrázky.
Lenže ako chceme obrázky vlastne ukladať?
Aby naša hra vyzerala o niečo živšie, budeme chcieť, aby sa nám
obrázky menili. Vlajka bude viať vo vetre, lietajúci hmyz bude mávať
krídlami, nepriatelia nebudú pri pohybe tam a späť cúvať, ale otočia sa a
pôjdu iným smerom. Ale ako to urobiť? Použijeme na to ten najjednoduchší
(aj keď nie práve algoritmický) spôsob. Jednoducho si uložíme viac
obrázkov a budeme ich periodicky meniť. Budeme si však musieť pamätať,
ktoré skupinky obrázkov patria k sebe. Preto bude fajn mať ich všetky v
rámci jedného Image objektu. V _images_cache bude
teda uložený slovník. Jeho kľúče budú mená objektov v hre a hodnoty
budú zoznamy všetkých pygame verzií obrázkov (budú to teda
objekty typu pygame.surface). Aby sme na toto nezabudli, radšej si
to poznamenáme pomocou knižnice typing. Predpripravíme si u nej
aj iné dátové typy, než potrebujeme, aby sme sa sem neskôr nemuseli
vracať. Celý súbor media.py teraz teda vyzerá takto:
import pygame import logging from typing import Dict, Set, Optional, List, Callable from engine.game import GameEngineLogger class Image: default_dir = '.' _accepted_extensions = ['.png', '.jpg', '.gif', '.bmp'] _images_cache: Dict[str, List[pygame.Surface]] = {}
Konštruktor
A teraz už konečne prejdeme ku konštruktoru. Na to, aby sme mohli obrázok správne načítať, budeme potrebovať:
- meno obrázku,
- veľkosť, na ktorú ho chceme zmeniť,
- info, či chceme obrázok vôbec načítať.
__init__() teda bude vyzerať
takto:
def __init__(self, image_name: str, convert_size: (int, int) = None, load: bool = True):
Teraz spíšeme atribúty inštancie triedy Image:
self.name– meno obrázku z__init__,self.speed- koľko iterácií hernej slučky musí prebehnúť, aby sa obrázok premenil na svoju ďalšiu „fázu“. Ako základná hodnota tu bude nula, ktorú použijeme ako deaktiváciu zmeny obrázku,self._image_index– index obrázku, ktorý sa práve zobrazuje,self._image_tick– koľko slučiek ubehlo od poslednej zmeny,self._size– veľkosť obrázku vo formáte (šírka, výška), zatiaľ nastavená na nulu, pretože nemáme žiadny obrázok načítaný.
self._game (konkrétne
inštancie práve bežiacej hry) a self._subimages (zoznam
obrázkov v rámci jedného objektu):
self.name = image_name self.speed = 0 self._image_index = 0 self._image_tick = 0 self._size = (0, 0) self._game = None self._subimages = None
Ďalšou vecou, ktorú musíme urobiť, je nevytvárať znovu obrázok,
pokiaľ už je v našej cache pamäti. Pokiaľ tam teda je, do
self._subimages príde hodnota cache pod menom obrázku. Zároveň
ohlásime načítanie z pamäte cez logging:
if image_name in self._images_cache: GameEngineLogger.debug(f"Image {image_name} is in cache") self._subimages = self._images_cache[image_name]
Teraz však už máme načítané obrázky av atribúte
self_size tak nemôže zostať hodnota (0,0). Budeme
ju musieť zmeniť a aby sa nám nestalo, že bude niektorý z obrázkov
väčší ako uložená hodnota, prejdeme ich všetky. Do atribútu
self_size uložíme najväčšiu šírku a najväčšiu dĺžku.
Vytvoríme na to metódu self._get_size(), ktorá bude vyzerať
takto:
def _count_size(self) -> (int, int): max_w = 0 max_h = 0 for sub in self._subimages: w, h = sub.get_size() if w > max_w: max_w = w if h > max_h: max_h = h self._size = (max_w, max_h) return self._size
Túto metódu zavoláme v našej momentálnej vetve konštruktora
__init__() a potom zavoláme return, aby sme
konštruktor v tejto vetve ukončili a neprepísali si načítané obrázky
ďalším kódom:
if image_name in self._images_cache: GameEngineLogger.debug(f"Image {image_name} is in cache") self._subimages = self._images_cache[image_name] self._count_size() return
Ďalšia okrajová podmienka sa týka našej premennej load z
hlavičky __init__(). Ak by totiž bola False, nemalo
by sa nič načítať. Navyše by sme mali z cache pamäte odstrániť
podobrázky, pokiaľ by tam boli. Táto vetva teda bude vyzerať takto:
if not load: GameEngineLogger.debug(f"Image {image_name} is not due to load") if not self._subimages: GameEngineLogger.debug(f"Image {image_name} has not been loaded, emptying all subimages") self._images_cache[image_name] = self._subimages = [] return
V tejto lekcii sme síce nijako nezmenili vizuál hry, avšak pripravili sme si podstatnú časť kódu pre budúcu podobu Skákačky. Kompletný zdrojový kód je na stiahnutie pod lekciou.
V ďalšej lekcii, Skákačka v Pygame - Obrázky - Načítanie, dokončíme načítanie obrázkov pre Skákačku.
Zameriame sa tiež na funkcie map() a lambda().
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 18x (9.14 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python

