Prakticky žádná hra odehrávající se v 2D prostoru se neobejde bez použití mnoha objektů, které se pohybují v herním světě. Tyto objekty spolu mohou kolidovat (narážet do sebe atd.), popř. mohou nastat kolize mezi pohyblivým objektem a nepohyblivým pozadím herní scény. Aby nebylo nutné výpočet kolizí pro každou vznikající hru programovat od začátku, nabízí knihovna Pygame svým uživatelům řešení ve formě modulu pygame.sprite. A právě popisem některých možností nabízených tímto modulem se budeme zabývat v dnešním článku.

Obsah

1. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: sprity v knihovně Pygame

2. Vytvoření vlastního spritu s využitím třídy pygame.sprite.Sprite

3. Vytvoření skupiny spritů

4. Vykreslení všech spritů z vybrané skupiny

5. Zdrojový kód demonstračního příkladu pygame17

6. Změna pozice spritu ve vykreslované scéně

7. Reakce na stisk kurzorových kláves

8. Zdrojový kód demonstračního příkladu pygame18

9. Reakce na puštění kurzorových kláves

10. Test kolize spritu s okrajem okna

11. Zdrojový kód demonstračního příkladu pygame19

12. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů

13. Funkce použité v dnešních demonstračních příkladech

14. Odkazy na Internetu

1. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky: sprity v knihovně Pygame

V předchozích třech částech [1] [2] [3] seriálu o programovacích jazycích i o knihovnách a frameworcích vhodných pro výuku programování popř. pro výuku základů počítačové grafiky, jsme se seznámili se způsobem vykreslování (převážně) statických objektů do vytvářené dvourozměrné scény s využitím populární knihovny Pygame. Připomeňme si, že lze zvolit tři základní způsoby vykreslování objektů do 2D scény (v případě potřeby je samozřejmě možné tyto způsoby vhodně zkombinovat):

  • Dvourozměrnou scénu či její část lze vykreslit doslova pixel po pixelu (explicitním nastavením barvy každého pixelu), což se hodí například ve chvíli, kdy se používají procedurální textury (založené například na Perlinově šumu či na fraktálech).
  • Použít lze i vykreslování s využitím základních geometrických tvarů, například úsečky či kružnice. U některých tvarů je dokonce možné zvolit, zda se má při vykreslování aplikovat antialiasing (vyhlazení hran) či nikoli.
  • Třetí možností je použití rastrových obrázků načtených z externích souborů. Speciálním případem jsou rastrové obrázky získané takzvanou rasterizací fontů, čehož lze využít při vykreslování textů (viz též předchozí část tohoto seriálu).

11

Obrázek 1: Scéna vykreslená pixel po pixelu, tj. explicitním nastavením barvy každého pixelu framebufferu.

01

Obrázek 2: Různobarevné úsečky vykreslené bez použití antialiasingu.

03

Obrázek 3: Tytéž úsečky, ovšem nyní vykreslené s použitím antialiasingu.

12

Obrázek 4: Kombinace rastrového obrázku a úseček v jediné 2D scéně.

Poněkud komplikovanější situace nastane ve chvíli, kdy je zapotřebí původně statickou 2D scénu „rozpohybovat“, tj. vložit do ní různé pohyblivé objekty. Modifikace 2D scény pixel po pixelu v naprosté většině případů nepřichází v úvahu, protože se jedná o velmi pomalou operaci. Podobně pomalé je většinou i vykreslování základních geometrických tvarů, které sice může být v některých případech realizováno na grafickém akcelerátoru, ovšem v případě knihovny Pygame nemáme jistotu, že nedojde k softwarovému (a tedy náležitě pomalému) vykreslení. Zbývá nám tedy jediné – zaměřit se na využití pohybujících se rastrových objektů neboli spritů. V tomto ohledu nám knihovna Pygame může pomoci, protože programátorům nabízí modul nazvaný pygame.sprite, v němž je deklarováno hned několik tříd vhodných pro implementaci spritů. My si prozatím vystačíme s dvojicí tříd: pygame.sprite.Sprite [4] a pygame.sprite.Group [5].

2. Vytvoření vlastního spritu s využitím třídy pygame.sprite.Sprite

Každý sprite je v knihovně Pygame představován instancí třídy odvozené od původní třídy pygame.sprite.Sprite. Důležité jsou především dva atributy. První atribut se jmenuje image a obsahuje rastrový obrázek s tvarem spritu (některé pixely samozřejmě mohou být průhledné či poloprůhledné, touto problematikou jsme se již ostatně zabývali předminule a minule). Druhý atribut se jmenuje rect a jak již název tohoto atributu napovídá, jedná se o obdélník reprezentovaný svými rozměry a pozicí v 2D světě. Rozměry se ve výchozím nastavení měří v pixelech a v případě spritů se tyto rozměry používají pro detekci kolizí. Pozice obdélníku v 2D světě odpovídá pozici spritu, což znamená, že spritem lze velmi snadno pohybovat.

07

Obrázek 5: Hra Warcraft II pro zobrazení budov i postaviček používá výhradně sprity.

