2. diel - Pygame - Kreslenie a pohyb
V minulej lekcii, Pygame - Úvod & inštalácia , sme si pygame predstavili a nainštalovali. V dnešnej lekcii sa naučíme, ako kresliť tvary na obrazovku a ako s nimi pohybovať. Zároveň si tiež povieme niečo málo o tom, ako má vyzerať herný cyklus.
Spätná kompatibilita
Aby sme zachovali spätnú kompatibilitu so všetkými verziami
pygame
, budeme importovať pygame
nasledujúcim
spôsobom:
try: # noinspection PyUnresolvedReferences import pygame_sdl2 pygame_sdl2.import_as_pygame() except ImportError: pass import pygame
Tento postup nám zaručí, že nech už máme nainštalovanú akúkoľvek
verziu pygame
, budeme sa na ňu môcť odkazovať iba pomocou
pygame
.
Otvárame naše prvé okno
Keď chceme pygame
používať, musíme ho najskôr
inicializovať. K tomu slúži funkcia pygame.init()
.
Akonáhle máme inicializácii dokončenú, vytvoríme si okno hry. Okno sa
vytvára pomocou funkcie pygame.display.set_mode()
. Funkcia berie
ako svoj prvý parameter tuple s rozmermi vytvoreného okna:
pygame.init() screen = pygame.display.set_mode((800, 600)) # vytvoří okno o velikosti 800x600
Ak chceme okno maximalizovať cez celú obrazovku, ako hodnoty použijeme
0
. Zároveň, ak by sme chceli odstrániť všetky okná, ako
druhý parameter použijeme pygame.FULLSCREEN
.
pygame.init() screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN) # vytvoří fullscreen okno
Upozornenie: Vytváranie okna vo fullscreen bez
predchádzajúcej implementácia ukončenia pygame
spôsobí, že
sa objavia čierne okno cez celú obrazovku, ktoré zachytáva všetky klávesy.
Dostať sa z takéhoto okna je vysoko ťažké.
Vďaka tomuto máme v premennej screen
uložený objekt typu
Surface
, čo je v pygame
reprezentácie akejkoľvek
grafiky.
Keď nás potom naše okno prestane baviť, použijeme funkciu
pygame.quit()
, ktorá ukončí celé pygame
.
Kreslíme tvary
Ak chceme v pygame
maľovať rôzne tvary, ponúka nám
jednoduchú možnosť skrze svoj podmodul pygame.draw
.
Ukážeme si najčastejšie príklady:
- kruh:
pygame.draw.circle(povrch, barva, (x, y), poloměr)
-(x, y)
udáva stred - obdĺžnik:
pygame.draw.rect(povrch, barva, obdélník)
, kde obdĺžnik je objekt triedyRect
. Ten ide vytvoriť akopygame.Rect(x, y, sirka, vyska)
.x
ay
udáva pozíciu ľavého horného rohu. - polygón:
pygame.draw.polygon(povrch, barva, body)
, kdebody
je zoznam tuple vo formáte(x, y)
- čiara:
pygame.draw.line(povrch, barva, start_pozice, konec_pozice)
Farba je tuple vo formáte
(červená, modrá, zelená, [průhlednost])
, kde všetky hodnoty
sú int
z rozsahu 0
- 255
.
Všetky tieto funkcie majú tiež voliteľný parameter width
. U
čiary určuje jej hrúbku, u ostatných tvarov určuje hrúbku ich výplne. Ak
je width
nastavený na 0
, čo je predvolená hodnota,
tvar je plne vyplnený.
Povrch je ľubovoľný objekt triedy Surface
, takže ním môže
byť akýkoľvek obrázok, alebo dokonca aj naše okno.
Kruh
Poďme si naše novo nadobudnuté vlastnosti hneď vyskúšať a Namaľujte si modrý kruh!
pygame.init() screen = pygame.display.set_mode((800, 600)) pygame.draw.circle(screen, (0, 0, 255), (400, 300), 150)
Skúste si tento kód spustiť. Čo sa stane?
Herné cyklus
V predchádzajúcom príklade sa nám okno otvorilo iba na chvíľu a hneď sa zavrelo. A ani ten kruh nebol vidieť. Čo sa stalo zle?
Odpoveď je jednoduchá: Interpreter došiel na koniec kódu a ukončil teda jeho implementácie. Zároveň sme nevideli ani na chvíľu náš kruh, pretože sme nepoužili funkciu na vykreslenie nového obsahu do okna. Poďme to teda hneď napraviť.
Definujme si nový pojem - krok. Krok je všetok kód,
ktorý chceme, aby sa periodicky vykonával vnútri našej hry. V našom
doterajšom kóde máme iba jeden krok, po ktorom sa vykonávania celej našej
hry ukončí. Tomu zamedzíme tým, že všetok kód, ktorý sa má vykonávať,
uzavrieme do slučky while True
. Na koniec slučky potom ešte
nesmieme zabudnúť pridať pygame.display.flip()
, čo spôsobí
aktualizáciu obrazovky:
pygame.init() while True: screen = pygame.display.set_mode((800, 600)) pygame.draw.circle(screen, (0, 0, 255), (400, 300), 150) pygame.display.flip()
výsledok:
Používame udalosti
Možno ste si všimli, že okno pygame
nešlo zavrieť inak,
než za použitia Ctrl + C v termináli. To je spôsobené
tým, že nijako neodchytáváme udalosť žiadosti o zatvorenie okna. Takéto
správanie nie je príliš intuitívne a tak by bol dobrý nápad ho
napraviť.
Zoznam všetkých udalostí získame pomocou zavolanie funkcie
pygame.event.get()
, cez ktorej výsledok môžeme iterovat a
porovnávať ho. Medzi často používané typy udalostí patria:
pygame.QUIT
- je zavolaná, keď sa niekto pokúsi ukončiť okno hrypygame.MOUSEBUTTONDOWN
- pri stlačení tlačidla myšipygame.MOUSEBUTTONUP
- pri uvoľnení tlačidla myšipygame.KEYDOWN
- pri stlačení nejakej klávesypygage.KEYUP
- pri uvoľnení nejakej klávesy
Malá poznámka: V Pygame_SDL2 sa môže stať, že vám nebude
fungovať rozpoznávanie stlačení klávesov šípok. Preto sa vo všetkých
kurzoch šípkam radšej vyvarujeme a budeme namiesto nich používať známe
W A S D. Zároveň som tiež narazil
na problém s pygame.KEYDOWN
vo verzii 1.9.6., Takže namiesto neho
budeme nateraz radšej používať pygame.KEYUP
.
Povedzme, že budeme chcieť ukončiť hru v dvoch prípadoch: Je o
ukončení požiadané alebo bola stlačená klávesa Esc. Keďže
nám teraz kód beží vnútri cyklu while True
, nedá sa z neho
tak ľahko vyskočiť. Preto si definujme radšej premennú
running = True
a budeme kontrolovať jej stav. Potom nám len
stačí pridať krátky for
cyklus, v ktorom otestujeme, či
náhodou nie je niektorá z aktívnych udalostí tá, ktorá nás zaujíma.
Po týchto úpravách bude náš kód vyzerať zhruba nasledovne:
pygame.init() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: running = False screen = pygame.display.set_mode((800, 600)) pygame.draw.circle(screen, (0, 0, 255), (400, 300), 150) pygame.display.flip()
Teraz by už naše okno malo ísť zavrieť ako pomocou krížika, tak pomocou stlačenia (resp. Uvoľnenie) klávesy Esc.
Kreslíme obdĺžnik
Obdĺžnik, resp. pygame.Rect
, je vysoko užitočná trieda
vnútri pygame
, pretože je možné s jej pomocou vyriešiť
napríklad kolízie. Aby sme si to v rýchlosti ukázali, nakreslíme si ku
kruhu ešte aj zelený obdĺžnik:
pygame.init() running = True while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: running = False screen = pygame.display.set_mode((800, 600)) pygame.draw.circle(screen, (0, 0, 255), (400, 300), 150) pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(10, 10, 100, 200)) pygame.display.flip()
výsledok:
Pohybujeme sa
Záverom tejto lekcie sa naučíme, ako sa sebou môžeme hýbať pomocou
stlačenia klávesov. Mohli by sme si zaznamenávať pomocou udalostí, ktoré
klávesy používateľ stlačil a ktoré potom pustil. Našťastie má ale
pygame
priamo už zabudovanú funkciu
pygame.key.get_pressed()
, ktorá vráti n-ticu všetkých práve
stlačených kláves. Indexy v tejto n-ticu zodpovedajú hodnotám konštánt
pygame.K_
.
Povedzme si teda, že chceme hýbať naším kruhom pomocou klávesov W A S D. K tomu si potrebujeme ukladať pozíciu kruhu, ku ktorej budeme pridávať hodnoty podľa toho, ktoré klávesy sú zrovna stlačené:
player_x = 400 player_y = 300 while running: # ... pressed = pygame.key.get_pressed() if pressed[pygame.K_w]: # Nahoru player_y -= 5 if pressed[pygame.K_s]: #Dolů player_y += 5 if pressed[pygame.K_a]: # Doleva player_x -= 5 if pressed[pygame.K_d]: # Doprava player_x += 5
Teraz by nám mala fungovať zmena súradníc, ako si želáme. Ešte ale musíme upraviť vykresľovanie kruhu:
while running: # ... pygame.draw.circle(screen, (0, 0, 255), (player_x, player_y), 150)
Teraz máme kruh, ktorý môžeme ovládať pomocou klávesov. Skúste si kód spustiť a chvíľu sa s ním hrať. Možno sa vám zdá, že modrý kruh behá trochu rýchlejšie, než ste si predstavovali. A áno, máte pravdu. To je preto, že sme nedali žiadne obmedzenie maximálnej rýchlosti programu, takže sa všetky kroky uskutočňujú tak rýchlo, ako len môžu. To nie je úplne žiaduce správanie, pretože by potom každému užívateľovi behala hra inak rýchlo a tiež by veľmi záležalo na vyťaženie procesora.
Preto má pygame
ľahkú cestu, ako obmedziť maximálnu
rýchlosť programu na určitý počet FPS (= frames per second = snímok za
sekundu). Normálna hodnota FPS býva 30, 60 alebo 120, čo sú všetko
hodnoty, pri ktorých si už ľudské oko nevšimne žiadneho trhania.
Pre obmedzenie maximálneho FPS na 30 teda použijeme inštanciu triedy
pygame.time.Clock
:
clock = pygame.time.Clock() # vytvoříme nové pygame hodiny while True: # ... clock.tick(30) # umístíme na konec cyklu
Máme hotovo!
Výborná práca, teraz máme hotové všetky základy, ktoré potrebujeme na vytvorenie našej prvej hry. Tú si spoločne vytvoríme nabudúce.
Ešte pre zopakovanie si ale ukážeme kompletný kód (bez importu), ktorý by sme mali mať po konci tejto lekcie:
pygame.init() running = True clock = pygame.time.Clock() player_x = 400 player_y = 300 while running: for event in pygame.event.get(): if event.type == pygame.QUIT: running = False elif event.type == pygame.KEYUP and event.key == pygame.K_ESCAPE: running = False pressed = pygame.key.get_pressed() if pressed[pygame.K_w]: # Nahoru player_y -= 5 if pressed[pygame.K_s]: # Dolů player_y += 5 if pressed[pygame.K_a]: # Doleva player_x -= 5 if pressed[pygame.K_d]: # Doprava player_x += 5 screen = pygame.display.set_mode((800, 600)) pygame.draw.circle(screen, (0, 0, 255), (player_x, player_y), 150) pygame.draw.rect(screen, (0, 255, 0), pygame.Rect(10, 10, 100, 200)) pygame.display.flip() clock.tick(30)
Pokračovať budeme nabudúce, v lekcii Pygame - Pong - Príprava .