Kolize spritů a naplánování operací v nástroji Pygame Zero

24. 11. 2020
Doba čtení: 39 minut

Sdílet

Dnes si nejprve popíšeme způsob detekce kolize spritů (což je ve hrách velmi často používaná operace) a posléze se zaměříme na popis objektu pojmenovaného clock, jenž umožňuje naplánování (asynchronních) akcí.

Obsah

1. Detekce kolize spritů v knihovně Pygame Zero

2. První demonstrační příklad – zobrazení trojice nepohyblivých spritů

3. Nastavení, popř. změna pozice spritu na obrazovce

4. Zobrazení aktuální pozice spritu

5. Změna pozice spritu s využitím klávesnice

6. Souběžný posun dvou spritů

7. Automatický pohyb posledního spritu, odrazy od okrajů okna

8. Úplný zdrojový kód příkladu s odrážejícím se spritem

9. Kolize spritů

10. Využití metody colliderect pro detekci kolizí spritů

11. Úplný zdrojový kód příkladu s detekcí kolize spritů

12. Využití metody collidelist pro detekci kolizí spritů

13. Úplný zdrojový kód druhé varianty příkladu s detekcí kolize spritů

14. Změna stavu hry po kolizi

15. Reakce herního „engine“ na kolizi spritu

16. Naplánování činnosti s využitím objektu clock

17. Obnovení barvy spritu sekundu po kolizi

18. Relevantní funkce z knihovny Pygame

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Detekce kolize spritů v knihovně Pygame Zero

V předchozích částech miniseriálu o nástroji Pygame Zero [1] [2] [3] [4] jsme se seznámili mj. i s tím, jakým způsobem lze pracovat s takzvanými sprity, tj. s rastrovými obrázky, s nimiž je možné pohybovat po celé dvourozměrné scéně. Sprity samozřejmě mohou úplně či částečně překreslit pozadí vytvářené scény, mohou se v případě potřeby navzájem překrývat, při překrytí lze aplikovat již dříve zmíněnou a použitou průhlednost či průsvitnost apod.

Obrázek 1: Sprity použité ve známé herní sérii Sonic the Hedgehog.

V poslední verzi knihovny Pygame Zero je dokonce možné provést i otočení spritů o libovolný úhel, což je téma, kterému jsme se věnovali minule (viz základ jednoduché hry typu Asteroids).

Obrázek 2: Snímek ze „hry“ naprogramované minule.

Poznámka: namísto termínu sprite se v dokumentaci k nástroji Pygame Zero setkáme se jménem actor, čemuž odpovídá i název příslušné třídy Actor.

Ovšem zbývá nám vyřešit ještě jeden relativně závažný problém úzce související se sprity – v mnoha aplikacích (především v počítačových hrách) je nutné nějakým způsobem zareagovat ve chvíli, kdy dojde ke kolizi či k překryvu dvou spritů. Představme si například klasickou hru Pac-Man, která musí adekvátně reagovat při srážce hlavního hrdiny s duchem, zareagovat na sežrání bodu (což je taktéž srážka spritu/spritů) apod. I tyto případy, které byly v minulosti řešeny už na úrovni příslušného hardware (video čipu), jsou samozřejmě v nástroji Pygame Zero relativně jednoduše vyřešitelné, což ostatně uvidíme v navazujících kapitolách. Již na tomto místě je vhodné poznamenat, že detekce kolize spritů není dokonalá a vlastně je horší, než tomu bylo v dobách osmibitových domácích mikropočítačů – kolizi dokážeme vypočítat pouze pro sprite jako celek (čtverec či obdélník) a navíc ve chvíli, kdy nedochází k natočení spritu. Pochopitelně by bylo možné kolizi detekovat až na úroveň pixelů (per-pixel collision detection), ovšem tuto funkcionalitu Pygame Zero (alespoň prozatím) nenabízí.

Obrázek 3: Starší varianta hry Pac-Man, zde pro osmibitovou herní konzoli Atari 2600. I v této hře (a speciálně na hardware Atari 2600) byly masivně používány sprity.

2. První demonstrační příklad – zobrazení trojice nepohyblivých spritů

Nejprve si připravíme kostru demonstračního příkladu, kterou budeme v rámci dalších kapitol rozšiřovat a doplňovat. Po jejím spuštění se na pozadí zobrazí trojice spritů, z nichž každý je představován čtvercem o rozměrech 32×32 pixelů. Pro jednoduchost je tento čtverec vyplněn konstantní barvou (mj. i proto je velikost příslušných rastrových obrázků nepatrná – 63 bajtů; použili jsme navíc pro takto malé obrázky výhodnější formát GIF). Zdrojový kód tohoto demonstračního příkladu vypadá následovně:

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()

Obrázek 4: Dnešní první demonstrační příklad po svém spuštění.

Alternativně je pochopitelně možné namísto pozadí vyplněného konstantní barvou použít nějaký podkladový obrázek, například z již výše zmíněné hry Pac-Man (použit je výřez z emulovaného pozadí reálného herního automatu):

WIDTH = 480
HEIGHT = 480
 
red_sprite = Actor("red.gif")
red_sprite.pos = (160, 220)
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 220)
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (320, 220)
 
 
def draw():
    screen.blit(images.pacman, (0, 0))
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()

Obrázek 5: Změna pozadí (rastrový obrázek) a nepatrné posunutí počáteční pozice spritů na obrazovce.

3. Nastavení, popř. změna pozice spritu na obrazovce

Sprite si můžeme představit jako čtverec nebo obdélník, který je vyplněný rastrovým obrázkem (nebo chcete-li, je otexturovaný). Pokud nebudeme brát v úvahu možnou rotaci spritu, lze pozici vyjádřit dvojicí souřadnic x, y. Ovšem význam těchto souřadnic se liší podle toho, který bod spritu budeme používat. K dispozici je celkem devět významných bodů, k nimž je možné souřadnice x a y vztáhnout:

Obrázek 6: Devět bodů, k nimž lze vztáhnout souřadnice x, y udávající pozici spritu na obrazovce.

Těmto bodům odpovídá i pojmenovaný (nepovinný) parametr předávaný konstruktoru Actor:

# Keyword
1 topleft
2 midtop
3 topright
4 midleft
5 center
6 midright
7 bottomleft
8 midbottom
9 bottomright

Souřadnice spritu lze nastavit změnou následujících atributů (skutečná pozice spritu se vypočte ihned po nastavení těchto atributů):