Ukažme si nyní způsob vytvoření nového spritu odvozením jeho třídy od třídy pygame.sprite.Sprite. Pro jednoduchost nebudeme načítat externí rastrový obrázek s tvarem spritu, ale spokojíme se pouze s vyplněním bitmapy spritu konstantní barvou; ostatně z tohoto důvodu naši třídu nazveme BlockySprite. Nastavení barvy, velikosti i pozice spritu je provedeno na základně parametrů předaných konstruktoru:

<i># Třída představující sprite zobrazený jako jednobarevný čtverec.</i>
<strong>class</strong> BlockySprite(pygame.sprite.Sprite):
    <i># Konstruktor</i>
    <strong>def</strong> __init__(self, color, size, x, y):
        <i># Nejprve je nutné zavolat konstruktor předka,</i>
        <i># tj. konstruktor třídy pygame.sprite.Sprite:</i>
        pygame.sprite.Sprite.__init__(self)

        <i># Vytvoření obrázku představujícího vizuální obraz spritu:</i>
        self.image = pygame.Surface([size,size])
        self.image.fill(color)

        <i># Vytvoření obalového obdélníku</i>
        <i># (velikost se získá z rozměru obrázku)</i>
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

Povšimněte si toho, že skutečně nastavuje dva atributy třídy: image a rect.

3. Vytvoření skupiny spritů

Před vykreslením spritů je nejprve nutné ty sprity, které se mají ve vytvářené 2D scéně objevit, sdružit do takzvané skupiny (group) a následně provést vykreslení všech spritů nacházejících se v této skupině (či skupinách). Skupina spritů je reprezentována instancí třídy pygame.sprite.Group, do níž se jednotlivé sprity přidávají pomocí metody add. V následujícím úryvku kódu je nejprve vytvořena (zkonstruována) instance třídy pygame.sprite.Group, následně jsou zkonstruovány dva sprity (instance naší třídy BlockySprite z předchozí kapitoly) a nakonec jsou tyto dva sprity přidány do jedné skupiny:

<i># Objekt sdružující všechny sprity</i>
all_sprites = pygame.sprite.Group()

<i># Vytvoření dvojice spritů</i>
sprite1 = BlockySprite(RED,  50, 10, 10)
sprite2 = BlockySprite(BLUE, 25, 50, 10)

<i># Přidání dvojice spritů do seznamu</i>
all_sprites.add(sprite1)
all_sprites.add(sprite2)

4. Vykreslení všech spritů z vybrané skupiny

Ve chvíli, kdy jsou všechny sprity, které se mají vykreslit, sdruženy do jedné skupiny (group), je jejich vykreslení velmi snadné, protože ve třídě pygame.sprite.Group je deklarována metoda draw. Této metodě je nutné předat libovolný objekt typu Surface, tj. libovolný rastrový obrázek. To mj. znamená, že sprity můžeme vykreslit přímo do framebufferu, neboť i framebuffer (konkrétně zadní buffer) je v knihovně Pygame představován objektem typu Surface. Inicializace grafického subsystému a vykreslení skupiny spritů by tedy mohlo vypadat následovně:

<i># Inicializace knihovny Pygame</i>
pygame.init()

<i># Vytvoření okna pro vykreslování</i>
display = pygame.display.set_mode([WIDTH, HEIGHT])

<i># Vykreslení celé skupiny spritů do bufferu</i>
all_sprites.draw(display)

5. Zdrojový kód demonstračního příkladu pygame17

Všechny úryvky kódu popsané v předchozích třech kapitolách nyní využijeme v demonstračním příkladu nazvaném pygame17, jehož úplný zdrojový kód je zobrazen pod tímto odstavcem, popř. ho lze získat na adrese https://github.com/tisnik/presentations/blob/master/pygame/pygame17.py:

<i>#!/usr/bin/python</i>
<i># vim: set fileencoding=utf-8</i>

<i># Demonstrační příklady využívající knihovnu Pygame</i>

<i># Příklad číslo 17: použití spritů</i>


<strong>import</strong> pygame, sys, os, math

<i># Nutno importovat kvůli konstantám QUIT atd.</i>
<strong>from</strong> pygame.locals <strong>import</strong> *

<i># Velikost okna aplikace</i>
WIDTH = 320
HEIGHT = 240

<i># Třída představující sprite zobrazený jako jednobarevný čtverec.</i>
<strong>class</strong> BlockySprite(pygame.sprite.Sprite):
    <i># Konstruktor</i>
    <strong>def</strong> __init__(self, color, size, x, y):
        <i># Nejprve je nutné zavolat konstruktor předka,</i>
        <i># tj. konstruktor třídy pygame.sprite.Sprite:</i>
        pygame.sprite.Sprite.__init__(self)

        <i># Vytvoření obrázku představujícího vizuální obraz spritu:</i>
        self.image = pygame.Surface([size,size])
        self.image.fill(color)

        <i># Vytvoření obalového obdélníku</i>
        <i># (velikost se získá z rozměru obrázku)</i>
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

<i># Inicializace knihovny Pygame</i>
pygame.init()

clock = pygame.time.Clock()

<i># Vytvoření okna pro vykreslování</i>
display = pygame.display.set_mode([WIDTH, HEIGHT])

<i># Nastavení titulku okna</i>
pygame.display.set_caption('Pygame test #17')

