III. díl Codemas
Ahoj, další díl je tady. Dnes se společně mrkneme na funkce a cykly, zároveň si díky novým znalostem vygenerujeme celou herní plochu. Jdeme na to!
Funkce
Možná jsi o funkcích už slyšel/a, ale krátké opakování určitě neuškodí. Funkce je skupina příkazů, kterou jsme nějak pojmenovali a kterou můžeme v programu volat opakovaně. V programování bychom se měli snažit držet principu DRY - Don't Repeat Yourself, neboli neopakuj se.
Provádíme-li v programu stejnou věc několikrát, je tento kousek kódu ideálním kandidátem na vytvoření funkce. Z našeho opakovaného kódu vytvoříme funkci, kterou pak z různých míst programu jenom voláme.
Funkce nám tak umožňují zjednodušit a zpřehlednit kód. Jsou prostě skvělé jako vánoční dárky! No, možná ne úplně, ale jsou tomu blízko. :)
Funkci začneme vždy slovem function, za kterým následuje jméno funkce (jak si my funkci pojmenujeme). Za jménem jsou kulaté závorky, ve kterých jsou tzv. parametry funkce. Pokud funkce parametry nemá, zůstanou závorky prázdné (ale být tam musí). A pak už jen do složených závorek {…}, které následují za klasickými závorkami, napíšeme příkazy, které chceme ve funkci mít.
Když chceme vykonat příkazy uvnitř funkce, stačí funkci zavolat jejím jménem s kulatými závorkami na konci. Do kulatých závorek se píšou parametry (víc později) nebo nic.
Pojďme se teď vrhnout na vygenerování plochy.
Základní kostra funkce generateBoard vypadá takto:
function generateBoard() { // zde budou příkazy, které chceme vykonat po zavolání funkce }
Co do ní ale napíšeme? Pokud jsme správně pochopili princip, musíme postupně procházet celé to velké pole. Ručně to ale rozhodně dělat nebudeme, použijeme něco, čemu se říká cyklus. Cyklus nám dokáže opakovat určité bloky kódu, když je to potřeba. Máme několik různých cyklů (např. for, while, do-while), my v naší hře využijeme primárně cyklus for.
Takový cyklus vypadá následovně:
for (let i = 0; i < 10; i++) { // zde budou příkazy, které chceme opakovat v cyklu }
Začneme klíčovým slovem for a v klasických závorkách cyklus nastavíme. Nastavení máme rozdělené do tří částí (oddělují se středníkem):
- let i = 0 – vytváříme řídící proměnnou i
- i < 10 – definujeme podmínku, do kdy se cyklus bude opakovat (v tomto případě, dokud bude i menší jak 10)
- i++ – to je tzv. inkrement, aby se nám z cyklu nestal nekonečný cyklus, potřebujeme měnit hodnotu řídící proměnné – i++ nám zajistí, že se po každém opakování zvýší hodnota proměnné i o 1.
Vše to, co je mezi složenými závorkami, se bude opakovat. Jakmile se projedou všechny příkazy, program přeskočí zpět ke kulatým závorkám, zkontroluje, jestli hodnota řídící proměnné splňuje podmínku a zvýší hodnotu řídící proměnné o 1. Takhle se cyklus bude opakovat, dokud nebude splněna podmínka.
Pojďme si do kódu přidat náš cyklus, který bude procházet pole board:
for (let y = 0; y < board.length; y++) { }
První část cyklu je nám známa, nastavíme si řídící proměnnou y s počáteční hodnotou 0. V podmínce říkáme, dokud je y menší než board.length. Schválně jsem v sekci o polích mluvil i o jejich délce – přesně v takových případech se nám to hodí, jelikož board.length nám vrátí hodnotu délky pole board. Někdo možná namítne, že známe velikost pole board – tedy 20. Každý program by měl být ale co nejvíce obecný a připravený na změny, pokud bychom změnili velikost pole na 21, musel bychom v tu chvíli myslet na to, abychom to hodnotu všude změnili, což není v lidských silách, proto se snaž vždy psát obecné programy a myslet na tyto případy. První cyklus máme, ale jistě ti došlo, že sice procházíme pole, ale už neprocházíme ta pole, která se nacházejí na těch indexech. Proto musíme vložit do cyklu další cyklus, který se o to postará.
for (let y = 0; y < board.length; y++) { for (let x = 0; x < board[y].length; x++) { } }
Druhý cyklus je dost podobný, ale je tam pro nás trochu neznámý zápis – board[y].length. Znamená to, že board[y] si vytáhne data z toho konkrétního indexu, tedy další pole. Tyto cykly nám zajistí, že se projde každý chlíveček v každém poli a my budeme schopni vykreslit mapu. Nezbývá nic jiného než vložit do druhého cyklu podmínku, která bude říkat – pokud bude v daném chlívečku 1, pak vykresli zeď, pokud bude v chlívečku 0, nech blok prázdný. Pro porovnání využijeme operátor === (rovnost).
for (let y = 0; y < board.length; y++) { for (let x = 0; x < board[y].length; x++) { if (board[y][x] === 1) { tx.drawImage(wall, x * blockSize, y * blockSize, blockSize, blockSize) } } }
Klasickou podmínku definujeme pomocí klíčového slova if a do závorek napíšeme logický výraz, ze kterého vzejde pravda nebo nepravda. V podmínce reagujeme pouze na 1, protože 0 nás nijak nezajímá (nestane se při ní nic).
Naše funkce generateBoard by měla vypadat následovně:
function generateBoard() { for (let y = 0; y < board.length; y++) { for (let x = 0; x < board[y].length; x++) { if (board[y][x] === 1) { ctx.drawImage(wall, x * blockSize, y * blockSize, blockSize, blockSize) } } } }
Pro vykreslení použijeme funkci drawImage. Jako parametr přijímá obrázek, pozici na ose x, pozici na ose y, výšku a šířku (přesně v tomto pořadí a oddělené čárkou).
Nyní už nám zbývá jen celou funkci zavolat. Na to taky půjdeme chytře. Budeme chtít tuto funkci zavolat ve chvíli, kdy se načte stránka. JavaScript na tuto a podobné události dokáže velice hezky reagovat, tzv. poslouchat. K „poslechu“ využijeme tzv. Poslouchač událostí.
Poslouchač událostí
Poslouchač událostí bude čekat (poslouchat), zda k události náhodou nedošlo a pokud ano, tak zavolá funkci, o které jsme mu řekli, že je tzv. ovladač události (event handler).
Posluchače události přidáváme pomocí: objekt.addEventListener('událost', ovladač).
- Objekt je objekt, ke kterému chceme ovladač události připojit.
- Událost je textový řetězec s názvem události, na kterou se má čekat.
- Ovladač je název funkce, která se spustí, když k události dojde.
Vypadá to složitě, ale zas tak složité to není. Ukažme si to na konkrétním příkladu, a to na našem kódu z minula:
window.addEventListener("load", generateBoard)
Tímto řádkem jsme JavaScriptu řekli, že objekt window (okno prohlížeče) bude čekat, dokud v něm nebude všechno načtené (událost load). Když se načte kompletní obsah stránky včetně všech obrázků, fontů apod., tak dojde k události a zavolá se funkce generateBoard - tedy ta funkce, která je zodpovědná za aktualizaci veškerého dění ve hře.
Na závěr
Na světě máme krásné bludiště! Dobrá práce! 😊
Celý kód z dneška najdeš zde. Doufám, že se ti to líbilo a uvidíme se zase u dalšího dílu.
Pokud s něčím bojuješ, neboj se nám napsat pod příspěvek na naší facebookové události, rádi ti pomůžeme. K dotazu ideálně pošli i URL adresu s odkazem na tvůj projekt. :)
Začala sis pohrávat s myšlenkou, že bys chtěla prozkoumat IT trochu víc? Podívej se na nabídku kurzů od Czechitas, kteří se zaměřují na vzdělávání převážně žen a dětí v IT. Jak si vybrat vhodný kurz zjistíš zde.
Michal z Czechitas