# Atribut Souřadnice
1 left horizontální
2 right horizontální
3 top vertikální
4 bottom vertikální
5 center horizontální či vertikální
6 middle horizontální či vertikální

4. Zobrazení aktuální pozice spritu

Pozici spritu lze kdykoli přečíst a nějakým způsobem využít. V dnešním druhém demonstračním příkladu tuto pozici (přesněji řečeno souřadnice x a y) zobrazíme. Tato operace probíhá ve funkci nazvané draw_sprite_pos:

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    screen.draw.text(str(int(sprite.x)), (pos_x+70, pos_y), color=color)
    screen.draw.text(str(int(sprite.y)), (pos_x+110, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")

Obrázek 7: Výchozí pozice spritů.

5. Změna pozice spritu s využitím klávesnice

Pohyb spritu je možné ovládat klávesnicí, což je ostatně způsob používaný v mnoha klasických 2D hrách. Tento způsob je v tom nejjednodušším případě založen na trojici callback funkcí nazvaných on_key_down, on_key_up a update. První callback funkce je zavolána ve chvíli, kdy je stisknuta nějaká klávesa. Reagovat budeme na kurzorové šipky a taktéž na klávesu Esc:

def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        dy = -1
    if key == keys.DOWN:
        dy = 1
    if key == keys.LEFT:
        dx = -1
    if key == keys.RIGHT:
        dx = 1

Druhá callback funkce je zavolána po puštění klávesy (ukončení stisku). Reagovat budeme na ukončení stisku kurzorových šipek:

def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        dx = 0

A konečně třetí callback funkce je volána pravidelně šedesátkrát za sekundu a můžeme v ní realizovat pohyb spritu na základě nastavených hodnot globálních proměnných dx a dy:

def update():
    blue_sprite.left += dx
    blue_sprite.top += dy

Úplný zdrojový kód tohoto příkladu vypadá následovně:

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
 
dx = 0
dy = 0
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    screen.draw.text(str(int(sprite.x)), (pos_x+70, pos_y), color=color)
    screen.draw.text(str(int(sprite.y)), (pos_x+110, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")
 
 
def update():
    blue_sprite.left += dx
    blue_sprite.top += dy
 
 
def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        dy = -1
    if key == keys.DOWN:
        dy = 1
    if key == keys.LEFT:
        dx = -1
    if key == keys.RIGHT:
        dx = 1
 
 
def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        dx = 0

Obrázek 8: Pohyb spritu s využitím kurzorových kláves.

Obrázek 9: Překrytí dvou spritů.

6. Souběžný posun dvou spritů

Předchozí demonstrační příklad můžeme snadno rozšířit tak, aby bylo možné s využitím další čtveřice kláves (W, A, S, D) posunovat i dalším spritem. Ovšem ideální by bylo, aby nám nerostl počet globálních proměnných. Z tohoto důvodu přidáme další atributy k existujícím spritům (což je možné), což v našem konkrétním případě znamená:

blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
blue_sprite.dx = 0
blue_sprite.dy = 0

a:

yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
yellow_sprite.dx = 0
yellow_sprite.dy = 0

Upravený zdrojový kód bude vypadat následovně:

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
blue_sprite.dx = 0
blue_sprite.dy = 0
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
yellow_sprite.dx = 0
yellow_sprite.dy = 0
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    screen.draw.text(str(int(sprite.x)), (pos_x+70, pos_y), color=color)
    screen.draw.text(str(int(sprite.y)), (pos_x+110, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")
 
 
def update():
    blue_sprite.left += blue_sprite.dx
    blue_sprite.top += blue_sprite.dy
 
    yellow_sprite.left += yellow_sprite.dx
    yellow_sprite.top += yellow_sprite.dy
 
 
def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        blue_sprite.dy = -1
    if key == keys.DOWN:
        blue_sprite.dy = 1
    if key == keys.LEFT:
        blue_sprite.dx = -1
    if key == keys.RIGHT:
        blue_sprite.dx = 1
    if key == keys.W:
        yellow_sprite.dy = -1
    if key == keys.S:
        yellow_sprite.dy = 1
    if key == keys.A:
        yellow_sprite.dx = -1
    if key == keys.D:
        yellow_sprite.dx = 1
 
 
def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        blue_sprite.dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        blue_sprite.dx = 0
    if key == keys.W or key == keys.S:
        yellow_sprite.dy = 0
    if key == keys.A or key == keys.D:
        yellow_sprite.dx = 0

Dvojice atributů left+right a top+bottom je svázaná, tj. změnou jednoho atributu dojde i ke změně atributu druhého. To si můžeme snadno ověřit spuštěním dalšího demonstračního příkladu a posunem spritu po obrazovce:

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
 
dx = 0
dy = 0
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    msg = "left: {}  right: {}  top: {}  bottom: {}".format(int(sprite.left), int(sprite.right), int(sprite.top), int(sprite.bottom))
    screen.draw.text(msg, (pos_x+100, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")
 
 
def update():
    blue_sprite.left += dx
    blue_sprite.top += dy
 
 
def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        dy = -1
    if key == keys.DOWN:
        dy = 1
    if key == keys.LEFT:
        dx = -1
    if key == keys.RIGHT:
        dx = 1
 
 
def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        dx = 0

Obrázek 10: Výchozí pozice spritů.

Obrázek 11: Horizontální posun modrého spritu doprava.

Obrázek 12: Vertikální posun modrého spritu dolů.

7. Automatický pohyb posledního spritu, odrazy od okrajů okna

Poslední sprite se bude ve scéně pohybovat zcela automaticky. Jeho atributy dx a dy nastavíme na shodnou nenulovou hodnotu, čímž zajistíme jeho úhlopříčný pohyb:

red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
red_sprite.dx = 1
red_sprite.dy = 1

Na okrajích okna se bude sprite odrážet, tj. jeden z jeho atributů dx či dy změní znaménko. Povšimněte si, jak je možné využít všech čtyř atributů se souřadnicemi spritu left, right, top a bottom takovým způsobem, aby se kód zajišťující odrazy co nejvíce zjednodušil:

def bounce(sprite):
    if red_sprite.left < 0:
        red_sprite.left = 0
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.right > WIDTH:
        red_sprite.right = WIDTH
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.top < 0:
        red_sprite.top = 0
        red_sprite.dy = -red_sprite.dy
 
    if red_sprite.bottom > HEIGHT:
        red_sprite.bottom = HEIGHT
        red_sprite.dy = -red_sprite.dy

8. Úplný zdrojový kód příkladu s odrážejícím se spritem

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
red_sprite.dx = 1
red_sprite.dy = 1
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
blue_sprite.dx = 0
blue_sprite.dy = 0
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
yellow_sprite.dx = 0
yellow_sprite.dy = 0
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    screen.draw.text(str(int(sprite.x)), (pos_x+70, pos_y), color=color)
    screen.draw.text(str(int(sprite.y)), (pos_x+110, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")
 
 
def bounce(sprite):
    if red_sprite.left < 0:
        red_sprite.left = 0
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.right > WIDTH:
        red_sprite.right = WIDTH
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.top < 0:
        red_sprite.top = 0
        red_sprite.dy = -red_sprite.dy
 
    if red_sprite.bottom > HEIGHT:
        red_sprite.bottom = HEIGHT
        red_sprite.dy = -red_sprite.dy
 
 
def update():
    blue_sprite.left += blue_sprite.dx
    blue_sprite.top += blue_sprite.dy
 
    yellow_sprite.left += yellow_sprite.dx
    yellow_sprite.top += yellow_sprite.dy
 
    red_sprite.left += red_sprite.dx
    red_sprite.top += red_sprite.dy
 
    bounce(red_sprite)
 
 
def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        blue_sprite.dy = -1
    if key == keys.DOWN:
        blue_sprite.dy = 1
    if key == keys.LEFT:
        blue_sprite.dx = -1
    if key == keys.RIGHT:
        blue_sprite.dx = 1
    if key == keys.W:
        yellow_sprite.dy = -1
    if key == keys.S:
        yellow_sprite.dy = 1
    if key == keys.A:
        yellow_sprite.dx = -1
    if key == keys.D:
        yellow_sprite.dx = 1
 
 
def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        blue_sprite.dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        blue_sprite.dx = 0
    if key == keys.W or key == keys.S:
        yellow_sprite.dy = 0
    if key == keys.A or key == keys.D:
        yellow_sprite.dx = 0

9. Kolize spritů

Nyní se začneme zabývat kolizí spritů. V „herní“ scéně se nyní nachází tři sprity, z nichž jeden se pohybuje zcela autonomně (odráží se od stěn atd.) a další dva můžeme posunovat s využitím klávesnice – kurzorových kláves a taktéž známou kombinací WASD. Jakým způsobem je však možné detekovat, že se dva nebo dokonce všechny tři sprity setkaly? K tomuto účelu lze využít několika metod, které jsou deklarovány přímo pro instance třídy Actor (interně je ovšem situace složitější, protože jsou tyto metody deklarovány ve třídě ZRect odvozené od třídy Rect knihovny Pygame). Jedná se o tyto metody:

# Metoda Stručný popis metody
1 collidepoint test na kolizi spritu s bodem
2 colliderect test na kolizi spritu s jiným spritem
3 collidelist test na kolizi spritu s více sprity (ze sekvence)
4 collidelistall dtto, ovšem vrací seznam kolidujících spritů
5 collidedict jako collidelist, ovšem pro slovník spritů
6 collidedictall jako collidelistall, ovšem pro slovník spritů

V následujících kapitolách se zaměříme na metody colliderect a collidelist.

10. Využití metody colliderect pro detekci kolizí spritů

Metoda colliderect slouží ke zjištění, zda se jeden objekt typu Rect protíná s jiným objektem stejného typu. Vzhledem k tomu, že sprite, tedy objekt typu Actor, získal vlastnosti Rect, můžeme přímo detekovat kolize (protnutí, dotyk) dvou spritů následujícím testem:

if sprite.colliderect(other_sprite):
    ...
    ...
    ...

V našem konkrétním případě potřebujeme zjistit kolizi spritu sprite s ostatními sprity realizovanými sekvencí other_sprites:

collision = False
for other_sprite in other_sprites:
    if sprite.colliderect(other_sprite):
        collision = True
        break
if collision:
    ...
    ...
    ...

Příklad použití tak, jak je tomu i v následujícím demonstračním příkladu:

def draw_sprite_col(sprite, other_sprites, pos_x, pos_y, color):
    collision = False
    for other_sprite in other_sprites:
        if sprite.colliderect(other_sprite):
            collision = True
            break
    if collision:
        screen.draw.text("x", (pos_x, pos_y), color=color)

11. Úplný zdrojový kód příkladu s detekcí kolize spritů

Výše uvedenou funkci draw_sprite_col můžeme snadno zakomponovat do ucelenějšího demonstračního příkladu, který u každého spritu vypisuje i příslušné kolize:

def draw():
    screen.fill(BACKGROUND_COLOR)
    ...
    ...
    ...
    draw_sprite_col(red_sprite, (blue_sprite, yellow_sprite), 200, 10, "#db0000")
    draw_sprite_col(blue_sprite, (red_sprite, yellow_sprite), 200, 30, "#00a2db")
    draw_sprite_col(yellow_sprite, (red_sprite, blue_sprite), 200, 50, "#dbc500")

Obrázek 13: Nekolidující sprity.

Obrázek 14: Kolize dvou spritů.

Obrázek 15: Kolize všech tří spritů.

Následuje výpis úplného zdrojového kódu tohoto příkladu:

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
red_sprite.dx = 1
red_sprite.dy = 1
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
blue_sprite.dx = 0
blue_sprite.dy = 0
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
yellow_sprite.dx = 0
yellow_sprite.dy = 0
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    screen.draw.text(str(int(sprite.x)), (pos_x+70, pos_y), color=color)
    screen.draw.text(str(int(sprite.y)), (pos_x+110, pos_y), color=color)
 
 
def draw_sprite_col(sprite, other_sprites, pos_x, pos_y, color):
    collision = False
    for other_sprite in other_sprites:
        if sprite.colliderect(other_sprite):
            collision = True
            break
    if collision:
        screen.draw.text("x", (pos_x, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")
 
    draw_sprite_col(red_sprite, (blue_sprite, yellow_sprite), 200, 10, "#db0000")
    draw_sprite_col(blue_sprite, (red_sprite, yellow_sprite), 200, 30, "#00a2db")
    draw_sprite_col(yellow_sprite, (red_sprite, blue_sprite), 200, 50, "#dbc500")
 
 
def bounce(sprite):
    if red_sprite.left < 0:
        red_sprite.left = 0
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.right > WIDTH:
        red_sprite.right = WIDTH
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.top < 0:
        red_sprite.top = 0
        red_sprite.dy = -red_sprite.dy
 
    if red_sprite.bottom > HEIGHT:
        red_sprite.bottom = HEIGHT
        red_sprite.dy = -red_sprite.dy
 
 
def update():
    blue_sprite.left += blue_sprite.dx
    blue_sprite.top += blue_sprite.dy
 
    yellow_sprite.left += yellow_sprite.dx
    yellow_sprite.top += yellow_sprite.dy
 
    red_sprite.left += red_sprite.dx
    red_sprite.top += red_sprite.dy
 
    bounce(red_sprite)
 
 
def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        blue_sprite.dy = -1
    if key == keys.DOWN:
        blue_sprite.dy = 1
    if key == keys.LEFT:
        blue_sprite.dx = -1
    if key == keys.RIGHT:
        blue_sprite.dx = 1
    if key == keys.W:
        yellow_sprite.dy = -1
    if key == keys.S:
        yellow_sprite.dy = 1
    if key == keys.A:
        yellow_sprite.dx = -1
    if key == keys.D:
        yellow_sprite.dx = 1
 
 
def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        blue_sprite.dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        blue_sprite.dx = 0
    if key == keys.W or key == keys.S:
        yellow_sprite.dy = 0
    if key == keys.A or key == keys.D:
        yellow_sprite.dx = 0

12. Využití metody collidelist pro detekci kolizí spritů

V některých případech, zejména když se má detekovat kolize většího množství spritů (a je nám jedno, o který konkrétní sprite se jedná), je výhodnější použít metodu nazvanou collidelist. Této metodě se předá seznam nebo n-tice spritů a výsledkem je index prvního spritu, který koliduje se spritem výchozím. Pokud k žádné kolizi nedochází, vrátí se namísto indexu hodnota –1, což je chování podobné například hledání znaku v řetězci atd.:

if sprite.collidelist(other_sprites) >= 0:
    ...
    ...
    ...

Konkrétní příklad použití:

def draw_sprite_col(sprite, other_sprites, pos_x, pos_y, color):
    if sprite.collidelist(other_sprites) >= 0:
        screen.draw.text("x", (pos_x, pos_y), color=color)

Při volání této funkce musíme v prvním parametru předat sprite, pro který kolizi hledáme a následně seznam či n-tici všech ostatních spritů:

draw_sprite_col(red_sprite, (blue_sprite, yellow_sprite), 200, 10, "#db0000")
draw_sprite_col(blue_sprite, (red_sprite, yellow_sprite), 200, 30, "#00a2db")
draw_sprite_col(yellow_sprite, (red_sprite, blue_sprite), 200, 50, "#dbc500")

13. Úplný zdrojový kód druhé varianty příkladu s detekcí kolize spritů

Podobně jako jedenácté kapitole si i nyní zobrazíme celý zdrojový kód příkladu, který detekuje kolize jednotlivých spritů mezi sebou:

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
red_sprite.dx = 1
red_sprite.dy = 1
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
blue_sprite.dx = 0
blue_sprite.dy = 0
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
yellow_sprite.dx = 0
yellow_sprite.dy = 0
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    screen.draw.text(str(int(sprite.x)), (pos_x+70, pos_y), color=color)
    screen.draw.text(str(int(sprite.y)), (pos_x+110, pos_y), color=color)
 
 
def draw_sprite_col(sprite, other_sprites, pos_x, pos_y, color):
    if sprite.collidelist(other_sprites) >= 0:
        screen.draw.text("x", (pos_x, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")
 
    draw_sprite_col(red_sprite, (blue_sprite, yellow_sprite), 200, 10, "#db0000")
    draw_sprite_col(blue_sprite, (red_sprite, yellow_sprite), 200, 30, "#00a2db")
    draw_sprite_col(yellow_sprite, (red_sprite, blue_sprite), 200, 50, "#dbc500")
 
 
def bounce(sprite):
    if red_sprite.left < 0:
        red_sprite.left = 0
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.right > WIDTH:
        red_sprite.right = WIDTH
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.top < 0:
        red_sprite.top = 0
        red_sprite.dy = -red_sprite.dy
 
    if red_sprite.bottom > HEIGHT:
        red_sprite.bottom = HEIGHT
        red_sprite.dy = -red_sprite.dy
 
 
def update():
    blue_sprite.left += blue_sprite.dx
    blue_sprite.top += blue_sprite.dy
 
    yellow_sprite.left += yellow_sprite.dx
    yellow_sprite.top += yellow_sprite.dy
 
    red_sprite.left += red_sprite.dx
    red_sprite.top += red_sprite.dy
 
    bounce(red_sprite)
 
 
def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        blue_sprite.dy = -1
    if key == keys.DOWN:
        blue_sprite.dy = 1
    if key == keys.LEFT:
        blue_sprite.dx = -1
    if key == keys.RIGHT:
        blue_sprite.dx = 1
    if key == keys.W:
        yellow_sprite.dy = -1
    if key == keys.S:
        yellow_sprite.dy = 1
    if key == keys.A:
        yellow_sprite.dx = -1
    if key == keys.D:
        yellow_sprite.dx = 1
 
 
def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        blue_sprite.dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        blue_sprite.dx = 0
    if key == keys.W or key == keys.S:
        yellow_sprite.dy = 0
    if key == keys.A or key == keys.D:
        yellow_sprite.dx = 0

14. Změna stavu hry po kolizi

Kolizi spritů, tedy například střetnutí hráče s protihráčem, můžeme zjišťovat buď po posunu každého spritu nebo kontinuálně ve funkci update, která je volána periodicky šedesátkrát za minutu:

def update():
    collide(red_sprite, blue_sprite)
    collide(red_sprite, yellow_sprite)

Po zjištění kolize samozřejmě může „engine“ hry nějak zareagovat. V našem případě pouze změníme barvu spritu, což znamená, že spritu přiřadíme jiný obrázek („white.gif“):

def collide(sprite1, sprite2):
    if sprite1.colliderect(sprite2):
        sprite2.image = "white"
Poznámka: pochopitelně je možné použít reálné obrázky a nikoli jednobarevné čtverce, které jakoby z oka vypadly tvaru hráče ze hry Adventure:)
adventure

Obrázek 16: Adventure ve verzi pro herní konzoli Atari 5200.

15. Reakce herního „engine“ na kolizi spritu

Nyní se podívejme na výsledek:

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
red_sprite.dx = 1
red_sprite.dy = 1
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
blue_sprite.dx = 0
blue_sprite.dy = 0
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
yellow_sprite.dx = 0
yellow_sprite.dy = 0
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    screen.draw.text(str(int(sprite.x)), (pos_x+70, pos_y), color=color)
    screen.draw.text(str(int(sprite.y)), (pos_x+110, pos_y), color=color)
 
 
def draw_sprite_col(sprite, other_sprites, pos_x, pos_y, color):
    if sprite.collidelist(other_sprites) >= 0:
        screen.draw.text("x", (pos_x, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")
 
    draw_sprite_col(red_sprite, (blue_sprite, yellow_sprite), 200, 10, "#db0000")
    draw_sprite_col(blue_sprite, (red_sprite, yellow_sprite), 200, 30, "#00a2db")
    draw_sprite_col(yellow_sprite, (red_sprite, blue_sprite), 200, 50, "#dbc500")
 
 
def bounce(sprite):
    if red_sprite.left < 0:
        red_sprite.left = 0
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.right > WIDTH:
        red_sprite.right = WIDTH
        red_sprite.dx = -red_sprite.dx
 
    if red_sprite.top < 0:
        red_sprite.top = 0
        red_sprite.dy = -red_sprite.dy
 
    if red_sprite.bottom > HEIGHT:
        red_sprite.bottom = HEIGHT
        red_sprite.dy = -red_sprite.dy
 
 
def collide(sprite1, sprite2):
    if sprite1.colliderect(sprite2):
        sprite2.image = "white"
 
 
def update():
    blue_sprite.left += blue_sprite.dx
    blue_sprite.top += blue_sprite.dy
 
    yellow_sprite.left += yellow_sprite.dx
    yellow_sprite.top += yellow_sprite.dy
 
    red_sprite.left += red_sprite.dx
    red_sprite.top += red_sprite.dy
 
    bounce(red_sprite)
    collide(red_sprite, blue_sprite)
    collide(red_sprite, yellow_sprite)
 
 
def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        blue_sprite.dy = -1
    if key == keys.DOWN:
        blue_sprite.dy = 1
    if key == keys.LEFT:
        blue_sprite.dx = -1
    if key == keys.RIGHT:
        blue_sprite.dx = 1
    if key == keys.W:
        yellow_sprite.dy = -1
    if key == keys.S:
        yellow_sprite.dy = 1
    if key == keys.A:
        yellow_sprite.dx = -1
    if key == keys.D:
        yellow_sprite.dx = 1
 
 
def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        blue_sprite.dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        blue_sprite.dx = 0
    if key == keys.W or key == keys.S:
        yellow_sprite.dy = 0
    if key == keys.A or key == keys.D:
        yellow_sprite.dx = 0

Obrázek 17: Stav před kolizí spritů.

Obrázek 18: Stav po kolizi spritů.

16. Naplánování činnosti s využitím objektu clock

Poslední vlastností nástroje Pygame Zero, s níž se v tomto miniseriálu setkáme, je schopnost naplánovat určitou činnost tak, aby proběhla až po uplynutí nějakého časového intervalu. K tomuto účelu se používá objekt clock s metodami schedule a schedule_unique. Těmto metodám se předává volaná funkce a taktéž časový interval, po jehož uplynutí je funkce skutečně zavolaná:

schedule(funkce, 1.00)         # interval jedné sekundy
schedule_unique(funkce, 1.00)  # interval jedné sekundy

Rozdíl mezi schedule a schedule_unique spočívá v tom, že pokud je naplánována stejná úloha (resp. přesněji řečeno úloha představovaná stejnou funkcí), je v případě schedule_unique původní plán zahozen. Představme si například naprogramování pozdní reakce na kliknutí na objekt ve scéně – i když budeme klikat vícekrát, budeme (většinou) požadovat pouze jediné vykonání příslušné akce.

Poznámka: důležité upozornění – volat lze pouze funkce bez parametrů a současně se nesmí jednat o uzávěry (což vyplývá z toho, že se jedná o funkce bez parametrů. Nelze ani použít funkce anonymní (lambda), pokud by se jednalo o uzávěr, což je poměrně velké omezení, které neumožňuje parametrizace.

17. Obnovení barvy spritu sekundu po kolizi

Zkusme si nyní naprogramovat změnu barvy spritu po nárazu do zdi (a odražení od ní). Po jedné sekundě by se měla barva vrátit na původní hodnotu (tedy použije se původní obrázek). Současně se přehraje zvuk s nárazem:

if bounced:
    red_sprite.image = "gray.gif"
    clock.schedule_unique(reset_sprite, 0.4)
    sounds.ping.play()

Po jedné sekundě od nárazu se zavolá tato funkce:

def reset_sprite():
    red_sprite.image = "red.gif"

Úplný zdrojový kód demonstračního příkladu vypadá následovně:

ict ve školství 24

WIDTH = 480
HEIGHT = 480
 
BACKGROUND_COLOR = (0, 0x40, 0x40)
 
red_sprite = Actor("red.gif")
red_sprite.pos = (120, 240)
red_sprite.dx = 1
red_sprite.dy = 1
 
blue_sprite = Actor("blue.gif")
blue_sprite.pos = (240, 240)
blue_sprite.dx = 0
blue_sprite.dy = 0
 
yellow_sprite = Actor("yellow.gif")
yellow_sprite.pos = (360, 240)
yellow_sprite.dx = 0
yellow_sprite.dy = 0
 
 
def draw_sprite_pos(which, sprite, pos_x, pos_y, color):
    screen.draw.text(which + ":", (pos_x, pos_y), color=color)
    screen.draw.text(str(int(sprite.x)), (pos_x+70, pos_y), color=color)
    screen.draw.text(str(int(sprite.y)), (pos_x+110, pos_y), color=color)
 
 
def draw_sprite_col(sprite, other_sprites, pos_x, pos_y, color):
    if sprite.collidelist(other_sprites) >= 0:
        screen.draw.text("x", (pos_x, pos_y), color=color)
 
 
def draw():
    screen.fill(BACKGROUND_COLOR)
    red_sprite.draw()
    blue_sprite.draw()
    yellow_sprite.draw()
 
    draw_sprite_pos("Red", red_sprite, 10, 10, "#db0000")
    draw_sprite_pos("Blue", blue_sprite, 10, 30, "#00a2db")
    draw_sprite_pos("Yellow", yellow_sprite, 10, 50, "#dbc500")
 
    draw_sprite_col(red_sprite, (blue_sprite, yellow_sprite), 200, 10, "#db0000")
    draw_sprite_col(blue_sprite, (red_sprite, yellow_sprite), 200, 30, "#00a2db")
    draw_sprite_col(yellow_sprite, (red_sprite, blue_sprite), 200, 50, "#dbc500")
 
 
def reset_sprite():
    red_sprite.image = "red.gif"
 
 
def bounce(sprite):
    bounced = False
 
    if red_sprite.left < 0:
        red_sprite.left = 0
        red_sprite.dx = -red_sprite.dx
        bounced = True
 
    if red_sprite.right > WIDTH:
        red_sprite.right = WIDTH
        red_sprite.dx = -red_sprite.dx
        bounced = True
 
    if red_sprite.top < 0:
        red_sprite.top = 0
        red_sprite.dy = -red_sprite.dy
        bounced = True
 
    if red_sprite.bottom > HEIGHT:
        red_sprite.bottom = HEIGHT
        red_sprite.dy = -red_sprite.dy
        bounced = True
 
    if bounced:
        red_sprite.image = "gray.gif"
        clock.schedule_unique(reset_sprite, 0.4)
        sounds.ping.play()
 
 
def collide(sprite1, sprite2):
    if sprite1.colliderect(sprite2):
        sprite1.image = "white.gif"
        clock.schedule_unique(reset_sprite, 1.0)
 
 
def update():
    blue_sprite.left += blue_sprite.dx
    blue_sprite.top += blue_sprite.dy
 
    yellow_sprite.left += yellow_sprite.dx
    yellow_sprite.top += yellow_sprite.dy
 
    red_sprite.left += red_sprite.dx
    red_sprite.top += red_sprite.dy
 
    bounce(red_sprite)
    collide(red_sprite, blue_sprite)
    collide(red_sprite, yellow_sprite)
 
 
def on_key_down(key, mod, unicode):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP:
        blue_sprite.dy = -1
    if key == keys.DOWN:
        blue_sprite.dy = 1
    if key == keys.LEFT:
        blue_sprite.dx = -1
    if key == keys.RIGHT:
        blue_sprite.dx = 1
    if key == keys.W:
        yellow_sprite.dy = -1
    if key == keys.S:
        yellow_sprite.dy = 1
    if key == keys.A:
        yellow_sprite.dx = -1
    if key == keys.D:
        yellow_sprite.dx = 1
 
 
def on_key_up(key, mod):
    global dx, dy
    if key == keys.ESCAPE:
        exit()
    if key == keys.UP or key == keys.DOWN:
        blue_sprite.dy = 0
    if key == keys.LEFT or key == keys.RIGHT:
        blue_sprite.dx = 0
    if key == keys.W or key == keys.S:
        yellow_sprite.dy = 0
    if key == keys.A or key == keys.D:
        yellow_sprite.dx = 0

18. Relevantní funkce z knihovny Pygame

V této kapitole jsou uvedeny odkazy na dokumentaci k funkcím knihovny Pygame, které jsou interně používány i projektem Pygame Zero. Tyto funkce jsou vidět v některých chybových hlášeních, protože i přes snahy autorů Pygame Zero není odstínění od knihovny Pygame úplné (což je možná jeden z největších současných nedostatků tohoto projektu):

  1. pygame.init()
    http://www.pygame.org/doc­s/ref/pygame.html#pygame.i­nit
  2. pygame.quit()
    http://www.pygame.org/doc­s/ref/pygame.html#pygame.qu­it
  3. pygame.display.set_mode()
    http://www.pygame.org/doc­s/ref/display.html#pygame­.display.set_mode
  4. pygame.display.set_caption()
    http://www.pygame.org/doc­s/ref/display.html#pygame­.display.set_caption
  5. pygame.display.update()
    http://www.pygame.org/doc­s/ref/display.html#pygame­.display.update
  6. pygame.event.get()
    http://www.pygame.org/doc­s/ref/event.html#pygame.e­vent.get
  7. pygame.time.wait()
    http://www.pygame.org/doc­s/ref/time.html#pygame.ti­me.wait
  8. pygame.time.Clock.tick()
    http://www.pygame.org/doc­s/ref/time.html#pygame.ti­me.Clock.tick
  9. pygame.draw.line()
    http://www.pygame.org/doc­s/ref/draw.html#pygame.draw­.line
  10. pygame.draw.circle()
    http://www.pygame.org/doc­s/ref/draw.html#pygame.draw­.circle
  11. pygame.draw.rect()
    http://www.pygame.org/doc­s/ref/draw.html#pygame.draw­.rect
  12. pygame.draw.ellipse()
    http://www.pygame.org/doc­s/ref/draw.html#pygame.draw­.ellipse
  13. pygame.key.get_pressed
    https://www.pygame.org/doc­s/ref/key.html#pygame.key­.get_pressed
  14. pygame.key.get_mods
    https://www.pygame.org/doc­s/ref/key.html#pygame.key­.get_mods
  15. pygame.mouse.get_pos
    https://www.pygame.org/doc­s/ref/mouse.html#pygame.mou­se.get_pos
  16. pygame.mouse.get_rel
    https://www.pygame.org/doc­s/ref/mouse.html#pygame.mou­se.get_rel
  17. pygame.mouse.get_pressed
    https://www.pygame.org/doc­s/ref/mouse.html#pygame.mou­se.get_pressed
  18. pygame.mixer
    https://www.pygame.org/doc­s/ref/mixer.html
  19. pygame.mixer.music
    https://www.pygame.org/doc­s/ref/music.html
  20. pygame.mixer.Sound
    https://www.pygame.org/doc­s/ref/mixer.html#pygame.mi­xer.Sound
  21. pygame.mixer.Channel
    https://www.pygame.org/doc­s/ref/mixer.html#pygame.mi­xer.Channel

19. Repositář s demonstračními příklady

Zdrojové kódy všech popsaných demonstračních příkladů určených pro Python 3 a současně i pro nástroj Pygame Zero byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má velikost zhruba několik desítek kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující čtveřici tabulek (ovšem vzhledem k tomu, že se datové soubory hledají v konkrétních podadresářích, je výhodnější provést klon celého repositáře):

# Demonstrační příklad Stručný popis příkladu Cesta
1 00_intro.py prázdný, ovšem plně funkční projekt https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/00_intro.py
2 01_clear_screen.py vymazání obrazovky https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/01_clear_screen.py
3 02_fill_in_screen.py vyplnění obrazovky určenou barvou specifikovanou trojicí RGB https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/02_fill_in_screen.py
4 03_fill_in_screen.py vyplnění obrazovky určenou barvou specifikovanou jménem https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/03_fill_in_screen.py
5 04_display_sprite.py zobrazení spritu https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/04_display_sprite.py
6 05_display_sprite.py zobrazení spritu odlišným způsobem https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/05_display_sprite.py
7 06_background.py zobrazení pozadí scény https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/06_background.py
8 07_background_and_sprite.py zobrazení pozadí scény a současně i spritu https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/07_background_and_spri­te.py
9 08_screen_type.py výpis typu globální proměnné screen https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/08_screen_type.py
10 09_images_type.py výpis typu globální proměnné images https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/09_images_type.py
11 10_sounds_type.py výpis typu globální proměnné souds https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/10_sounds_type.py
12 11_keyboard_type.py výpis typu globální proměnné keyboard https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/11_keyboard_type.py
13 12_tone_type.py výpis typu globální proměnné tone https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/12_tone_type.py
14 13_draw_lines.py okraj v okně aplikace vykreslený čtveřicí úseček https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/13_draw_lines.py
15 14_draw_lines.py úsečky, z nichž každá je vykreslena odlišnou barvou https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/14_draw_lines.py
16 15_draw_rect.py obrys obdélníka vykreslený metodou screen.draw.rect https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/15_draw_rect.py
17 16_draw_filled_rect.py část barvové palety, pro jejíž vykreslení je použita metoda screen.draw.filled_rect https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/16_draw_filled_rect.py
18 17_draw_circle.py kružnice vykreslená metodou screen.draw.circle https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/17_draw_circle.py
19 18_draw_filled_circles.py část barvové palety, pro jejíž vykreslení je použita metoda screen.draw.filled_circle https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/18_draw_filled_circles­.py
20 19_draw_simple_text.py nejjednodušší forma vykreslení textu do okna https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/19_draw_simple_text.py
21 20_font_name.py vykreslení textu fontem o zvolené velikosti https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/20_font_name.py
22 21_outline.py vykreslení textu se zvýrazněným obrysem https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/21_outline.py
23 22_drop_shadow.py vykreslení stínovaného textu https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/22_drop_shadow.py
24 23_drop_shadow_more.py vykreslení stínovaného textu s větším odstupem stínu https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/23_drop_shadow_more.py
25 24_color_gradient.py text vykreslený s využitím gradientního přechodu https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/24_color_gradient.py
26 25_wrapping.py zalomení delšího textu na obrazovce https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/25_wrapping.py
27 26_vertical_text.py vertikální text https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/26_vertical_text.py
28 27_rotated_text.py otočení vykreslovaného textu o libovolný úhel https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/27_rotated_text.py
29 28_sprite_on_background.py zobrazení spritu na vyplněném pozadí scény https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/28_sprite_on_background­.py
30 29_print_key_codes.py výpis kódů stisknutých kláves https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/29_print_key_codes.py
31 30_esc_to_end.py ukončení aplikace po stisku Esc https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/30_esc_to_end.py
32 31_move_sprite.py přesun spritu kurzorovými klávesami (první verze) https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/31_move_sprite.py
33 32_move_sprite_in_update.py přesun spritu kurzorovými klávesami (druhá verze) https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/32_move_sprite_in_upda­te.py
34 33_move_sprite_in_update_correct.py přesun spritu kurzorovými klávesami (funkční verze) https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/33_move_sprite_in_upda­te_correct.py
35 34_move_sprite_by_mouse.py přesun spritu pohybem myši https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/34_move_sprite_by_mouse­.py
36 35_move_sprite_by_mouse_click.py okamžitý přesun spritu po kliku myší https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/35_move_sprite_by_mouse_clic­k.py
37 36_animate_sprite_by_mouse_click.py animovaný přesun spritu po kliku myší https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/36_animate_sprite_by_mou­se_click.py
38 37_colors_table.py tabulka s názvy barev https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/37_colors_table.py
39 38_show_colors.py zobrazení několika barev podporovaných knihovnou Pygame Zero https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/38_show_colors.py
40 39_animation_framework.py kostra příkladu s animací spritů ovládaných z klávesnice https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/39_animation_framework­.py
41 40_fast_slow_animation.py rychlá a pomalá animace řízená z klávesnice https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/40_fast_slow_animation­.py
42 41_accelerated_decelerated_tween.py zrychlující a zpomalující se animace https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/41_accelerated_decelera­ted_tween.py
43 42_elastic_tween.py elastické odrazy na začátku či na konci animace https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/42_elastic_tween.py
44 43_bounce_tween.py odrazy na začátku a konci animace https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/43_bounce_tween.py
45 44_complicated_animation.py komplikovanější animace https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/44_complicated_animati­on.py
46 45_more_sprites_preparation.py animace s více sprity (příprava) https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/45_more_sprites_prepara­tion.py
47 46_more_sprites.py animace s více sprity (funkční příklad) https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/46_more_sprites.py
48 47_rotate_sprite.py rotace spritu https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/47_rotate_sprite.py
49 48_more_sprites_rotation.py rotace více spritů současně (kombinace s lineárním pohybem) https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/48_more_sprites_rotati­on.py
50 49_move_and_rotate_sprite.py posun a rotace spritu řízený z klávesnice https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/49_move_and_rotate_spri­te.py
51 50_play_sound.py přehrání zvuku po stisku klávesy https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/50_play_sound.py
52 51_play_music.py automatické přehrání hudby po spuštění příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/51_play_music.py
53 52_more_sprites.py zobrazení trojice nepohyblivých spritů na jednobarevném pozadí https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/52_more_sprites.py
53 52_B_more_sprites_bg.py zobrazení trojice nepohyblivých spritů na pozadí představujících část bludiště Pac Mana https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/52_B_more_sprites_bg.py
54 53_sprites_pos.py zobrazení pozice spritů na obrazovce https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/53_sprites_pos.py
55 54_sprites_pos_move_one.py posun jednoho spritu klávesnicí https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/54_sprites_pos_move_one­.py
56 55_sprites_pos_move_two.py posun dvou spritů klávesnicí https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/55_sprites_pos_move_two­.py
57 56_sprites_pos_move_three.py posun všech tří spritů https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/56_sprites_pos_move_thre­e.py
58 57_sprites_collisions.py kolize spritů https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/57_sprites_collisions.py
59 58_sprites_collisions.py vylepšená kolize spritů https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/58_sprites_collisions.py
60 59_sprites_collisions_change_color.py změna barvy spritu po kolizi https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/59_sprites_collisions_chan­ge_color.py
61 60_sprites_collisions_chan­ge_color_sound.py změna barvy spritu a zvuk po kolizi https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/60_sprites_collisions_chan­ge_color_sound.py
62 61_sprite_print_pos.py zobrazení levého, pravého, horního i spodního okraje posunovaného spritu https://github.com/tisnik/most-popular-python-libs/blob/master/pygame_ze­ro/61_sprite_print_pos.py

20. Odkazy na Internetu

  1. Welcome to Pygame Zero
    https://pygame-zero.readthedocs.io/en/sta­ble/index.html
  2. Other libraries like Pygame Zero
    https://pygame-zero.readthedocs.io/en/stable/other-libs.html
  3. Principles of Pygame Zero
    https://pygame-zero.readthedocs.io/en/sta­ble/principles.html
  4. Built-in Objects (in Pygame Zero)
    https://pygame-zero.readthedocs.io/en/sta­ble/builtins.html
  5. Pygame
    https://www.pygame.org/news
  6. Kniha: Coding Games With Pygame Zero & Python: Student workbook
    https://bookerystore.com/dow­nloads/coding-games-with-pygame-zero-python-student-workbook/
  7. Projekty založené na Pygame
    https://www.pygame.org/tags/all
  8. Domovská stránka projektu LÖVE
    https://love2d.org/
  9. PyWeek, a bi-annual game jam to write games in Python
    https://pyweek.org/
  10. Teaching a kid to code with Pygame Zero
    https://www.mattlayman.com/blog/2019/te­ach-kid-code-pygame-zero/
  11. Games with PyGame Zero
    https://codewith.mu/en/tu­torials/1.0/pgzero
  12. Coding Games With Pygame Zero & Python: Student workbook (2nd edition)
    https://electronstudio.git­hub.io/pygame-zero-book/
  13. Historie vývoje počítačových her (116. část – vývoj her v současnosti: od assembleru k PyGame)
    https://www.root.cz/clanky/historie-vyvoje-pocitacovych-her-116-cast-vyvoj-her-v-soucasnosti-od-assembleru-k-pygame/
  14. Lua + LÖVE: vytvořte si vlastní hru
    https://www.root.cz/clanky/lua-love-vytvorte-si-vlastni-hru/
  15. Hrátky se systémem LÖVE
    https://www.root.cz/clanky/hratky-se-systemem-love/
  16. Vytváříme hru v systému LÖVE
    https://www.root.cz/clanky/vytvarime-hru-v-systemu-love/
  17. Hrátky se systémem LÖVE – částicové systémy
    https://www.root.cz/clanky/hratky-se-systemem-love-casticove-systemy/
  18. Hrátky se systémem LÖVE – kolize a odrazy těles
    https://www.root.cz/clanky/hratky-se-systemem-love-ndash-kolize-a-odrazy-teles/
  19. Hrátky se systémem LÖVE – kolize a odrazy těles II
    https://www.root.cz/clanky/hratky-se-systemem-love-kolize-a-odrazy-teles-ii/
  20. Hrátky se systémem LÖVE – pružné vazby mezi tělesy
    https://www.root.cz/clanky/hratky-se-systemem-love-pruzne-vazby-mezi-telesy/
  21. Hrátky se systémem LÖVE – dokončení
    https://www.root.cz/clanky/hratky-se-systemem-love-dokonceni/
  22. Seriál Letní škola programovacího jazyka Logo
    http://www.root.cz/serialy/letni-skola-programovaciho-jazyka-logo/
  23. Scratch: oficiální stránka projektu
    http://scratch.mit.edu/
  24. Scratch: galerie projektů vytvořených ve Scratchi
    http://scratch.mit.edu/ga­lleries/browse/newest
  25. Scratch: nápověda
    file:///usr/share/scratch/Hel­p/en/index.html
  26. Scratch: obrazovky nápovědy
    file:///usr/share/scratch/Hel­p/en/allscreens.html
  27. Scratch (Wikipedie CZ)
    http://cs.wikipedia.org/wiki/Scratch
  28. Scratch (programming language)
    http://en.wikipedia.org/wi­ki/Scratch_(programming_lan­guage)
  29. Scratch Modification
    http://wiki.scratch.mit.e­du/wiki/Scratch_Modificati­on
  30. Scratch Lowers Resistance to Programming
    http://www.wired.com/gadge­tlab/2009/03/scratch-lowers/
  31. Snap!
    http://snap.berkeley.edu/
  32. Prostředí Snap!
    http://snap.berkeley.edu/snap­source/snap.html
  33. Alternatives to Scratch
    http://wiki.scratch.mit.e­du/wiki/Alternatives_to_Scrat­ch
  34. Snap! (programming language)
    https://en.wikipedia.org/wi­ki/Snap!_(programming_lan­guage)
  35. Kniha o Basicu-256
    http://www.basicbook.org/fi­les/syw2l2p_b256.pdf/
  36. Basic-256 home page
    http://www.basic256.org/index_en
  37. Basic-256 Language Documentation
    http://doc.basic256.org/doku.php
  38. Basic-256 Art Gallery
    http://www.basic256.org/artgallery
  39. Basic-256 Tutorial
    http://www.basic256.org/tutorials
  40. Why BASIC?
    http://www.basic256.org/whybasic
  41. A book to teach ANYBODY how to program a computer (using BASIC)
    http://www.basicbook.org/
  42. Sprite ve Scratchi
    https://en.scratch-wiki.info/wiki/Sprite
  43. Scratch Modification
    https://en.scratch-wiki.info/wiki/Scratch_Modification
  44. 3D Programming in Python – Part 1
    https://greendalecs.wordpres­s.com/2012/04/21/3d-programming-in-python-part-1/
  45. A very basic Pyglet tutorial
    http://www.natan.termitnjak­.net/tutorials/pyglet_basic­.html
  46. Alpha blending
    https://en.wikipedia.org/wi­ki/Alpha_compositing#Alpha_blen­ding
  47. Pygame Colors
    https://pygame-zero.readthedocs.io/en/la­test/colors_ref.html
  48. Python Color Constants Module
    https://www.webucator.com/blog/2015/03/pyt­hon-color-constants-module/
  49. Inbetweening
    https://en.wikipedia.org/wi­ki/Inbetweening
  50. MP3 (Wikipedia)
    https://en.wikipedia.org/wiki/MP3
  51. Ogg (Wikipedia)
    https://en.wikipedia.org/wiki/Ogg
  52. Vorbis audio compression
    https://xiph.org/vorbis/
  53. Vorbis (Wikipedia)
    https://en.wikipedia.org/wiki/Vorbis
  54. Tweens
    https://helpx.adobe.com/a­nimate/using/Tweens.html

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.