<i># Konstanty s n-ticemi představujícími základní barvy</i>
BLACK   = (  0,   0,   0)
RED     = (255,   0,   0)
BLUE    = (  0,   0,   255)

<i># Vyplnění plochy okna černou barvou</i>
display.fill(BLACK)

<i># Objekt sdružující všechny sprity</i>
all_sprites = pygame.sprite.Group()

<i># Vytvoření dvojice spritů</i>
sprite1 = BlockySprite(RED,  50, 10, 10)
sprite2 = BlockySprite(BLUE, 25, 50, 10)

<i># Přidání dvojice spritů do seznamu</i>
all_sprites.add(sprite1)
all_sprites.add(sprite2)

<i># Vykreslení celé skupiny spritů do bufferu</i>
all_sprites.draw(display)



<i># Hlavní herní smyčka</i>
<strong>while</strong> True:
    <i># Načtení a zpracování všech událostí z fronty</i>
    <strong>for</strong> event <strong>in</strong> pygame.event.get():
        <strong>if</strong> event.type == QUIT:
            pygame.quit()
            sys.exit()
        <strong>if</strong> event.type == KEYDOWN and event.key == K_ESCAPE:
            pygame.quit()
            sys.exit()

    pygame.display.update()
    clock.tick(20)

<i># finito</i>

06

Obrázek 6: Screenshot demonstračního příkladu pygame17.

6. Změna pozice spritu ve vykreslované scéně

Vytvoření statických (tj. nepohyblivých) spritů již máme odzkoušeno, nyní si tedy pojďme ukázat, jakým způsobem lze měnit pozice spritů ve vykreslované scéně. Prozatím se spokojíme s tím, že jeden ze spritů, který se ve dvourozměrné scéně nachází, bude možné ovládat kurzorovými klávesami. Pro tento účel si u každého spritu zapamatujeme ještě jeho aktuální rychlost v horizontálním a vertikálním směru. Pokud bude sprite nepohyblivý, budou obě složky rychlosti nulové, kladná horizontální složka rychlosti znamená pohyb spritu doprava (záporná samozřejmě doleva) a kladná vertikální složka rychlosti pak pohyb spritu dolů (záporná hodnota pohyb nahoru). Změna provedená ve třídě BlockySprite je minimální, pouze se do konstruktoru přidá kód pro vytvoření a prvotní inicializaci obou atributů (poslední dva řádky):

<i># Třída představující sprite zobrazený jako jednobarevný čtverec.</i>
<strong>class</strong> BlockySprite(pygame.sprite.Sprite):
    <i># Konstruktor</i>
    <strong>def</strong> __init__(self, color, size, x, y):
        <i># Nejprve je nutné zavolat konstruktor předka,</i>
        <i># tj. konstruktor třídy pygame.sprite.Sprite:</i>
        pygame.sprite.Sprite.__init__(self)

        <i># Vytvoření obrázku představujícího vizuální obraz spritu:</i>
        self.image = pygame.Surface([size,size])
        self.image.fill(color)

        <i># Vytvoření obalového obdélníku</i>
        <i># (velikost se získá z rozměru obrázku)</i>
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

        <i># Počáteční rychlost spritu</i>
        self.speed_x = 0
        self.speed_y = 0

Změna souřadnic libovolného spritu je snadná: postačuje modifikovat souřadnice x a y přiřazené k atributu rect, o němž jsme se již zmínili v předchozích kapitolách. Posun všech spritů ve skupině zařizuje funkce nazvaná move_sprites:

<i># Posun všech spritů ve skupině na základě jejich rychlosti</i>
<strong>def</strong> move_sprites(sprite_group):
    <strong>for</strong> sprite <strong>in</strong> sprite_group:
        sprite.rect.x = sprite.rect.x + sprite.speed_x
        sprite.rect.y = sprite.rect.y + sprite.speed_y

Po změně pozic spritů je nutné celou scénu znovu překreslit, což zajišťuje funkce nazvaná draw_scene. Důležité je, že tato funkce pracuje se zadním bufferem (back buffer), což znamená, že při překreslení pozadí scény i při vykreslení všech spritů nebude docházet k nepříjemnému poblikávání:

<i># Vykreslení celé scény na obrazovku</i>
<strong>def</strong> draw_scene(display, background_color, sprite_group):
    <i># Vyplnění plochy okna černou barvou</i>
    display.fill(background_color)
    <i># Vykreslení celé skupiny spritů do bufferu</i>
    sprite_group.draw(display)
    <i># Obnovení obsahu obrazovky (překlopení zadního a předního bufferu)</i>
    pygame.display.update()

07

Obrázek 7: Screenshot demonstračního příkladu pygame18 ihned po jeho inicializaci.

7. Reakce na stisk kurzorových kláves

Poslední funkcionalitu, kterou musíme doprogramovat, je reakce na stisk kurzorových kláves (šipek). Reakci na stisk kláves (ne ovšem na jejich puštění) zařizuje následující programový kód, který je umístěn do hlavní herní smyčky. Povšimněte si, že tento kód pouze nastavuje atributy speed_x či speed_y, protože vlastní pohyb spritů již máme vyřešen ve výše popsané funkci move_sprites:

