VI. díl Codemas

Ahoj, vítej u dalšího dílu vánočního kódování. Už se umíme hýbat, nenarážíme do zdí a ani neodcházíme pryč z herního pole – paráda! Pojďme si do hry dnes přidat další předměty, které pan Perníček na své cestě posbírá.

Předmětů je celkem 6 a každý je reprezentován nějakým obrázkem ve složce images. Budeme muset tedy vytvořit šest dalších proměnných pro 6 obrázků, které si přidáme na začátek kódu k našim již vytvořeným proměnným.

let wall = new Image() wall.src = "images/zed.png" let hero = new Image() hero.src = "images/pernicek_dolu.png" let darek2 = new Image() darek2.src = "images/darek2.png" let darek3 = new Image() darek3.src = "images/darek3.png" let hulka = new Image() hulka.src = "images/hulka.png" let hvezda = new Image() hvezda.src = "images/hvezda.png" let kapr = new Image() kapr.src = "images/kapr.png" let ponozky = new Image() ponozky.src = "images/ponozky.png"

Kód se opakuje, pouze vytváříme 6 unikátních proměnných pro předměty, stejně jako pro postavu nebo zeď. Teď se ale musíme zamyslet, jak tyto předměty budeme vykreslovat do hry. Určitě bude mít každý z nich své souřadnice x a y. Předmětů je celkem 6, tudíž můžeme využít nějaké pole a obdobně jako u generování herní plochy budeme toto pole postupně pomocí cyklu procházet a předměty vykreslovat. Pokud už si tak čistě nepamatuješ, jak se pole a cykly využívají, mrkni na 2. díl a 3. díl, kde je to podrobně popsané. :)

Pojďme si vytvořit pole s názvem items:

let items = []

Nyní je potřeba naplnit pole předměty s jejich pozicí x a y. Vytvoříme si tedy herní objekty. Na toto je dobré si taky vytvořit samostatnou funkci, kterou si nazveme createitems:

function createitems() { }

V rámci této funkce budeme plnit pole items předměty. Pro tuto akci využijeme další funkci push, kterou můžeme na tom poli zavolat:

items.push({ x: 1, y: 1, imageObject: darek2 })

Push najdeme například u dveří a je to signál, že na dveře máme zatlačit, abychom je otevřeli. Tady budeme do pole “tlačit” herní objekty. Každý objekt bude mít souřadnice x a y a zároveň i funkci imageObject, kam uložíme proměnnou, ve které se skrývá obrázek. Tímto způsobem do pole vložíme všechny předměty a funkce bude vypadat následovně:

function createitems() { items.push({ x: 1, y: 1, imageObject: darek2 }) items.push({ x: 1, y: 15, imageObject: darek3 }) items.push({ x: 14, y: 12, imageObject: hulka }) items.push({ x: 15, y: 18, imageObject: hvezda }) items.push({ x: 5, y: 11, imageObject: kapr }) items.push({ x: 15, y: 1, imageObject: ponozky }) }

Funkci máme hotovou, zbývají nám momentálně jen 2 věci – někde tuto funkci zavolat a zajistit vykreslení jednotlivých předmětů. Začneme voláním funkce. Naplnění pole by mělo proběhnout jen jednou a ideálně hned na startu hry. Problémem je, že nyní se nám opakuje stále funkce draw. Proto si vytvoříme ještě jednu funkci s názvem startGame, která bude zodpovědná za prvotní nastavení hry:

function startGame() { createitems() draw() }

Funkce v prvé řadě naplní pole předměty a zavolá funkci draw, která poběží zbytek hry. Z tohoto důvodu musíme trochu pozměnit náš poslouchač události, který po načtení stránky automaticky spouští funkci draw.

window.addEventListener("load", startGame)

Nyní by se měla automaticky spouštět startGame. A teď ještě zmiňované vykreslování – tady to nebudeme mít složité, jednoduše vložíme do naší funkce generateBoard další cyklus:

for (let i = 0; i < items.length; i++) { ctx.drawImage( items[i].imageObject, items[i].x * blockSize, items[i].y * blockSize, blockSize, blockSize ) }

