Obsah
1. Seznam demonstračních příkladů a způsob jejich spuštění
2. Zjištění všech dostupných celoobrazovkových režimů
3. Načtení externího fontu a vykreslení všech jeho znaků
4. Natočení textu při jeho vykreslování
5. Funkce určené pro změnu stylu vykreslování
6. Vykreslení jednoduchého obrazce pomocí funkcí z knihovny love.graphics
7. Nastavení míchání barev a použití průhlednosti při vykreslování
8. Základ animací
9. Načtení externího obrázku, vykreslení obrázku v animaci s jeho natočením
1. Seznam demonstračních příkladů a způsob jejich spuštění
V dnešním článku bude mj. uvedeno sedm demonstračních příkladů, na nichž si vysvětlíme některé základní funkce systému LÖVE. Nejprve si řekněme, jakým způsobem je možné tyto demonstrační příklady spustit (předpokladem samozřejmě je, že systém LÖVE je již nainstalovaný). Nejjednodušší metoda spočívá v tom, že se interpretr love či love.exe spustí s jedním parametrem, kterým je název (popřípadě doplněný i o cestu) k souboru s koncovkou .love. Tento soubor není ve skutečnosti nic jiného než archiv vytvořený programem typu zip, jenž obsahuje několik souborů: konfigurační soubor game.conf (který prozatím nevyužíváme, proto má jen velmi jednoduchou strukturu), vlastní skript představující aplikaci (hru) nazvaný main.lua a v případě potřeby i další potřebné soubory – většinou se v demonstračních příkladech jedná o font DejaVuLGCSansMono.ttf nebo o rastrový obrázek gnome-globe.png.
Výsledné balíky tedy obsahují všechna data potřebná pro jejich běh (pozor – musí se komprimovat přímo soubory se hrou, nikoli nadřazený adresář!). Druhou možností spouštění, kterou využijí především vývojáři, je vyvolání interpretru love či love.exe s jedním parametrem představujícím cestu k adresáři, který obsahuje všechny výše uvedené soubory (nesmí se uvést přímo cesta ke skriptu main.lua, ale k celému adresáři). Je tedy možné například soubor gfx_modes.love rozbalit programem unzip (či podobnou aplikací) do samostatného adresáře a cestu k tomuto adresáři předat interpretru. V následující tabulce jsou uloženy odkazy na všech sedm demonstračních příkladů popsaných v následujících kapitolách:
Název příkladu | Balík s příkladem |
---|---|
Zjištění dostupných celoobrazovkových režimů | gfx_modes.love |
Načtení externího fontu | fonts1.love |
Natočení textu | fonts2.love |
Vykreslení jednoduchého obrazce | drawing1.love |
Nastavení míchání barev | drawing2.love |
Jednoduchá animace | animation.love |
Pohybující se rastrový obrázek | images.love |
2. Zjištění všech dostupných celoobrazovkových režimů
Již v předchozí části tohoto seriálu jsme si řekli, že systém LÖVE umožňuje běh hry či jiné multimediální aplikace jak v běžném okně (vytvářeném pomocí správce oken daného operačního systému), tak i v takzvaném celoobrazovkovém režimu – fullscreen mode. V celoobrazovkovém režimu má aplikace zajištěn exkluzivní přístup k části video paměti a při porušení této oblasti paměti (tj. například ve chvíli přepnutí do jiné aplikace) systém sám požádá o překreslení celé scény. Okno či celoobrazovkový režim je možné nastavit pomocí funkce love.graphics.setMode(), ovšem před voláním této funkce je vhodné, zejména při snaze o nastavení celoobrazovkového režimu, zavoláním love.graphics.getModes() nebo love.graphics.checkMode() zjistit, zda je požadovaný grafický režim vůbec podporován (například na mnoha počítačích existují poměrně restriktivní omezení pro rozlišení celoobrazovkových režimů). V následující tabulce je vypsáno všech pět parametrů funkce love.graphics.setMode(), kterou budeme používat ve všech dnešních demonstračních příkladech:
Parametry funkce love.graphics.checkMode()
Název parametru | Význam |
---|---|
width | požadovaný počet pixelů na horizontální ose (buď se jedná o vnitřní šířku okna bez započítání jeho okrajů, nebo o horizontální rozlišení celoobrazovkového režimu) |
height | požadovaný počet pixelů na vertikální ose (buď se jedná o vnitřní výšku okna bez okrajů a horní lišty, nebo o vertikální rozlišení celoobrazovkového režimu) |
fullscreen | pravdivostní příznak určující, zda se má vykreslovat do okna či na celou obrazovku |
vsync | pravdivostní příznak určující, zda se má provádět synchronizace vykreslování s vertikálním návratem paprsku (vertikální zatmění); většinou je vhodné synchronizaci zapnout, aby se zabránilo nežádoucím „střihům“ ve scéně při přepínání předního a zadního bufferu |
fsaa | počet bufferů použitých při antialiasingu celé scény (antialiasing však lze zapnout lokálně, například při vykreslování geometrických tvarů, což bude patrné i ze screenshotů demonstračních příkladů), toto nastavení má význam především při práci s rastrovými obrázky |
Funkce love.graphics.getModes(), na rozdíl od výše popsané funkce love.graphics.setMode(), nevyžaduje při svém volání předání žádných parametrů. Výstupní hodnotou této funkce je asociativní pole obsahující seznam všech podporovaných celoobrazovkových grafických režimů. Každý grafický režim je v tomto poli představován jednou položkou, která je taktéž (jako prakticky každý složitější datový typ jazyka Lua) asociativním polem s dvojicí klíčů width a height obsahujících horizontální a vertikální rozlišení každého celoobrazovkového grafického režimu. Dnešní první demonstrační příklad slouží ke zjištění všech těchto režimů a uložení informací o nich do globální proměnné modes. Následně je otevřeno okno, načteno standardní písmo (viz následující kapitoly) a do okna je celý seznam režimů vypsán. Vertikální velikost okna je přepočtena na základě celkového počtu podporovaných režimů. Pokud by bylo okno příliš vysoké, postačuje snížit hodnotu konstanty fontHeight, čímž dojde ke zmenšení písma použitého pro výpis informací. Zdrojový kód prvního demonstračního příkladu, tj. obsah souboru nazvaného main.lua, je následující:
-----------------------------------------------------------------------
-- Seriál "Programovací jazyk Lua"
--
-- Zjištění všech podporovaných celoobrazovkových grafických režimů
-----------------------------------------------------------------------
-- asociativní pole, do kterého se seznam podporovaných režimů uloží
modes = nil
fontHeight = 20
-- callback funkce zavolaná při inicializaci aplikace
function load()
-- získat všechny podporované grafické režimy
modes = love.graphics.getModes()
-- načíst standardní font
local font = love.graphics.newFont(love.default_font, fontHeight)
-- vytvořit okno pro vykreslování
love.graphics.setMode(450, 100 + #modes * fontHeight, false, false, 0)
love.graphics.setFont(font)
end
-- callback funkce volaná průběžně ve chvíli, kdy je zapotřebí překreslit okno
function draw()
love.graphics.setColor(255, 255, 255)
love.graphics.draw("Gfx modes:", 10, 30)
-- iterovat přes všechny režimy uložené v asociativním poli "modes"
for i, mode in ipairs(modes) do
-- výpočet intenzity jedné barvové složky pro změnu barvy textu
local color = 255*(i-1)/#modes
love.graphics.setColor(255-color, 255, color)
-- formátování řetězce, který se vypíše do okna
local desc = string.format("gfx.mode %d: %dx%d", i, mode.width, mode.height)
love.graphics.draw(desc, 20, 50 + i * fontHeight)
end
love.graphics.setColor(255, 128, 128)
-- přepočet vertikálního umístění řetězce v závislosti na počtu grafických režimů
love.graphics.draw("Press escape to exit.", 30, 90 + #modes * fontHeight)
end
-- callback funkce volaná ve chvíli, kdy uživatel stlačí nějakou klávesu
function keypressed(key)
if key == love.key_escape then
love.system.exit()
end
end
-- finito
Obrázek 1: Screenshot prvního demonstračního příkladu, který byl spuštěn na počítači s grafickou kartou Intel 82852 GM. Tato karta sice podporuje i vyšší rozlišení, než zde zobrazených 1024×768 pixelů, ovšem nabídka všech reálně nabízených režimů je omezena taktéž maximálním rozlišením displeje, které je v tomto případě rovno právě zmíněným 1024×768 pixelům (jedná se o starší notebook s displejem 4:3).
3. Načtení externího fontu a vykreslení všech jeho znaků
Ve druhém demonstračním příkladu si ukážeme, jakým způsobem je možné načíst libovolný font ve formátu TrueType či OpenType (třetím podporovaným formátem je rastrový obrázek s vykreslenými znaky, jehož použití si ukážeme příště). Soubor s fontem by měl být umístěný ve stejném adresáři, v jakém se nachází samotný skript s hrou (soubor main.lua), popř. ho lze umístit i do archivu s hrou. Font se při inicializaci hry načte pomocí funkce love.graphics.newFont(). Tato funkce akceptuje buď jeden nebo dva parametry. Prvním parametrem je vždy název souboru s fontem, druhý (nepovinný) parametr udává velikost písma. Pokud není druhý parametr zadaný, doplní se automaticky velikost 12 bodů. Vzhledem k tomu, že ve formátech TrueType i OpenType jsou hranice znaků popsány parametricky, je možné písmo takřka libovolně zvětšovat a zmenšovat (navíc se může při zmenšování uplatnit takzvaný hinting zlepšující kresbu malých znaků). Po načtení fontu je možné pomocí funkce love.graphics.draw() provést výpis libovolného řetězce na obrazovku. Tato funkce je přetížená (viz následující kapitolu), přičemž v tomto demonstračním příkladu je použita její nejjednodušší podoba se třemi parametry: samotným řetězcem následovaným x-ovou a y-ovou souřadnicí začátku vykreslování. Následuje výpis zdrojového kódu druhého demonstračního příkladu:
-----------------------------------------------------------------------
-- Seriál "Programovací jazyk Lua"
--
-- Ukázka načtení fontu uloženého v externím souboru
-----------------------------------------------------------------------
-- callback funkce zavolaná při inicializaci aplikace
function load()
--local font = love.graphics.newFont(love.default_font, 20)
local font = love.graphics.newFont("DejaVuLGCSansMono.ttf", 20)
love.graphics.setMode(450, 300, false, false, 0)
love.graphics.setFont(font)
end
-- průměrná výška fontu
fontHeight = 30
-- callback funkce volaná průběžně ve chvíli, kdy je zapotřebí překreslit okno
function draw()
love.graphics.setColor(200, 255, 200)
-- vykreslit matici 32x8 znaků
-- (prvních 32 znaků však většinou font neobsahuje, popřípadě obsahuje
-- pouze samé prázdné obdélníky - podle typu fontu)
for y = 0, 7 do
local str = ""
for x = 0, 31 do
str = str .. string.char(x + y * 32)
end
-- vypsat celý řádek 32 znaků uložený v řetězci "str"
love.graphics.draw(str, 20, fontHeight + y * fontHeight)
end
love.graphics.setColor(255, 200, 255)
love.graphics.draw("Press escape to exit.", 30, 280)
end
-- callback funkce volaná ve chvíli, kdy uživatel stlačí nějakou klávesu
function keypressed(key)
if key == love.key_escape then
love.system.exit()
end
end
-- finito
Obrázek 2: Screenshot druhého demonstračního příkladu – výpis prvních 256 znaků fontu nazvaného DejaVu LGC Sans Mono. Prvních 32 znaků je zcela prázdných a znaky na pozicích 128–160 obsahují pouze obdélník, tj. pro praktické využití jsou také neobsazené. Systém LÖVE nedokáže ve své současné verzi vypsat znaky s jiným kódem než 0–255, což způsobuje problémy při práci s lokalizovanými aplikacemi. Jedno z možných řešení tohoto problému si ukážeme příště.
4. Natočení textu při jeho vykreslování
V předchozí kapitole jsme si řekli, že funkce love.graphics.draw() je přetížená, tj. akceptuje při svém volání různý počet i odlišné typy parametrů, které ovlivňují její chování. Pro vykreslování písma (řetězce znaků) je možné využít celkem čtyři podoby této funkce, které jsou vypsány v následující tabulce. Navíc jsou v tabulce pro úplnost vypsány i dvě podoby funkce love.graphics.drawf() (draw formatted string), pomocí níž lze řetězec zalomit do odstavce se zadanou šířkou (v pixelech).
Podoby funkce love.graphics.draw() při vykreslování písma
Volání funkce love.graphics.draw() | Význam |
---|---|
love.graphics.draw(string, x, y) | výpis řetězce na pozici [x,y] |
love.graphics.draw(string, x, y, angle) | výpis řetězce na pozici [x,y] s natočením angle stupňů |
love.graphics.draw(string, x, y, angle, s) | stejné, jako předchozí volání, ovšem text lze zvětšit či zmenšit podle hodnoty parametru s |
love.graphics.draw(string, x, y, angle, sx, sy) | hodnoty parametrů sx a sy ovlivňují měřítko v horizontální a vertikální ose |
love.graphics.drawf(string, x, y, limit) | výpis řetězce zalomeného do odstavce, jehož šířka je limit pixelů |
love.graphics.drawf(string, x, y, limit, align) | výpis řetězce zalomeného do odstavce, jehož šířka je limit pixelů, řádky v odstavci jsou zarovnány podle parametru align: love.align_left, love.align_center či love.align_right |
Ve třetím demonstračním příkladu je funkce love.graphics.draw() volána se čtveřicí parametrů: vlastním řetězcem, který se má vykreslit, souřadnicemi počátku vykreslovaného řetězce v okně a konečně úhlem natočení řetězce. Po spuštění příkladu se vykreslí 36 řetězců, každý s odlišným natočením i různým počátečním bodem. Úhel natočení se postupně zvyšuje tak, aby po ukončení vykreslování všech řetězců byla dokončena celá smyčka o 360° a počátek vykreslování řetězce se posouvá z bodu [30, 20] směrem vpravo dolů. Zdrojový text třetího demonstračního příkladu má tvar:
-----------------------------------------------------------------------
-- Seriál "Programovací jazyk Lua"
--
-- Ukázka načtení fontu uloženého v externím souboru a vykreslení
-- textu spolu s jeho natočením a změnou barvy
-----------------------------------------------------------------------
-- callback funkce zavolaná při inicializaci aplikace
function load()
local font = love.graphics.newFont("DejaVuLGCSansMono.ttf", 30)
love.graphics.setMode(450, 450, false, false, 0)
love.graphics.setFont(font)
end
-- callback funkce volaná průběžně ve chvíli, kdy je zapotřebí překreslit okno
function draw()
-- vypisovaný řetězec
str = "www.root.cz"
for i=0, 255, 7 do
-- nastavení barvy
love.graphics.setColor(i, 255, 255-i)
-- výpis textu s jeho natočením
local uhel = i * 360 / 255
love.graphics.draw(str, 30 + i, 1.5 * i + 20, uhel)
end
love.graphics.setColor(255, 200, 255)
love.graphics.draw("Press escape to exit.", 30, 430)
end
-- callback funkce volaná ve chvíli, kdy uživatel stlačí nějakou klávesu
function keypressed(key)
if key == love.key_escape then
love.system.exit()
end
end
-- finito
Obrázek 3: Screenshot třetího demonstračního příkladu – výpis řetězce s posunem počátku jeho vykreslení i úhlu natočení.
5. Funkce určené pro změnu stylu 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) 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. Styl čáry je ovlivněn šestnáctibitovou hodnotou představující bitový vzorek – bitová hodnota 1 znamená, že se ve vzorku nachází krátká čárka, nula naopak znamená mezeru. Použití si ukážeme příště v komplexnějším demonstračním příkladu, který bude všechny dostupné styly používat. Povolení antialiasingu funkcí love.graphics.setLineStyle(love.line_smooth) poměrně výrazným způsobem zlepšuje kvalitu výsledného obrázku, především u šikmých linek, kde díky 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 funkcí ovlivňujících způsob vykreslování je uveden v tabulce níže:
Název funkce | Význam |
---|---|
love.graphics.setColor() | nastavení barvy vykreslovaných objektů |
love.graphics.setColorMode() | určení, zda se má při vykreslování provádět modulace (násobení) barvy s pozadím |
love.graphics.setBlendMode() | povolení či zákaz míchání barev s pozadím při vykreslování |
love.graphics.setLineWidth() | šířka čáry při vykreslování |
love.graphics.setLineStyle() | povolení či zákaz antialiasingu při vykreslování úseček |
love.graphics.setLineStipple() | nastavení typu čáry podle zadaného bitového vzorku |
6. Vykreslení jednoduchého obrazce pomocí funkcí z knihovny love.graphics
Ve čtvrtém demonstračním příkladu, kde je výše zmíněný antialiasing při vykreslování úseček povolen (jedná se ostatně o implicitní nastavení), je ukázán způsob vykreslení úseček funkcí love.graphics.line() spolu se změnou jejich barvy pomocí funkce love.graphics.setColor(), které lze předat buď trojici barvových složek červená, zelená, modrá barvového režimu RGB, popřípadě lze k této trojici přidat i míru průhlednosti (viz následující kapitolu). Hodnoty všech tří barvových složek i hodnota průhlednosti musí ležet v rozsahu 0 až 255, kde nula značí nulovou intenzitu složky a hodnota 255 naopak maximální intenzitu. Černá barva je tedy zadána trojicí (0, 0, 0), čistá červená barva trojicí (255, 0, 0), barva žlutá trojicí (255, 255, 0) a bílá pomocí (255, 255, 255). Při vývoji aplikace je možné potřebné barevné odstíny získat například z dialogu pro míchání barev, který se nachází mj. i v programu GIMP či PaintBrush. Pomocí úseček je vytvořen objekt sestavený ze čtyřiceti rovnostranných trojúhelníků s proměnnou barvou stran. Následuje výpis zdrojového kódu tohoto demonstračního příkladu:
-----------------------------------------------------------------------
-- Seriál "Programovací jazyk Lua"
--
-- Kreslení pomocí funkcí z knihovny love.graphics
-----------------------------------------------------------------------
-- rozměry okna
width = 450
height = 450
-- poloměr vykreslovaného obrazce
radius = 200
-- callback funkce zavolaná při inicializaci aplikace
function 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
-- callback funkce volaná průběžně ve chvíli, kdy je zapotřebí překreslit okno
function 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.draw("Press escape to exit.", 30, 443)
end
-- callback funkce volaná ve chvíli, kdy uživatel stlačí nějakou klávesu
function keypressed(key)
if key == love.key_escape then
love.system.exit()
end
end
-- finito
Obrázek 4: Screenshot čtvrtého demonstračního příkladu – povšimněte si, že při vykreslování úseček byl použit antialiasing, takže jejich okraje vypadají poněkud rozmazaně a především se snížil (většinou) nežádoucí jagging šikmých čar.
7. Nastavení míchání barev a použití průhlednosti při vykreslování
V dnešním páté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 love.blending_normal a love.blending_additive a klávesami až 9 se nastavuje aktuální hodnota alfa, jež musí ležet mezi nulou a 255. V režimu love.blending_normal je 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 pokud je nastavený režim love.blending_additive, 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:
-----------------------------------------------------------------------
-- Seriál "Programovací jazyk Lua"
--
-- Kreslení pomocí 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 = love.blend_normal
-- konstanta pro směšování
blend_factor = 80
-- callback funkce zavolaná při inicializaci aplikace
function 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
-- callback funkce volaná průběžně ve chvíli, kdy je zapotřebí překreslit okno
function 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.draw("Press escape to exit.", 30, 443)
end
-- callback funkce volaná ve chvíli, kdy uživatel stlačí nějakou klávesu
function keypressed(key)
if key == love.key_escape then
love.system.exit()
end
if key == love.key_b then
setBlending()
end
if key >= love.key_0 and key<= love.key_9 then
setBlendFactor(key)
end
end
-- povolení či zákaz směšování barev po stisku klávesy "b"
function setBlending()
if blending == love.blend_normal then
blending = love.blend_additive
else
blending = love.blend_normal
end
end
-- nastavení hodnoty blend_factor po stisku kláves "0" až "9"
function setBlendFactor(key)
local code = key - love.key_0
blend_factor = code * 255 / 10
end
-- finito
Obrázek 5: Screenshot pátého demonstračního příkladu.
8. Základ animací
V předposledním demonstračním příkladu je ukázáno, jakým způsobem je možné vytvořit jednoduchou animaci založenou na postupné změně parametrů použitých při vykreslování obrazce složeného z úseček. V příkladu je použita callback funkce update() volaná automaticky systémem LÖVE v relativně pravidelných intervalech po cca 100 milisekundách, tj. 10× za sekundu. V callback funkci se nejprve volá funkce love.timer.sleep(), která zajišťuje pasivní čekání s možností přepnutí řízení na jiný proces, což představuje rozdíl oproti aktivnímu čekání v programové smyčce, které zbytečně zatěžuje mikroprocesor a blokuje běh dalších aplikací v systému. Po ukončení funkce love.timer.sleep() se zvýší hodnota globální proměnné offset, která je následně využita v průběhu překreslení celé scény v callback funkci draw(). Pokud by bylo zapotřebí animaci časovat přesněji, lze pro tento účel využít hodnotu parametru dt předávaného funkci update(), popř. je také možné použít časovač dostupný přes funkce nabízené knihovnou love.timer.
Obrázek 6: Šestý demonstrační příklad – začátek animace.
Zdrojový kód šestého demonstračního příkladu má tvar:
-----------------------------------------------------------------------
-- Seriál "Programovací jazyk Lua"
--
-- Jednoduchá animace objektu složeného z úseček
-----------------------------------------------------------------------
-- rozměry okna
width = 450
height = 450
-- poloměr objektu
radius = 200
-- průběžně zvyšovaná hodnota
offset = 0
-- callback funkce zavolaná při inicializaci aplikace
function load()
local font = love.graphics.newFont(love.default_font, 20)
love.graphics.setMode(width, height, false, false, 0)
love.graphics.setFont(font)
end
-- callback funkce volaná průběžně ve chvíli, kdy je zapotřebí překreslit okno
function draw()
-- nastavení režimu kreslení (míchání stávajícího obrázku s novým objektem)
love.graphics.setBlendMode(love.blend_additive)
love.graphics.setColor(255, 255, 255, 80)
-- vykreslení celého obrazce
for i=1, 90 do
for j=0, 3 do
local angle1 = math.rad(i + j * 90)
local angle2 = angle1 + math.rad(offset)
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.draw("Press escape to exit.", 30, 443)
end
-- callback funkce volaná po 10ms
function update(dt)
love.timer.sleep(100)
-- zvýší se hodnota globální proměnné "offset"
offset = offset + 1
end
-- callback funkce volaná ve chvíli, kdy uživatel stlačí nějakou klávesu
function keypressed(key)
if key == love.key_escape then
love.system.exit()
end
end
-- finito
Obrázek 7 a 8: Další snímky z animace prováděné šestým demonstračním příkladem
9. Načtení externího obrázku, vykreslení obrázku v animaci s jeho natočením
I dnešní poslední demonstrační příklad bude po svém spuštění zobrazovat jednoduchou animaci. Animovaný objekt je představován rastrovým obrázkem uloženým ve formátu PNG, který je do aplikace načtený funkcí love.graphics.newImage(). Po načtení je obrázek uložen do paměti grafického akcelerátoru ve formě textury, což mj. znamená, že s ním není možné provádět některé operace, například změnu barvy pixelu, čtení barev pixelů atd. Naopak je podporováno hardwarově urychlené vykreslení obrázků, které je interně provedeno namapováním obrázku (tj. rastrové textury) na obdélník, který je následně promítnut do vykreslované scény. S využitím systému LÖVE je vykreslení obrázku jednoduché, neboť se používá již výše zmíněná přetížená funkce love.graphics.draw(). Této funkci lze předat objekt představující obrázek, souřadnice obrázku (buď jeho středu nebo bodu zadaného metodou setCenter(x,y)) a volitelně také úhel natočení obrázku a změnu jeho měřítka. V demonstračním příkladu je poloha obrázku (tj. vlastního objektu) měněna na základě výpočtu, který simuluje trajektorii míčku v gravitačním poli (odrazy míčku jsou beze ztráty pohybové energie). S každým odrazem se také mění směr otáčení obrázku. Povšimněte si, že funkce love.graphics.newImage() ve skutečnosti vrací objekt s několika metodami, které lze volat, například image:getWidth().
Obrázek 9: Tato bitmapa je použita jako „sprite“ v sedmém demonstračním příkladu.
-----------------------------------------------------------------------
-- Seriál "Programovací jazyk Lua"
--
-- Ukázka načtení rastrového obrázku uloženého v externím souboru,
-- natočení obrázku při jeho vykreslování
-----------------------------------------------------------------------
-- rozměry okna
width = 450
height = 450
-- parametry obrázku
image = nil
x = 100
y = 100
-- posun obrázku a míra gravitace
dx = 1
dy = 1
gravity = 0.01
-- natočení obrázku a změna natočení (doprava, doleva)
angle = 0
rotation = 1
-- callback funkce zavolaná při inicializaci aplikace
function load()
-- načíst standardní font
local font = love.graphics.newFont(love.default_font, 20)
love.graphics.setFont(font)
-- načíst externí obrázek
image = love.graphics.newImage("gnome-globe.png")
love.graphics.setMode(width, height, false, false, 0)
end
-- callback funkce volaná průběžně ve chvíli, kdy je zapotřebí překreslit okno
function draw()
-- vykreslit natočený obrázek
love.graphics.draw(image, x + image:getWidth()/2, y + image:getHeight()/2, angle)
love.graphics.setColor(255, 200, 255, 255)
love.graphics.draw("Press escape to exit.", 30, 443)
end
-- průběžně volaná callback funkce
function update(dt)
-- posun obrázku
x = x + dx
y = y + dy
-- gravitace = zrychlení ve směru osy y
dy = dy + gravity
-- změna rotace obrázku
angle = angle + rotation
-- otestovat nárazy do okrajů okna
if x < 0 then
x = 0
dx = -dx
rotation = 1
end
if x > width - image:getWidth() then
x = width - image:getWidth()
dx = -dx
rotation = -1
end
-- "podlaha" a "strop"
if y < 0 then
y = 0
dy = -dy
end
if y > height - image:getHeight() then
y = height - image:getHeight()
dy = -dy
end
love.timer.sleep(10)
end
-- callback funkce volaná ve chvíli, kdy uživatel stlačí nějakou klávesu
function keypressed(key)
if key == love.key_escape then
love.system.exit()
end
end
-- finito
Obrázek 10: Jeden snímek animace prováděné sedmým demonstračním příkladem.