<i># Načtení a zpracování všech událostí z fronty</i>
<strong>for</strong> event <strong>in</strong> pygame.event.get():
    <strong>if</strong> event.type == QUIT:
        pygame.quit()
        sys.exit()
    <strong>if</strong> event.type == KEYDOWN:
        <strong>if</strong> event.key == K_ESCAPE:
            pygame.quit()
            sys.exit()
        <i># Stiskem kurzorových kláves je možné měnit směr pohybu spritu</i>
        <strong>elif</strong> event.key == pygame.K_LEFT:
            player.speed_x = -3
        <strong>elif</strong> event.key == pygame.K_RIGHT:
            player.speed_x = +3
        <strong>elif</strong> event.key == pygame.K_UP:
            player.speed_y = -3
        <strong>elif</strong> event.key == pygame.K_DOWN:
            player.speed_y = +3

08

Obrázek 8: Screenshot demonstračního příkladu pygame18 při posunu spritu do levého horního rohu.

8. Zdrojový kód demonstračního příkladu pygame18

Všechny úryvky kódu popsané v obou předchozích kapitolách jsou využity v demonstračním příkladu nazvaném pygame18, jehož úplný zdrojový kód je zobrazen pod tímto odstavcem, popř. ho lze získat na adrese https://github.com/tisnik/presentations/blob/master/pygame/pygame17.py:

<i>#!/usr/bin/python</i>
<i># vim: set fileencoding=utf-8</i>

<i># Demonstrační příklady využívající knihovnu Pygame</i>

<i># Příklad číslo 18: použití spritů, pohyblivý sprite</i>


<strong>import</strong> pygame, sys, os, math

<i># Nutno importovat kvůli konstantám QUIT atd.</i>
<strong>from</strong> pygame.locals <strong>import</strong> *

<i># Velikost okna aplikace</i>
WIDTH = 320
HEIGHT = 240



<i># Třída představující sprite zobrazený jako jednobarevný čtverec.</i>
<strong>class</strong> BlockySprite(pygame.sprite.Sprite):
    <i># Konstruktor</i>
    <strong>def</strong> __init__(self, color, size, x, y):
        <i># Nejprve je nutné zavolat konstruktor předka,</i>
        <i># tj. konstruktor třídy pygame.sprite.Sprite:</i>
        pygame.sprite.Sprite.__init__(self)

        <i># Vytvoření obrázku představujícího vizuální obraz spritu:</i>
        self.image = pygame.Surface([size,size])
        self.image.fill(color)

        <i># Vytvoření obalového obdélníku</i>
        <i># (velikost se získá z rozměru obrázku)</i>
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

        <i># Počáteční rychlost spritu</i>
        self.speed_x = 0
        self.speed_y = 0



<i># Inicializace knihovny Pygame</i>
pygame.init()

clock = pygame.time.Clock()

<i># Vytvoření okna pro vykreslování</i>
display = pygame.display.set_mode([WIDTH, HEIGHT])

<i># Nastavení titulku okna</i>
pygame.display.set_caption('Pygame test #18')

<i># Konstanty s n-ticemi představujícími základní barvy</i>
BLACK   = (  0,   0,   0)
RED     = (255,   0,   0)
GRAY    = (128, 128, 128)

<i># Objekt sdružující všechny sprity</i>
all_sprites = pygame.sprite.Group()

<i># Vytvoření dvojice spritů - zdi a hráče</i>
wall   = BlockySprite(GRAY, 50, 10, 10)
player = BlockySprite(RED,  25, WIDTH/2, HEIGHT/2)

<i># Přidání dvojice spritů do seznamu</i>
all_sprites.add(wall)
all_sprites.add(player)



<i># Posun všech spritů ve skupině na základě jejich rychlosti</i>
<strong>def</strong> move_sprites(sprite_group):
    <strong>for</strong> sprite <strong>in</strong> sprite_group:
        sprite.rect.x = sprite.rect.x + sprite.speed_x
        sprite.rect.y = sprite.rect.y + sprite.speed_y



<i># Vykreslení celé scény na obrazovku</i>
<strong>def</strong> draw_scene(display, background_color, sprite_group):
    <i># Vyplnění plochy okna černou barvou</i>
    display.fill(background_color)
    <i># Vykreslení celé skupiny spritů do bufferu</i>
    sprite_group.draw(display)
    <i># Obnovení obsahu obrazovky (překlopení zadního a předního bufferu)</i>
    pygame.display.update()



<i># Hlavní herní smyčka</i>
<strong>while</strong> True:
    <i># Načtení a zpracování všech událostí z fronty</i>
    <strong>for</strong> event <strong>in</strong> pygame.event.get():
        <strong>if</strong> event.type == QUIT:
            pygame.quit()
            sys.exit()
        <strong>if</strong> event.type == KEYDOWN:
            <strong>if</strong> event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
            <i># Stiskem kurzorových kláves je možné měnit směr pohybu spritu</i>
            <strong>elif</strong> event.key == pygame.K_LEFT:
                player.speed_x = -3
            <strong>elif</strong> event.key == pygame.K_RIGHT:
                player.speed_x = +3
            <strong>elif</strong> event.key == pygame.K_UP:
                player.speed_y = -3
            <strong>elif</strong> event.key == pygame.K_DOWN:
                player.speed_y = +3

    
    move_sprites(all_sprites)
    draw_scene(display, BLACK, all_sprites)
    clock.tick(20)