Tento cyklus bude postupně procházet pole a pomocí funkce drawImage ho vykreslovat do bludiště. Funkce generateBoard po úpravě vypadá 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) } } } for (let i = 0; i < items.length; i++) { ctx.drawImage( items[i].imageObject, items[i].x * blockSize, items[i].y * blockSize, blockSize, blockSize ) } }

Sbírání předmětů

Pro tuto akci si vytvoříme další funkci a bude se jmenovat collect.

function collect() { }

A teď se budeme muset zamyslet, jak nastavit algoritmus pro sbírání. Víme, že předmět by se měl sebrat ve chvíli, kdy se postavička bude nacházet na jeho pozici, tudíž musíme vymyslet nějakou podmínku. A abychom mohli kontrolovat všechny předměty, musíme celé pole items procházet a až v cyklu kontrolovat jejich sbírání. Kód tedy bude vypadat takto:

function collect() { for (let i = 0; i < items.length; i++) { console.log(player.x + " " + items[i].x); if (player.x == items[i].x && player.y == items[i].y) { items.splice(i, 1) increaseScore() } } }

Procházíme celé pole a v podmínce kontrolujeme, jestli se naše postava nachází na stejném místě jako předmět. Pokud ano, využijeme funkci splice, která smaže daný předmět z pole – už se nebude zobrazovat. Funkce splice přijímá 2 parametry – index v poli a počet předmětů, které chceme smazat. Jako index uvádíme i, tedy řídící proměnnou cyklu, a mažeme jeden předmět. Nyní musíme funkci opět někde zavolat. Dává smysl, abychom ji zavolali ve funkci draw. A je dobré ji zavolat až po uskutečnění pohybu – tedy po zavolání funkce movement. Kód pak bude vypadat následovně:

function draw() { ctx.clearRect(player.x * blockSize, player.y * blockSize, blockSize, blockSize) generateBoard() movement() collect() ctx.drawImage(hero, player.x * blockSize, player.y * blockSize, blockSize, blockSize) }

Pokud teď hru spustíme a zkusíme si sebrat nějaký předmět, tak to funguje, dobrá práce!

Skóre

Dnes uděláme ještě jednu důležitou funkcionalitu, a to přidávání skóre. Abychom mohli přidávat skóre a propisovat ho do stránky, musíme JavaScript propojit s elementem, který skóre zobrazuje. Vytvořme si nový herní objekt s názvem game, kde si uložíme odkaz na HTML element, do kterého budeme vkládat skóre. Vytvoříme si i vlastnost score, ve které budeme uchovávat aktuální skóre.

let game = { scoreElement: document.getElementById("score"), score: 0 }

Přidáme si další funkci s názvem increaseScore, ve které zvýšíme hodnotu score a zároveň skóre vypíšeme.

function increaseScore() { game.score++ game.scoreElement.textContent = `${game.score}/6` }

Score++ jistě poznáváme – vzpomeň si na inkrement v cyklech. Zvyšujeme tím hodnotu proměnné o 1. Abychom skóre vypsali, využijeme funkce textContent. Ta nám umožňuje změnit textový obsah elementu. My do něj vložíme naši proměnnou score. Nakonec funkci increaseScore zavoláme ve funkci collect:

function collect() { for (let i = 0; i < items.length; i++) { if (player.x == items[i].x && player.y == items[i].y) { items.splice(i, 1) increaseScore() } } }

Dobrovolný úkol

Do hry jsme si přidali 6 předmětů. Ve složce s obrázky se nachází jeden další - rukavice.png. Zkus si tento předmět přidat do hry a nezapomeň změnit skóre ze 6 na 7. Až to budeš mít hotové, udělej screenshot obrazovky a pošli nám ho do komentářů pod příspěvek na Facebooku. :)

Na závěr

Dnešní díl byl trochu delší, na druhou stranu jsme naši hru posunuli o velký kus dál. Vygenerovali jsme všechny potřebné předměty a už je umíme i sbírat.

Naše hra je téměř hotová, zbývá nám jen doplnit časovač a naprogramovat konec hry. Vrhneme se na to v následujících dvou dílech, kdy hru dokončíme. Kód z dnešní lekce najdeš zde.

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