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
2. Vytvoření vlastního spritu s využitím třídy pygame.sprite.Sprite
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
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).
Obrázek 1: Scéna vykreslená pixel po pixelu, tj. explicitním nastavením barvy každého pixelu framebufferu.
Obrázek 2: Různobarevné úsečky vykreslené bez použití antialiasingu.
Obrázek 3: Tytéž úsečky, ovšem nyní vykreslené s použitím antialiasingu.
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.
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>
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()
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
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>
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
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
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>
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
- pygame.init()
http://www.pygame.org/docs/ref/pygame.html#pygame.init - pygame.quit()
http://www.pygame.org/docs/ref/pygame.html#pygame.quit - pygame.display.set_mode()
http://www.pygame.org/docs/ref/display.html#pygame.display.set_mode - pygame.display.set_caption()
http://www.pygame.org/docs/ref/display.html#pygame.display.set_caption - pygame.display.quit()
http://www.pygame.org/docs/ref/display.html#pygame.display.quit - pygame.display.update()
http://www.pygame.org/docs/ref/display.html#pygame.display.update - pygame.event.get()
http://www.pygame.org/docs/ref/event.html#pygame.event.get - pygame.time.Clock()
http://www.pygame.org/docs/ref/time.html#pygame.time.Clock - pygame.time.Clock.tick()
http://www.pygame.org/docs/ref/time.html#pygame.time.Clock.tick - pygame.Surface()
http://www.pygame.org/docs/ref/surface.html - pygame.Surface.fill()
http://www.pygame.org/docs/ref/surface.html#pygame.Surface.fill - pygame.Sprite.__init__()
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Sprite - pygame.sprite.Group()
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Group - pygame.sprite.Group.add()
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Group.add - pygame.sprite.Group.draw()
http://www.pygame.org/docs/ref/sprite.html#pygame.sprite.Group.draw
14. Odkazy na Internetu
- Program Arcade Games With Python And Pygame
http://programarcadegames.com/index.php?lang=en# - Program Arcade Games With Python And Pygame: Chapter 13: Introduction to Sprites:
http://programarcadegames.com/index.php?chapter=introduction_to_sprites# - Pygame.org
http://pygame.org/hifi.html - Pygame - instalační soubory pro různé operační systémy
http://pygame.org/download.shtml - Pygame: documentation
http://www.pygame.org/docs/ - Pygame Wiki: Getting Started
http://www.pygame.org/wiki/GettingStarted - Pygame Tutorials: Tutorials Basic
http://pygametutorials.wikidot.com/tutorials-basic - Pygame: Font class
http://www.pygame.org/docs/ref/font.html - Python.org (dokumentace k jazyku, odkazy na instalační soubory atd.)
https://www.python.org/ - 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 - Bresenham's line algorithm
https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm - Xiaolin Wu's line algorithm
https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm - Pyglet
https://pypi.python.org/pypi/pyglet/1.2.4 - Pyglet documentation
http://pythonhosted.org/pyglet/ - PyOpenGL
https://pypi.python.org/pypi/PyOpenGL/ - Computer font (Wikipedia)
https://en.wikipedia.org/wiki/Computer_font - TrueType (Wikipedia)
https://en.wikipedia.org/wiki/TrueType - SDL and Fonts
http://www.gamedev.net/page/resources/_/technical/game-programming/sdl--fonts-r1953 - SDL_ttf Documentation
http://www.libsdl.org/projects/SDL_ttf/docs/ - SDL_ttf 2.0 (není prozatím součástí SDLJava)
http://www.libsdl.org/projects/SDL_ttf/ - SDL_ttf doc
http://www.libsdl.org/projects/SDL_ttf/docs/SDL_ttf_frame.html - SDL 1.2 Documentation: SDL_Surface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsurface.html - SDL 1.2 Documentation: SDL_PixelFormat
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlpixelformat.html - SDL 1.2 Documentation: SDL_LockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdllocksurface.html - SDL 1.2 Documentation: SDL_UnlockSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlunlocksurface.html - SDL 1.2 Documentation: SDL_LoadBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlloadbmp.html - SDL 1.2 Documentation: SDL_SaveBMP
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlsavebmp.html - SDL 1.2 Documentation: SDL_BlitSurface
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlblitsurface.html - SDL 1.2 Documentation: SDL_VideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlvideoinfo.html - SDL 1.2 Documentation: SDL_GetVideoInfo
http://www.libsdl.org/release/SDL-1.2.15/docs/html/sdlgetvideoinfo.html - Graphical user interface (Wikipedia)
http://en.wikipedia.org/wiki/Graphical_user_interface - The Real History of the GUI
http://articles.sitepoint.com/article/real-history-gui - Computer-History: Xerox Alto
http://www.mr-gadget.de/apple/2004-01-15/computer-history-xerox-alto - bitsavers.org
http://www.bitsavers.org/ - Dokumenty k počítači Xerox Alto na bitsavers.org
http://www.bitsavers.org/pdf/xerox/alto/ - The ALTO Computer
http://www.maniacworld.com/alto-computer-video.html - Xerox Alto Operating System and Alto Applications
http://www.digibarn.com/collections/software/alto/index.html - Xerox Alto (Wikipedia)
http://en.wikipedia.org/wiki/Xerox_Alto - BitBLT routines (1975)
http://www.bitsavers.org/pdf/xerox/alto/BitBLT_Nov1975.pdf - BitBlt in Squeak
http://wiki.squeak.org/squeak/189 - Bitmaps, Device Contexts and BitBlt
http://www.winprog.org/tutorial/bitmaps.html - BitBlt Game Programming Tutorial
http://www.freevbcode.com/ShowCode.asp?ID=3677 - Bit blit (Wikipedia)
http://en.wikipedia.org/wiki/BitBLT - The Xerox Alto
http://toastytech.com/guis/alto3.html - History of the graphical user interface
http://en.wikipedia.org/wiki/History_of_the_graphical_user_interface - Domovská stránka systému LÖVE
http://love2d.org/ - Dokumentace k systému LÖVE
http://love2d.org/wiki/love - Domovská stránka programovacího jazyka Lua
http://www.lua.org/ - Seriál o programovacím jazyku Lua (root.cz):
http://www.root.cz/serialy/programovaci-jazyk-lua/ - Web o Lieru, Gusanos, GeneRally, Atari atd.
http://karelik.wz.cz/ - Web o Lieru, Gusanos
http://karelik.wz.cz/gusanos.php - GUSANOS
http://gusanos.sourceforge.net/ - GUSANOS Download
http://sourceforge.net/projects/gusanos/ - Lua
http://www.linuxexpres.cz/praxe/lua - Lua
http://cs.wikipedia.org/wiki/Lua - Lua (programming language)
http://en.wikipedia.org/wiki/Lua_(programming_language) - The Lua Programming Language
http://www.tiobe.com/index.php/paperinfo/tpci/Lua.html - Lua Programming Gems
http://www.lua.org/gems/ - LuaForge
http://luaforge.net/ - Forge project tree
http://luaforge.net/softwaremap/trove_list.php - SdlBasic home page
http://www.sdlbasic.altervista.org/main/ - SdlBasic examples
http://nitrofurano.linuxkafe.com/sdlbasic/ - SdlBasic na Wikipedii
http://en.wikipedia.org/wiki/SdlBasic - Simple DirectMedia Layer
http://en.wikipedia.org/wiki/Simple_DirectMedia_Layer - SDLBASIC – The high-level interpreter for all?
http://openbytes.wordpress.com/2008/11/08/sdlbasic-the-high-level-interpreter-for-all/ - FreeBasic home page
http://www.freebasic.net/ - FreeBASIC (Wikipedia EN)
https://en.wikipedia.org/wiki/FreeBASIC - FreeBASIC Wiki
http://www.freebasic.net/wiki/wikka.php?wakka=FBWiki - FreeBASIC Manual
http://www.freebasic.net/wiki/wikka.php?wakka=DocToc - FreeBASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/FreeBASIC - The Griffon Legend
http://syn9.thingie.net/?table=griffonlegend - Seriál Letní škola programovacího jazyka Logo
http://www.root.cz/serialy/letni-skola-programovaciho-jazyka-logo/ - Scratch: oficiální stránka projektu
http://scratch.mit.edu/ - Scratch: galerie projektů vytvořených ve Scratchi
http://scratch.mit.edu/galleries/browse/newest - Scratch: nápověda
file:///usr/share/scratch/Help/en/index.html - Scratch: obrazovky nápovědy
file:///usr/share/scratch/Help/en/allscreens.html - Scratch (Wikipedie CZ)
http://cs.wikipedia.org/wiki/Scratch - Scratch (programming language)
http://en.wikipedia.org/wiki/Scratch_(programming_language) - Scratch Modification
http://wiki.scratch.mit.edu/wiki/Scratch_Modification - Scratch Lowers Resistance to Programming
http://www.wired.com/gadgetlab/2009/03/scratch-lowers/ - Snap!
http://snap.berkeley.edu/ - Prostředí Snap!
http://snap.berkeley.edu/snapsource/snap.html - Alternatives to Scratch
http://wiki.scratch.mit.edu/wiki/Alternatives_to_Scratch - Basic-256 home page
http://www.basic256.org/index_en - Basic-256 Language Documentation
http://doc.basic256.org/doku.php - Basic-256 Art Gallery
http://www.basic256.org/artgallery - Basic-256 Tutorial
http://www.basic256.org/tutorials - Why BASIC?
http://www.basic256.org/whybasic - A book to teach ANYBODY how to program a computer (using BASIC)
http://www.basicbook.org/ - BASIC Computer Games (published 1978) - Hammurabi
http://atariarchives.org/basicgames/showpage.php?page=78 - Hamurabi - zdrojový kód v BASICu
http://www.dunnington.u-net.com/public/basicgames/HMRABI