<i># finito</i>

09

Obrázek 9: Screenshot demonstračního příkladu pygame18 při posunu spritu do pravého horního rohu.

9. Reakce na puštění kurzorových kláves

Předchozí příklad je ještě možné upravit. První úprava bude spočívat v tom, že se pohyb spritu zastaví ihned poté, co uživatel pustí příslušné kurzorové tlačítko (šipku). Tato úprava je velmi jednoduchá, protože spočívá v tom, že se bude reagovat jak na stisk klávesy (změna rychlosti spritu v horizontálním či vertikálním směru), tak i na puštění klávesy (změna rychlosti, ale v opačném směru, resp. přesněji řečeno vynulování příslušné složky vektoru rychlosti). Podívejme se nyní na způsob implementace této úpravy:

    <i># Načtení a zpracování všech událostí z fronty</i>
    <strong>for</strong> event <strong>in</strong> pygame.event.get():
        <strong>if</strong> event.type == QUIT:
            pygame.quit()
            sys.exit()
        <strong>if</strong> event.type == KEYDOWN:
            <strong>if</strong> event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
            <i># Stiskem kurzorových kláves je možné měnit směr pohybu spritu</i>
            <strong>elif</strong> event.key == pygame.K_LEFT:
                player.speed_x = -3
            <strong>elif</strong> event.key == pygame.K_RIGHT:
                player.speed_x = +3
            <strong>elif</strong> event.key == pygame.K_UP:
                player.speed_y = -3
            <strong>elif</strong> event.key == pygame.K_DOWN:
                player.speed_y = +3
        <strong>if</strong> event.type == KEYUP:
            <i># Puštění kurzorových kláves vede k zastavení pohybu spritu</i>
            <strong>if</strong> event.key == pygame.K_LEFT:
                player.speed_x = 0
            <strong>elif</strong> event.key == pygame.K_RIGHT:
                player.speed_x = 0
            <strong>elif</strong> event.key == pygame.K_UP:
                player.speed_y = 0
            <strong>elif</strong> event.key == pygame.K_DOWN:
                player.speed_y = 0

10

Obrázek 9: Screenshot demonstračního příkladu pygame19 ihned po jeho inicializaci.

10. Test kolize spritu s okrajem okna

Poslední úprava spočívá v tom, že se při pohybu spritů provede test, jestli sprite nenarazil do okrajů okna. Po nárazu je nutné upravit horizontální či vertikální souřadnici spritu a následně vynulovat příslušnou složku vektoru rychlosti. Tuto úpravu lze snadno přidat do již existující funkce move_sprites. Povšimněte si, jak je vypočtena pozice pravého a dolního okraje spritu::

<i># Posun všech spritů ve skupině na základě jejich rychlosti</i>
<strong>def</strong> move_sprites(sprite_group, playground_width, playground_height):
    <strong>for</strong> sprite <strong>in</strong> sprite_group:
        <i># Posun spritu</i>
        sprite.rect.x = sprite.rect.x + sprite.speed_x
        sprite.rect.y = sprite.rect.y + sprite.speed_y
        <i># Kontrola, zda sprite nenarazil do okraju okna</i>
        <strong>if</strong> sprite.rect.x < 0:
            sprite.rect.x = 0
            sprite.speed_x = 0
        <strong>if</strong> sprite.rect.x + sprite.rect.width > playground_width:
            sprite.rect.x = playground_width - sprite.rect.width
            sprite.speed_x = 0
        <strong>if</strong> sprite.rect.y < 0:
            sprite.rect.y = 0
            sprite.speed_y = 0
        <strong>if</strong> sprite.rect.y + sprite.rect.height > playground_height:
            sprite.rect.y = playground_height - sprite.rect.height
            sprite.speed_y = 0

11

Obrázek 10: Screenshot demonstračního příkladu pygame19 při posunu spritu do levého horního rohu.

11. Zdrojový kód demonstračního příkladu pygame19

Obě vylepšení popsaná v předchozích dvou kapitolách jsou přidána do dnešního posledního demonstračního příkladu nazvaného pygame19. Následuje výpis zdrojového kódu tohoto příkladu:

<i>#!/usr/bin/python</i>
<i># vim: set fileencoding=utf-8</i>

<i># Demonstrační příklady využívající knihovnu Pygame</i>

<i># Příklad číslo 19: použití spritů, pohyblivý sprite</i>


<strong>import</strong> pygame, sys, os, math

<i># Nutno importovat kvůli konstantám QUIT atd.</i>
<strong>from</strong> pygame.locals <strong>import</strong> *

<i># Velikost okna aplikace</i>
WIDTH = 320
HEIGHT = 240



