Ve čtvrtém článku věnovaném programovacím jazykům a taktéž knihovnám, které mohou být vhodné pro výuku programování i základů počítačové grafiky, se opět budeme zabývat popisem možností knihovny LÖVE, o níž jsme se stručně zmínili minule i předminule. Na demonstračních příkladech si ukážeme použití 2D grafiky, tvorbu animací i práci se sprity.
Obsah
1. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky (4)
2. Šestý demonstrační příklad: kreslení s využitím funkcí z modulu love.graphics
3. Nastavení parametrů vykreslování
4. Sedmý demonstrační příklad: kreslení s využitím funkcí z modulu love.graphics, směšování barev
5. Rastrové obrázky a sprity aneb základní objekty při tvorbě 2D her
6. Osmý demonstrační příklad: základy práce se sprity
7. Tvorba animací s využitím callback funkce nazvané love.update()
8. Devátý demonstrační příklad: pohyb spritů na obrazovce (skákající míčky)
9. Otáčení spritů okolo jejich lokální souřadnice [0,0]
10. Desátý demonstrační příklad: otáčení spritů při vykreslování
11. Další parametry funkce love.draw()
12. Jedenáctý demonstrační příklad: korektní rotace spritů
13. Repositář se zdrojovými kódy dnešních demonstračních příkladů
1. Programovací jazyky a knihovny určené pro výuku základů počítačové grafiky (4)
V předchozí části seriálu o programovacích jazycích a taktéž knihovnách, které mohou být vhodné pro výuku programování i základů počítačové grafiky, jsme se seznámili s některými možnostmi nabízenými knihovnou LÖVE. Víme již, že tato knihovna je určena především pro jednoduchou a rychlou tvorbu her s 2D grafikou, hudbou a zvuky, přičemž pro zápis algoritmů se používá snadno naučitelný programovací jazyk Lua. Samozřejmě je možné LÖVE použít i pro tvorbu jiných typů aplikací, například různých dem, simulací s grafickým výstupem atd. (pro složitější aplikace však chybí funkce pro tvorbu plnohodnotného grafického uživatelského rozhraní). Minule jsme si na pěti demonstračních příkladech ukázali některé základní grafické (vykreslovací) funkce a taktéž způsob obsluhy klávesnice a myši. Dnes se zaměříme na popis dalších možností nabízených především subsystémem pro práci s grafikou, tj. na funkce, které lze nalézt v modulu love.graphics.
Obrázek 1: Ukázka hry naprogramované s využitím knihovny LÖVE.
V následující tabulce jsou pro přehlednost uvedeny ty funkce knihovny LÖVE, které budou popsány v dalších kapitolách:
# | Funkce | Kapitola |
---|---|---|
1 | love.graphics.setMode() | 2 |
2 | love.window.setMode() | 2 |
3 | love.graphics.newFont() | 2 |
4 | love.graphics.setFont() | 2 |
5 | love.graphics.print() | 2 |
6 | love.graphics.line() | 2 |
7 | love.graphics.setColor() | 3 |
8 | love.graphics.setColorMask() | 3 |
9 | love.graphics.setColorMode() | 3 |
10 | love.graphics.setBlendMode() | 3 |
11 | love.graphics.setLineWidth() | 3 |
12 | love.graphics.setLineStyle() | 3 |
13 | love.graphics.setLineStipple() | 3 |
14 | love.graphics.setPointSize | 3 |
15 | love.graphics.setPointStyle | 3 |
16 | love.graphics.newImage | 5 |
17 | love.graphics.draw | 5 |
Obrázek 2: Prohlížeč demonstračních příkladů.
2. Šestý demonstrační příklad: kreslení s využitím funkcí z modulu love.graphics
Minule jsme si ukázali, jakým způsobem je možné vykreslit základní grafický obrazec (obdélník) i způsob načtení a následného zobrazení rastrových obrázků. V dalším demonstračním příkladu, který je v pořadí už šestým příkladem, je použito hned několik nových funkcí. První funkce slouží pro nastavení grafického režimu a popř. i pro nastavení velikosti hlavního okna aplikace; tato funkce se tedy může používat v handleru love.load() (ten je zavolán při inicializaci aplikace).
Funkce pro nastavení grafického režimu ve skutečnosti existuje ve dvou variantách v závislosti na tom, která verze knihovny LÖVE je použita. Ve verzi 0.8 se používá funkce nazvaná love.graphics.setMode(), ve verzi 0.9 pak funkce nazvaná love.window.setMode(). I parametry obou zmíněných funkcí se odlišují, nicméně v obou případech se do prvních dvou parametrů zadává velikost hlavního okna aplikace. U funkce love.graphics.setMode() se dále zadává trojice hodnot: zda se má využít celoobrazovkový režim (fullscreen), zda se má při vykreslování čekat na vertikální zatemnění (v-sync) a zda se má použít buffer pro antialiasing. U funkce love.window.setMode() jsou tyto parametry předány v tabulce předané jako třetí parametr (v demonstračním příkladu je tato tabulka prázdná).
Další trojice funkcí, které jsou v tomto demonstračním příkladu použity, slouží pro práci s textem. Jedná se o funkci love.graphics.newFont() určenou pro načtení fontu (my zde používáme výchozí font nabízený knihovnou LÖVE). Funkce love.graphics.setFont() umožňuje vybrat si aktuálně používaný font v případě, že jich je načteno větší množství. A konečně funkce love.graphics.print() vytiskne zadaný řetězec na určené souřadnice na obrazovce. Poslední novou funkcí, která je v příkladu použita, je funkce nazvaná love.graphics.line(). Ta ve své nejjednodušší podobě slouží pro vykreslení úsečky z bodu [x1, y1] do bodu [x2, y2] aktuálně nastavenou barvou.
Obrázek 3: Screenshot v pořadí šestého demonstračního příkladu.
Všechny zmíněné funkce naleznete ve zdrojovém kódu šestého demonstračního příkladu:
-- -- Knihovna LÖVE -- -- Šestý demonstrační příklad -- -- Kreslení s využitím funkcí z knihovny love.graphics -- -- rozměry okna width = 450 height = 450 -- poloměr vykreslovaného obrazce radius = 200 -- -- Funkce volaná při inicializaci aplikace. -- function love.load() -- načtení standardního fontu a nastavení grafického režimu local font = love.graphics.newFont(love.default_font, 20) love.window.setMode(width, height, {}) love.graphics.setFont(font) end -- -- Tato funkce je volána automaticky při překreslení obsahu -- okna či obrazovky. -- function love.draw() local max = 120 -- vykreslení obrazce složeného ze sady rovnostranných trojúhelníků for i=1, max, 3 do -- natočení trojúhelníku local colorAngle = math.rad(i*360/max) -- výpočet a nastavení barvy love.graphics.setColor(128+127*math.cos(colorAngle), 255, 128+128*math.sin(colorAngle)) for j=0, 2 do local angle1 = math.rad(i + j * 120) local angle2 = angle1 + math.rad(120) local x1 = width/2 + radius*math.cos(angle1) local y1 = width/2 + radius*math.sin(angle1) local x2 = width/2 + radius*math.cos(angle2) local y2 = width/2 + radius*math.sin(angle2) love.graphics.line(x1, y1, x2, y2) end end love.graphics.setColor(255, 200, 255, 255) love.graphics.print("Press escape to exit.", 30, 433) end -- -- Callback funkce zavolaná při stisku klávesy. -- function love.keypressed(k) if k == 'escape' then love.event.quit() end end -- -- finito --
Pokud používáte knihovnu LÖVE verze 0.9, je nutné změnit funkci love.load() následujícím způsobem:
-- -- Funkce volaná při inicializaci aplikace. -- function love.load() -- načtení standardního fontu a nastavení grafického režimu local font = love.graphics.newFont(love.default_font, 20) love.window.setMode(width, height, {}) love.graphics.setFont(font) end
Obrázek 4: Chybové hlášení vypsané v případě, že se použije nekompatibilní verze knihovny LÖVE.
3. Nastavení parametrů vykreslování
Knihovna love.graphics obsahuje několik funkcí určených pro vykreslování základních geometrických obrazců, především bodů (love.graphics.point), úseček (love.graphics.line), trojúhelníků (love.graphics.triangle(), obdélníků (love.graphics.rectangle) a kružnic (love.graphics.circle). Tyto obrazce jsou vykresleny nastavenou barvou, tloušťkou čáry, stylem čáry (plná, čárkovaná atd.) a se zapnutým či vypnutým antialiasingem. Povolení antialiasingu funkcí love.graphics.setLineStyle(Linestyle.rough/smooth) poměrně výrazným způsobem zlepšuje kvalitu výsledného obrázku, především u šikmých linek, kde kvůli vlastnostem rastrového displeje dochází k tvorbě „schodů“ – jagged lines, ovšem toto vizuální vylepšení jde na úkor rychlosti vykreslování. U jednodušších her, ve kterých se používá omezený počet objektů (řádově stovky), si však s tímto typem antialiasingu soudobé grafické akcelerátory bez větších problémů poradí, protože vykreslování je prováděno (přes knihovnu OpenGL i ovladač grafické karty) samotným GPU umístěným na akcelerátoru. Seznam nejdůležitějších funkcí ovlivňujících způsob vykreslování, je uveden v tabulce níže:
# | Název funkce | Význam |
---|---|---|
1 | love.graphics.setColor() | nastavení barvy vykreslovaných objektů |
2 | love.graphics.setColorMask() | povoluje či zakazuje jednotlivé barvové kanály (přidáno ve verzi 0.9) |
3 | love.graphics.setColorMode() | určení, zda se má při vykreslování provádět modulace (násobení) barvy s pozadím (odstraněno ve verzi 0.9!) |
4 | love.graphics.setBlendMode() | povolení či zákaz míchání barev s pozadím při vykreslování |
5 | love.graphics.setLineWidth() | šířka čáry při vykreslování |
6 | love.graphics.setLineStyle() | povolení či zákaz antialiasingu při vykreslování úseček |
7 | love.graphics.setLineStipple() | nastavení typu čáry podle zadaného bitového vzorku (odstraněno ve verzi 0.9!) |
8 | love.graphics.setPointSize | velikost vykreslovaných bodů |
9 | love.graphics.setPointStyle | styl vykreslovaných bodů (bez či s antialisingem) |
4. Sedmý demonstrační příklad: kreslení s využitím funkcí z modulu love.graphics, směšování barev
V sedmém demonstračním příkladu, jehož zdrojový kód je vypsán pod tímto odstavcem, je ukázáno použití funkce love.graphics.setBlendMode() i význam čtvrtého (nepovinného) parametru funkce love.graphics.setColor(), nazývaného alfa (alpha). Tento parametr určuje průhlednost nastavené barvy a tím i celkový vizuální vzhled objektu. Po spuštění demonstračního příkladu je možné pomocí klávesy B přepínat režim míchání barev mezi "alpha" a "additive". V závislosti na vybraném režimu je buď nastavená barva pouze vynásobena hodnotou alfa (předaná hodnota je nejprve vydělena 255, aby se nacházela v rozsahu 0.0 až 1.0), ovšem ve druhém případě je proveden součet barvy pozadí (tj. i dříve nakreslených objektů) s barvou vykreslovaného objektu, takže v místech, kde se objekty překrývají, dochází ke zvýšení intenzity barev, což ostatně můžeme vidět dvojici screenshotů:
Obrázek 5: Screenshot sedmého demonstračního příkladu.
Obrázek 6: Screenshot sedmého demonstračního příkladu (změna režimu směšování barev).
-- -- Knihovna LÖVE -- -- Sedmý demonstrační příklad -- -- Kreslení s využitím funkcí z knihovny love.graphics, nastavení režimu -- směšování barev -- -- rozměry okna width = 450 height = 450 -- poloměr vykreslovaného obrazce radius = 200 -- režim směšování barev blending = "alpha" -- konstanta pro směšování blend_factor = 80 -- -- Funkce volaná při inicializaci aplikace. -- function love.load() -- načtení standardního fontu a nastavení grafického režimu local font = love.graphics.newFont(love.default_font, 20) love.graphics.setMode(width, height, false, false, 0) love.graphics.setFont(font) end -- -- Tato funkce je volána automaticky při překreslení obsahu -- okna či obrazovky. -- function love.draw() -- nastavení režimu směšování barev love.graphics.setBlendMode(blending) love.graphics.setColor(255, 255, 255, blend_factor) -- vykreslení obrazce for i=1, 90 do for j=0, 3 do local angle1 = math.rad(i + j * 90) local angle2 = angle1 + 90 local x1 = width/2 + radius*math.cos(angle1*2) local y1 = width/2 + radius*math.sin(angle1*3) local x2 = width/2 + radius*math.cos(angle2*3) local y2 = width/2 + radius*math.sin(angle2*2) love.graphics.line(x1, y1, x2, y2) end end love.graphics.setColor(255, 200, 255, 255) love.graphics.print("Press escape to exit.", 30, 433) end -- -- Callback funkce zavolaná při stisku klávesy. -- function love.keypressed(k) if k == 'escape' then love.event.quit() elseif k == 'b' then setBlending() end end -- povolení či zákaz směšování barev po stisku klávesy "b" function setBlending() if blending == "alpha" then blending = "additive" else blending = "alpha" end end -- -- finito --
Podobně jako u předchozího příkladu platí, že pokud používáte knihovnu LÖVE verze 0.9, je nutné změnit funkci love.load() následujícím způsobem:
-- -- Funkce volaná při inicializaci aplikace. -- function love.load() -- načtení standardního fontu a nastavení grafického režimu local font = love.graphics.newFont(love.default_font, 20) love.window.setMode(width, height, {}) love.graphics.setFont(font) end
5. Rastrové obrázky a sprity aneb základní objekty při tvorbě 2D her
Základní grafickou entitou používanou při tvorbě naprosté většiny klasických her s 2D grafikou, jsou rastrové obrázky, jejichž některé pixely jsou buď zcela průhledné či poloprůhledné. Díky měnitelné průhlednosti (definované až na úroveň jednotlivých pixelů) je možné takové rastrové obrázky použít pro zobrazení pohybujících se objektů či naopak statických prvků jednotlivých scén, které mohou překrývat pozadí. V dobách osmibitových domácích mikropočítačů a herních konzolí se takové bitmapy (s malým rozlišením a omezeným množstvím barev) označovaly jménem sprite a o jejich vykreslování se mnohdy staraly specializované čipy. Dnes je vlastně situace obdobná, protože bitmapy jsou (i s případnou průhledností) vykreslovány s využitím grafických akcelerátorů a jejich GPU. V následujících demonstračních příkladech si ukážeme použití moderní obdoby spritů s využitím funkcí nabízených knihovnou LÖVE.
Obrázek 7: Historická hra pro osmibitové mikropočítače (Draconus), v níž se pro zobrazení postavy ovládané hráčem používaly hardwarově vykreslované sprity, tj. bitmapy o malém rozlišení a omezeném počtu barev, o jejichž vykreslení se staral specializovaný čip.
6. Osmý demonstrační příklad: základy práce se sprity
V tomto demonstračním příkladu si připomeneme, jakým způsobem se rastrový obrázek dá načíst z externího souboru a jaká funkce posléze slouží k jeho zobrazení. Načtení obrázku je realizováno funkcí love.graphics.newImage(), která dokáže pracovat s prakticky všemi základními grafickými formáty, samozřejmě včetně dnes pravděpodobně nejpoužívanějších formátů PNG a JPEG. Při použití formátu PNG je plně podporována průhlednost jednotlivých pixelů, a to jak průhlednost reprezentovaná jedním bitem (pixel je buď plně průhledný či naopak zcela neprůhledný), tak i plnohodnotný alfa kanál. Podrobnosti o možnostech formátu PNG jsou popsány v článcích PNG is not GIF a PNG - bity, byty, chunky, nás však dnes bude zajímat především fakt, že právě PNG lze použít pro tvorbu plnohodnotných spritů. Obrázky s průhledností jsou totiž v osmém demonstračním příkladu použity pro vytvoření následující 2D scény:
Obrázek 8: Screenshot osmého demonstračního příkladu.
Následuje výpis zdrojového kódu osmého demonstračního příkladu:
-- -- Knihovna LÖVE -- -- Osmý demonstrační příklad -- -- Práce se sprity. -- -- rozměry okna width = 450 height = 450 local sprite1 = nil local sprite2 = nil -- -- Funkce volaná při inicializaci aplikace. -- function love.load() -- načtení standardního fontu a nastavení grafického režimu local font = love.graphics.newFont(love.default_font, 40) -- načtení spritů sprite1 = love.graphics.newImage("sprite1.png") sprite2 = love.graphics.newImage("sprite2.png") love.graphics.setMode(width, height, false, false, 0) love.graphics.setFont(font) end -- -- Tato funkce je volána automaticky při překreslení obsahu -- okna či obrazovky. -- function love.draw() -- velikost okna local windowWidth = love.graphics.getWidth() local windowHeight = love.graphics.getHeight() -- vykreslení mřížky for y=0, windowHeight - sprite2:getHeight(), sprite2:getHeight()+5 do for x=0, windowWidth - sprite2:getWidth(), sprite2:getWidth()+5 do love.graphics.draw(sprite2, x, y) end end -- vykreslení prvního spritu přes ostatní sprity love.graphics.draw(sprite1, 30, 30) love.graphics.print("Press escape to exit.", 30, 433) end -- -- Callback funkce zavolaná při stisku klávesy. -- function love.keypressed(k) if k == 'escape' then love.event.quit() end end -- -- finito --
7. Tvorba animací s využitím callback funkce nazvané love.update()
Všechny předchozí příklady pouze zobrazovaly statickou 2D scénu, což vlastně ani není příliš zajímavé. Užitečnější je tvorba animací, ať již animací běžících zcela automaticky (různá grafická dema atd.), tak i dynamických scén, které může svou činností ovlivňovat uživatel (počítačové hry). V obou případech je nutné, aby existovala nějaká periodicky volaná funkce, v jejímž těle se mění stav programu a tím pádem i například pozice spritů na obrazovce. V knihovně LÖVE se tato funkce jmenuje love.update(). Tuto funkci automaticky volá engine knihovny LÖVE a uživatel může sám zjistit, kolik času uběhlo od předchozího volání této funkce přečtením jejího parametru dt (tento čas je udaný v sekundách, ovšem jedná se o číslo s plovoucí řádovou čárkou, takže časový úsek je možné měřit s větší přesností). Jedna z možností, jak zajistit změnu stavu programu v pravidelných intervalech (zde konkrétně v intervalu jedné třicetiny sekundy) spočívá v použití funkce love.timer.sleep(), která pozastaví provádění celého programu po nastavený časový okamžik. Nepříliš přesné, ovšem pro nás dostačující, řešení může vypadat následovně:
-- -- Funkce volaná cca 30x za sekundu -- function love.update(dt) -- změna stavu aplikace -- změna stavu aplikace -- změna stavu aplikace local delay = 1/30 if dt < delay then love.timer.sleep(delay - dt) end end
8. Devátý demonstrační příklad: pohyb spritů na obrazovce (skákající míčky)
Funkce love.update(), která byla zmíněná v předchozí kapitole, je použita v devátém demonstračním příkladu pro animaci třech skákajících míčků představovaných ve vykreslované scéně sprity. Stav celého programu je uložen v proměnných sprite1, sprite2 a sprite3, což jsou asociativní pole obsahující jak vlastní sprite (obrázek s poloprůhlednými i průhlednými pixely), tak i jeho aktuální pozici na obrazovce a vektor pohybu (proměnné dx, dy, zjednodušeně tento vektor můžeme považovat za rychlost). Vertikální složka vektoru pohybu se v čase postupně mění, čímž je simulován vliv gravitace. Odrážení míčků od stěn je jednoduché – pouze se změní znaménko horizontální či vertikální složky vektoru pohybu. Animaci a současně i celý program je možné zastavit klávesou Esc. Animace vytvořená tímto demonstračním programem vypadá následovně:
Zdrojový kód devátého demonstračního příkladu:
-- -- Knihovna LÖVE -- -- Devátý demonstrační příklad -- -- Práce se sprity: zobrazení, posun. -- (skákající míčky) -- -- rozměry okna width = 450 height = 450 -- objekty představující sprity zobrazené v okně local sprite1 = {x=100, y=100, dx=4, dy=0} local sprite2 = {x=200, y=10, dx=3, dy=0} local sprite3 = {x=300, y=100, dx=2, dy=0} -- -- Funkce volaná při inicializaci aplikace. -- function love.load() -- načtení standardního fontu a nastavení grafického režimu local font = love.graphics.newFont(love.default_font, 40) -- načtení spritů sprite1.image = love.graphics.newImage("sprite2.png") sprite2.image = love.graphics.newImage("sprite1.png") sprite3.image = love.graphics.newImage("sprite2.png") love.graphics.setMode(width, height, false, false, 0) -- nastavení fontu love.graphics.setFont(font) end -- -- Vykreslení spritu s jeho posunem. -- function drawSprite(sprite) -- vykreslení spritu s posunem love.graphics.draw(sprite.image, sprite.x, sprite.y) end -- -- Tato funkce je volána automaticky při překreslení obsahu -- okna či obrazovky. -- function love.draw() -- vykreslení prvního spritu přes ostatní sprity drawSprite(sprite1) -- vykreslení druhého spritu přes ostatní sprity drawSprite(sprite2) -- vykreslení třetího spritu přes ostatní sprity drawSprite(sprite3) love.graphics.print("Press escape to exit.", 30, 433) end -- -- Změna pozice spritů v okně -- function updateSpritePosition(sprite) -- velikost okna local windowWidth = love.graphics.getWidth() local windowHeight = love.graphics.getHeight() sprite.x = sprite.x + sprite.dx sprite.y = sprite.y + sprite.dy if sprite.x < 1 or sprite.x > windowWidth - sprite.image:getWidth() - 2 then sprite.dx = -sprite.dx end if sprite.y < 1 or sprite.y > windowHeight - sprite.image:getHeight() - 2 then sprite.dy = -sprite.dy end sprite.dy = sprite.dy + 0.1 end -- -- Funkce volaná cca 30x za sekundu -- function love.update(dt) updateSpritePosition(sprite1) updateSpritePosition(sprite2) updateSpritePosition(sprite3) local delay = 1/30 if dt < delay then love.timer.sleep(delay - dt) end end -- -- Callback funkce zavolaná při stisku klávesy. -- function love.keypressed(k) if k == 'escape' then love.event.quit() end end -- -- finito --
Obrázek 9: Screenshot devátého demonstračního příkladu.
9. Otáčení spritů okolo jejich lokální souřadnice [0,0]
Funkce love.graphics.draw() používaná mj. i pro vykreslení obrázků do 2D scény, ve skutečnosti akceptuje více parametrů, než jen proměnnou obsahující obrázek a x-ovou i y-ovou pozici obrázku na obrazovce. Čtvrtým parametrem této funkce je možné specifikovat otočení obrázku, což se samozřejmě může v mnoha případech hodit (představit si můžeme například vesmírnou střílečku typu Asteroids či závodní hru, kde jsou autíčka viděna svrchu). Při rotaci obrázků v průběhu jejich vykreslování je však zapotřebí dbát na dvě vlastnosti funkce love.graphics.draw(). Rotace je udávána v radiánech, takže pokud se ve hře úhel reprezentuje ve stupních, je nutné zajistit převod této hodnoty, například vynásobením konstantou 180/π. Druhá vlastnost může přinášet jisté komplikace – otáčení obrázku je totiž provedeno okolo jeho počátku, tj. okolo souřadnic [0,0] a nikoli okolo středu obrázku. Výsledek tedy nemusí ve všech případech odpovídat představám vývojáře, o čemž se přesvědčíme hned v dalším demonstračním příkladu.
10. Desátý demonstrační příklad: otáčení spritů při vykreslování
V desátém demonstračním příkladu je ukázáno použití funkce love.graphics.draw() pro vykreslení otočených obrázků. Opět se jedná o animaci, přičemž se ve funkci love.update() mění pouze proměnná sprite.r představující úhel otočení daného spritu reprezentovaný v radiánech. O vykreslení spritů se stará uživatelská funkce pojmenovaná drawSprite(), jejíž zdrojový kód vypadá následovně:
-- -- Vykreslení spritu s jeho otočením. -- function drawSprite(sprite) -- vykreslení spritu s rotací love.graphics.draw(sprite.image, sprite.x, sprite.y, sprite.r) end
Vzhledem k tomu, že sprity jsou otáčeny okolo jejich lokální souřadnice [0,0], nebude pravděpodobně výsledná animace odpovídat představám vývojáře, o čemž se ostatně můžeme snadno přesvědčit:
Zdrojový kód desátého demonstračního příkladu:
-- -- Knihovna LÖVE -- -- Desátý demonstrační příklad -- -- Práce se sprity: zobrazení, otočení. -- -- rozměry okna width = 450 height = 450 -- objekty představující sprity zobrazené v okně local sprite1 = {x=100, y=100, r=0, dr=-0.17} local sprite2 = {x=185, y=80, r=0, dr=0.1} local sprite3 = {x=300, y=100, r=0, dr=0.05} -- -- Funkce volaná při inicializaci aplikace. -- function love.load() -- načtení standardního fontu a nastavení grafického režimu local font = love.graphics.newFont(love.default_font, 40) -- načtení spritů sprite1.image = love.graphics.newImage("sprite2.png") sprite2.image = love.graphics.newImage("sprite1.png") sprite3.image = love.graphics.newImage("sprite2.png") love.graphics.setMode(width, height, false, false, 0) -- nastavení fontu love.graphics.setFont(font) end -- -- Vykreslení spritu s jeho otočením. -- function drawSprite(sprite) -- vykreslení spritu s rotací love.graphics.draw(sprite.image, sprite.x, sprite.y, sprite.r) end -- -- Tato funkce je volána automaticky při překreslení obsahu -- okna či obrazovky. -- function love.draw() -- vykreslení prvního spritu přes ostatní sprity drawSprite(sprite1) -- vykreslení druhého spritu přes ostatní sprity drawSprite(sprite2) -- vykreslení třetího spritu přes ostatní sprity drawSprite(sprite3) love.graphics.print("Press escape to exit.", 30, 433) end -- -- Změna rotace spritů v okně -- function updateSpriteAngle(sprite) sprite.r = sprite.r + sprite.dr end -- -- Funkce volaná cca 30x za sekundu -- function love.update(dt) updateSpriteAngle(sprite1) updateSpriteAngle(sprite2) updateSpriteAngle(sprite3) local delay = 1/30 if dt > delay then love.timer.sleep(delay - dt) end end -- -- Callback funkce zavolaná při stisku klávesy. -- function love.keypressed(k) if k == 'escape' then love.event.quit() end end -- -- finito --
Obrázek 10: Screenshot desátého demonstračního příkladu: začátek animace.
Obrázek 11: Screenshot desátého demonstračního příkladu: průběh animace.
11. Další parametry funkce love.draw()
Problém s rotací obrázků, se kterým jsme se setkali v předchozím demonstračním příkladu, je možné řešit dvěma způsoby: změnou souřadného systému (to si popíšeme příště) popř. použitím dalších parametrů funkce love.graphics.draw. Tato funkce totiž ve skutečnosti akceptuje až deset parametrů s následujícím významem:
# | Parametr | Význam |
---|---|---|
1 | drawable | obrázek či jiný objekt, který se má vykreslit |
2 | x | horizontální souřadnice obrázku na obrazovce |
3 | y | vertikální souřadnice obrázku na obrazovce |
4 | r | otočení obrázku (radiány) |
5 | sx | horizontální měřítko obrázku (1=beze změny velikosti) |
6 | sy | vertikální měřítko obrázku (1=beze změny velikosti) |
7 | ox | horizontální offset (ten se používá při otáčení) |
8 | oy | vertikální offset |
9 | kx | horizontální zešikmení |
10 | ky | vertikální zešikmení |
Pro rotaci obrázku okolo jakéhokoli bodu tedy postačuje vhodným způsobem specifikovat horizontální a vertikální offset. Konkrétně pro rotaci okolo středu obrázku:
-- -- Vykreslení spritu s jeho otočením. -- function drawSprite(sprite) -- vykreslení spritu love.graphics.draw(sprite.image, sprite.x, sprite.y, -- souřadnice na obrazovce (umístění spritu) sprite.r, -- rotace 1.0, 1.0, -- zvětšení/změna měřítka sprite.image:getWidth()/2, sprite.image:getHeight()/2) -- posun pozice středu otáčení end
12. Jedenáctý demonstrační příklad: korektní rotace spritů
Upravená funkce drawSprite() zmíněná v předchozí kapitole, která otáčí každý obrázek/sprite okolo jeho středu, je součástí jedenáctého a současně i posledního demonstračního příkladu. Po jeho spuštění se zobrazí tato animace:
Zdrojový kód jedenáctého demonstračního příkladu:
-- -- Knihovna LÖVE -- -- Jedenáctý demonstrační příklad -- -- Práce se sprity: zobrazení, otočení (korektní rotace). -- -- rozměry okna width = 450 height = 450 -- objekty představující sprity zobrazené v okně local sprite1 = {x=100, y=100, r=0, dr=-0.17} local sprite2 = {x=185, y=80, r=0, dr=0.1} local sprite3 = {x=300, y=100, r=0, dr=0.05} -- -- Funkce volaná při inicializaci aplikace. -- function love.load() -- načtení standardního fontu a nastavení grafického režimu local font = love.graphics.newFont(love.default_font, 40) -- načtení spritů sprite1.image = love.graphics.newImage("sprite2.png") sprite2.image = love.graphics.newImage("sprite1.png") sprite3.image = love.graphics.newImage("sprite2.png") love.graphics.setMode(width, height, false, false, 0) -- nastavení fontu love.graphics.setFont(font) end -- -- Vykreslení spritu s jeho otočením. -- function drawSprite(sprite) -- vykreslení spritu love.graphics.draw(sprite.image, sprite.x, sprite.y, -- souřadnice na obrazovce (umístění spritu) sprite.r, -- rotace 1.0, 1.0, -- zvětšení sprite.image:getWidth()/2, sprite.image:getHeight()/2) -- posun pozice středu otáčení end -- -- Tato funkce je volána automaticky při překreslení obsahu -- okna či obrazovky. -- function love.draw() -- vykreslení prvního spritu přes ostatní sprity drawSprite(sprite1) -- vykreslení druhého spritu přes ostatní sprity drawSprite(sprite2) -- vykreslení třetího spritu přes ostatní sprity drawSprite(sprite3) love.graphics.print("Press escape to exit.", 30, 433) end -- -- Změna rotace spritů v okně -- function updateSpriteAngle(sprite) sprite.r = sprite.r + sprite.dr end -- -- Funkce volaná cca 30x za sekundu -- function love.update(dt) updateSpriteAngle(sprite1) updateSpriteAngle(sprite2) updateSpriteAngle(sprite3) local delay = 1/30 if dt > delay then love.timer.sleep(delay - dt) end end -- -- Callback funkce zavolaná při stisku klávesy. -- function love.keypressed(k) if k == 'escape' then love.event.quit() end end -- -- finito --
Obrázek 12: Screenshot jedenáctého demonstračního příkladu: začátek animace.
Obrázek 13: Screenshot jedenáctého demonstračního příkladu: průběh animace.
Obrázek 14: Screenshot jedenáctého demonstračního příkladu: průběh animace.
13. Repositář se zdrojovými kódy dnešních demonstračních příkladů
Všech šest demonstračních příkladů, s nimiž jsme se v dnešním článku seznámili, bylo uloženo do Git repositáře na GitHubu (https://github.com/tisnik/presentations):
# | Příklad | Zdrojový kód |
---|---|---|
1 | example06 pro v0.8 | https://github.com/tisnik/presentations/tree/master/love/example06 |
2 | example06 pro v0.9 | https://github.com/tisnik/presentations/tree/master/love/example06_v09 |
3 | example07 pro v0.8 | https://github.com/tisnik/presentations/tree/master/love/example07 |
4 | example07 pro v0.9 | https://github.com/tisnik/presentations/tree/master/love/example07_v09 |
5 | example08 | https://github.com/tisnik/presentations/tree/master/love/example08 |
6 | example09 | https://github.com/tisnik/presentations/tree/master/love/example09 |
7 | example10 | https://github.com/tisnik/presentations/tree/master/love/example10 |
8 | example11 | https://github.com/tisnik/presentations/tree/master/love/example11 |
14. Odkazy na Internetu
- 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/ - Domovská stránka systému LÖVE
http://love2d.org/ - Domovská stránka programovacího jazyka Lua
http://www.lua.org/ - 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