<i># Třída představující sprite zobrazený jako jednobarevný čtverec.</i>
<strong>class</strong> BlockySprite(pygame.sprite.Sprite):
    <i># Konstruktor</i>
    <strong>def</strong> __init__(self, color, size, x, y):
        <i># Nejprve je nutné zavolat konstruktor předka,</i>
        <i># tj. konstruktor třídy pygame.sprite.Sprite:</i>
        pygame.sprite.Sprite.__init__(self)

        <i># Vytvoření obrázku představujícího vizuální obraz spritu:</i>
        self.image = pygame.Surface([size,size])
        self.image.fill(color)

        <i># Vytvoření obalového obdélníku</i>
        <i># (velikost se získá z rozměru obrázku)</i>
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

        <i># Počáteční rychlost spritu</i>
        self.speed_x = 0
        self.speed_y = 0



<i># Inicializace knihovny Pygame</i>
pygame.init()

clock = pygame.time.Clock()

<i># Vytvoření okna pro vykreslování</i>
display = pygame.display.set_mode([WIDTH, HEIGHT])

<i># Nastavení titulku okna</i>
pygame.display.set_caption('Pygame test #19')

<i># Konstanty s n-ticemi představujícími základní barvy</i>
BLACK   = (  0,   0,   0)
RED     = (255,   0,   0)
GRAY    = (128, 128, 128)

<i># Objekt sdružující všechny sprity</i>
all_sprites = pygame.sprite.Group()

<i># Vytvoření dvojice spritů - zdi a hráče</i>
wall   = BlockySprite(GRAY, 50, 10, 10)
player = BlockySprite(RED,  25, WIDTH/2, HEIGHT/2)

<i># Přidání dvojice spritů do seznamu</i>
all_sprites.add(wall)
all_sprites.add(player)



<i># Posun všech spritů ve skupině na základě jejich rychlosti</i>
<strong>def</strong> move_sprites(sprite_group, playground_width, playground_height):
    <strong>for</strong> sprite <strong>in</strong> sprite_group:
        <i># Posun spritu</i>
        sprite.rect.x = sprite.rect.x + sprite.speed_x
        sprite.rect.y = sprite.rect.y + sprite.speed_y
        <i># Kontrola, zda sprite nenarazil do okraju okna</i>
        <strong>if</strong> sprite.rect.x < 0:
            sprite.rect.x = 0
            sprite.speed_x = 0
        <strong>if</strong> sprite.rect.x + sprite.rect.width > playground_width:
            sprite.rect.x = playground_width - sprite.rect.width
            sprite.speed_x = 0
        <strong>if</strong> sprite.rect.y < 0:
            sprite.rect.y = 0
            sprite.speed_y = 0
        <strong>if</strong> sprite.rect.y + sprite.rect.height > playground_height:
            sprite.rect.y = playground_height - sprite.rect.height
            sprite.speed_y = 0



<i># Vykreslení celé scény na obrazovku</i>
<strong>def</strong> draw_scene(display, background_color, sprite_group):
    <i># Vyplnění plochy okna černou barvou</i>
    display.fill(background_color)
    <i># Vykreslení celé skupiny spritů do bufferu</i>
    sprite_group.draw(display)
    <i># Obnovení obsahu obrazovky (překlopení zadního a předního bufferu)</i>
    pygame.display.update()



<i># Hlavní herní smyčka</i>
<strong>while</strong> True:
    <i># Načtení a zpracování všech událostí z fronty</i>
    <strong>for</strong> event <strong>in</strong> pygame.event.get():
        <strong>if</strong> event.type == QUIT:
            pygame.quit()
            sys.exit()
        <strong>if</strong> event.type == KEYDOWN:
            <strong>if</strong> event.key == K_ESCAPE:
                pygame.quit()
                sys.exit()
            <i># Stiskem kurzorových kláves je možné měnit směr pohybu spritu</i>
            <strong>elif</strong> event.key == pygame.K_LEFT:
                player.speed_x = -3
            <strong>elif</strong> event.key == pygame.K_RIGHT:
                player.speed_x = +3
            <strong>elif</strong> event.key == pygame.K_UP:
                player.speed_y = -3
            <strong>elif</strong> event.key == pygame.K_DOWN:
                player.speed_y = +3
        <strong>if</strong> event.type == KEYUP:
            <i># Puštění kurzorových kláves vede k zastavení pohybu spritu</i>
            <strong>if</strong> event.key == pygame.K_LEFT:
                player.speed_x = 0
            <strong>elif</strong> event.key == pygame.K_RIGHT:
                player.speed_x = 0
            <strong>elif</strong> event.key == pygame.K_UP:
                player.speed_y = 0
            <strong>elif</strong> event.key == pygame.K_DOWN:
                player.speed_y = 0

    move_sprites(all_sprites, display.get_width(), display.get_height())
    draw_scene(display, BLACK, all_sprites)
    clock.tick(20)

<i># finito</i>

12

Obrázek 12: Screenshot demonstračního příkladu pygame19 při posunu spritu do pravého dolního rohu.

12. Repositář se zdrojovými kódy všech dnešních demonstračních příkladů

Všechny demonstrační příklady, s nimiž jsme se v dnešním článku seznámili, byly, podobně jako v předchozích částech tohoto seriálu, uloženy do Git repositáře umístěného na GitHubu (https://github.com/tisnik/presentations):

# Příklad Zdrojový kód
1 pygame17.py https://github.com/tisnik/presentations/blob/master/pygame/pygame17.py
2 pygame18.py https://github.com/tisnik/presentations/blob/master/pygame/pygame18.py
3 pygame19.py https://github.com/tisnik/presentations/blob/master/pygame/pygame19.py

13. Funkce použité v dnešních demonstračních příkladech

  1. pygame.init()
    http://www.pygame.org/docs/ref/pygame.html#pygame.init
  2. pygame.quit()
    http://www.pygame.org/docs/ref/pygame.html#pygame.quit
  3. pygame.display.set_mode()
    http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode
  4. pygame.display.set_caption()
    http://www.pygame.org/docs/ref/display.html#pygame.display.set_caption
  5. pygame.display.quit()
    http://www.pygame.org/docs/ref/display.html#pygame.display.quit
  6. pygame.display.update()
    http://www.pygame.org/docs/ref/display.html#pygame.display.update
  7. pygame.event.get()
    http://www.pygame.org/docs/ref/event.html#pygame.event.get
  8. pygame.time.Clock()
    http://www.pygame.org/docs/ref/time.html#pygame.time.Clock
  9. pygame.time.Clock.tick()
    http://www.pygame.org/docs/ref/time.html#pygame.time.Clock.tick
  10. pygame.Surface()
    http://www.pygame.org/docs/ref/surface.html
  11. pygame.Surface.fill()
    http://www.pygame.org/docs/ref/surface.html#pygame.Surface.fill
  12. pygame.Sprite.__init__()
    http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Sprite
  13. pygame.sprite.Group()
    http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Group
  14. pygame.sprite.Group.add()
    http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Group.add
  15. pygame.sprite.Group.draw()
    http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Group.draw

14. Odkazy na Internetu

  1. Program Arcade Games With Python And Pygame
    http://programarcadegames.com/index.php?lang=en#
  2. Program Arcade Games With Python And Pygame: Chapter 13: Introduction to Sprites:
    http://programarcadegames.com/index.php?chapter=introduction_to_sprites#
  3. Pygame.org
    http://pygame.org/hifi.html
  4. Pygame - instalační soubory pro různé operační systémy
    http://pygame.org/download.shtml
  5. Pygame: documentation
    http://www.pygame.org/docs/
  6. Pygame Wiki: Getting Started
    http://www.pygame.org/wiki/GettingStarted
  7. Pygame Tutorials: Tutorials Basic
    http://pygametutorials.wikidot.com/tutorials-basic
  8. Pygame: Font class
    http://www.pygame.org/docs/ref/font.html
  9. Python.org (dokumentace k jazyku, odkazy na instalační soubory atd.)
    https://www.python.org/
  10. How to Draw with Pygame on Your Raspberry Pi
    http://www.dummies.com/how-to/content/how-to-draw-with-pygame-on-your-raspberry-pi.html
  11. Bresenham's line algorithm
    https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
  12. Xiaolin Wu's line algorithm
    https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
  13. Pyglet
    https://pypi.python.org/pypi/pyglet/1.2.4
  14. Pyglet documentation
    http://pythonhosted.org/pyglet/
  15. PyOpenGL
    https://pypi.python.org/pypi/PyOpenGL/
  16. Computer font (Wikipedia)
    https://en.wikipedia.org/wiki/Computer_font
  17. TrueType (Wikipedia)
    https://en.wikipedia.org/wiki/TrueType
  18. SDL and Fonts
    http://www.gamedev.net/page/resources/_/technical/game-programming/sdl--fonts-r1953
  19. SDL_ttf Documentation
    http://www.libsdl.org/projects/SDL_ttf/docs/
  20. SDL_ttf 2.0 (není prozatím součástí SDLJava)
    http://www.libsdl.org/projects/SDL_ttf/
  21. SDL_ttf doc
    http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf_frame.html
  22. SDL 1.2 Documentation: SDL_Surface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html
  23. SDL 1.2 Documentation: SDL_PixelFormat
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html
  24. SDL 1.2 Documentation: SDL_LockSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html
  25. SDL 1.2 Documentation: SDL_UnlockSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html
  26. SDL 1.2 Documentation: SDL_LoadBMP
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html
  27. SDL 1.2 Documentation: SDL_SaveBMP
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html
  28. SDL 1.2 Documentation: SDL_BlitSurface
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html
  29. SDL 1.2 Documentation: SDL_VideoInfo
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html
  30. SDL 1.2 Documentation: SDL_GetVideoInfo
    http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html
  31. Graphical user interface (Wikipedia)
    http://en.wikipedia.org/wiki/Graphical_user_interface
  32. The Real History of the GUI
    http://articles.sitepoint.com/article/real-history-gui
  33. Computer-History: Xerox Alto
    http://www.mr-gadget.de/apple/2004-01-15/computer-history-xerox-alto
  34. bitsavers.org
    http://www.bitsavers.org/
  35. Dokumenty k počítači Xerox Alto na bitsavers.org
    http://www.bitsavers.org/pdf/xerox/alto/
  36. The ALTO Computer
    http://www.maniacworld.com/alto-computer-video.html
  37. Xerox Alto Operating System and Alto Applications
    http://www.digibarn.com/collections/software/alto/index.html
  38. Xerox Alto (Wikipedia)
    http://en.wikipedia.org/wiki/Xerox_Alto
  39. BitBLT routines (1975)
    http://www.bitsavers.org/pdf/xerox/alto/BitBLT_Nov1975.pdf
  40. BitBlt in Squeak
    http://wiki.squeak.org/squeak/189
  41. Bitmaps, Device Contexts and BitBlt
    http://www.winprog.org/tutorial/bitmaps.html
  42. BitBlt Game Programming Tutorial
    http://www.freevbcode.com/ShowCode.asp?ID=3677
  43. Bit blit (Wikipedia)
    http://en.wikipedia.org/wiki/BitBLT
  44. The Xerox Alto
    http://toastytech.com/guis/alto3.html
  45. History of the graphical user interface
    http://en.wikipedia.org/wiki/History_of_the_graphical_user_interface
  46. Domovská stránka systému LÖVE
    http://love2d.org/
  47. Dokumentace k systému LÖVE
    http://love2d.org/wiki/love
  48. Domovská stránka programovacího jazyka Lua
    http://www.lua.org/
  49. Seriál o programovacím jazyku Lua (root.cz):
    http://www.root.cz/serialy/programovaci-jazyk-lua/
  50. Web o Lieru, Gusanos, GeneRally, Atari atd.
    http://karelik.wz.cz/
  51. Web o Lieru, Gusanos
    http://karelik.wz.cz/gusanos.php
  52. GUSANOS
    http://gusanos.sourceforge.net/
  53. GUSANOS Download
    http://sourceforge.net/projects/gusanos/
  54. Lua
    http://www.linuxexpres.cz/praxe/lua
  55. Lua
    http://cs.wikipedia.org/wiki/Lua
  56. Lua (programming language)
    http://en.wikipedia.org/wiki/Lua_(programming_language)
  57. The Lua Programming Language
    http://www.tiobe.com/index.php/paperinfo/tpci/Lua.html
  58. Lua Programming Gems
    http://www.lua.org/gems/
  59. LuaForge
    http://luaforge.net/
  60. Forge project tree
    http://luaforge.net/softwaremap/trove_list.php
  61. SdlBasic home page
    http://www.sdlbasic.altervista.org/main/
  62. SdlBasic examples
    http://nitrofurano.linuxkafe.com/sdlbasic/
  63. SdlBasic na Wikipedii
    http://en.wikipedia.org/wiki/SdlBasic
  64. Simple DirectMedia Layer
    http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer
  65. SDLBASIC – The high-level interpreter for all?
    http://openbytes.wordpress.com/2008/11/08/sdlbasic-the-high-level-interpreter-for-all/
  66. FreeBasic home page
    http://www.freebasic.net/
  67. FreeBASIC (Wikipedia EN)
    https://en.wikipedia.org/wiki/FreeBASIC
  68. FreeBASIC Wiki
    http://www.freebasic.net/wiki/wikka.php?wakka=FBWiki
  69. FreeBASIC Manual
    http://www.freebasic.net/wiki/wikka.php?wakka=DocToc
  70. FreeBASIC (Wikipedia CZ)
    http://cs.wikipedia.org/wiki/FreeBASIC
  71. The Griffon Legend
    http://syn9.thingie.net/?table=griffonlegend
  72. Seriál Letní škola programovacího jazyka Logo
    http://www.root.cz/serialy/letni-skola-programovaciho-jazyka-logo/
  73. Scratch: oficiální stránka projektu
    http://scratch.mit.edu/
  74. Scratch: galerie projektů vytvořených ve Scratchi
    http://scratch.mit.edu/galleries/browse/newest
  75. Scratch: nápověda
    file:///usr/share/scratch/Help/en/index.html
  76. Scratch: obrazovky nápovědy
    file:///usr/share/scratch/Help/en/allscreens.html
  77. Scratch (Wikipedie CZ)
    http://cs.wikipedia.org/wiki/Scratch
  78. Scratch (programming language)
    http://en.wikipedia.org/wiki/Scratch_(programming_language)
  79. Scratch Modification
    http://wiki.scratch.mit.edu/wiki/Scratch_Modification
  80. Scratch Lowers Resistance to Programming
    http://www.wired.com/gadgetlab/2009/03/scratch-lowers/
  81. Snap!
    http://snap.berkeley.edu/
  82. Prostředí Snap!
    http://snap.berkeley.edu/snapsource/snap.html
  83. Alternatives to Scratch
    http://wiki.scratch.mit.edu/wiki/Alternatives_to_Scratch
  84. Basic-256 home page
    http://www.basic256.org/index_en
  85. Basic-256 Language Documentation
    http://doc.basic256.org/doku.php
  86. Basic-256 Art Gallery
    http://www.basic256.org/artgallery
  87. Basic-256 Tutorial
    http://www.basic256.org/tutorials
  88. Why BASIC?
    http://www.basic256.org/whybasic
  89. A book to teach ANYBODY how to program a computer (using BASIC)
    http://www.basicbook.org/
  90. BASIC Computer Games (published 1978) - Hammurabi
    http://atariarchives.org/basicgames/showpage.php?page=78
  91. Hamurabi - zdrojový kód v BASICu
    http://www.dunnington.u-net.com/public/basicgames/HMRABI