Zůstaň doma a naprogramuj si hru 6

Máme za sebou generování mapy, dnes se vrhneme na generování hlavní postavy. Spoustu věcí už znáš ze včerejška, a tak to dnes nebude tak dlouhé. 😊

Vytvoření herního objektu

Hráče si v JavaScriptu vydefinujeme jako herní objekt. Ten vypadá následovně:

let player = {
    x: 8,
    y: 1
};

Herní objekt je datová struktura, ve které budeme uchovávat údaje o našem hráči. Nám stačí uchovávat dvě informace, pozici x a y na naší herní ploše. Jinak lze uchovávat libovolný počet informací, ty musejí být vždy oddělené čárkou.

Jelikož budeme postavu vykreslovat jako obrázek, musíme si založit proměnnou, do které obrázek uložíme.

let hero = new Image();
hero.src = "images/down.png";

Připadá ti ten kód povědomý? Včera jsme takto zakládali proměnnou pro zeď. Máme herní objekt a obrázek a jak už jsem zmiňoval pár řádků nahoru, budeme muset postavu vykreslit.

Vykreslení hráče

Vytvoříme si novou funkci s názvem draw.

function draw() {

}

Tato funkce nám bude sloužit nejen k vykreslení hráče, ale bude jakousi hlavní metodou naší hry. Přidáme si do funkce příkaz nutný k vykreslení postavy:

ctx.drawImage(hero,player.x * blockSize, player.y * blockSize, blockSize, blockSize);

Samotnou funkci jsme ještě nezavolali, proto se nám po spuštění žádný hráč nezobrazí. Včera jsme si na konci dne přidali do kódu poslouchač události, který čekal na načtení stránky. Jakmile se načte stránka, zavolá se funkce generateBoard. Pojďme toto trošku upravit, funkci generateBoard zavoláme ve funkci draw a funkce draw se nám zavolá při načtení stránky. Upravený kód vypadá následovně:

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

//poslouchač událostí, čekáme (posloucháme) na načtení stránky, pak zavoláme funkci generateBoard
window.addEventListener("load", draw);

Pokud nyní hru zapneme, vykreslí se nám do ní i hlavní postava.

Pohyb hlavní postavy

Dnes ještě uděláme jednu důležitou věc a to pohyb postavy. 😊 Naše hra bude reagovat na stisk klávesy. Budeme využívat šipky. Přidejme si na konec skriptu následující kód:

document.body.addEventListener("keydown", function(e) {
    keys[e.keyCode] = true;

    draw();
});

document.body.addEventListener("keyup", function(e) {
    keys[e.keyCode] = false;

    draw();
});

Na tělo celého dokumentu umístíme dva poslouchače události keydown a keyup. Keydown se zaktivuje ve chvíli, kdy stiskneme nebo budeme držet libovolnou klávesu, keyup pak zareaguje při uvolnění klávesy. Jedna bez druhého v našem případě nemůže fungovat. Každá klávesa má svůj kód, takže pokud budeš nějakou klávesu držet nebo ji stiskneš, tak se v poli keys označí jako true. Pokud ji pustíš, označí se jako false. Aby nám vše fungovalo tak jak má, musíme vytvořit novou proměnnou keys, do které uložíme prázdné pole. Na začátek našeho skriptu mezi proměnné vlož tento řádek kódu:

let keys = [];

Samotné poslouchače v sobě volají funkci draw a to z jednoduchého důvodu, při každém stisku chceme aktualizovat pozici i stav hry.

Nyní si vytvoříme funkci, která se bude čistě starat o pohyb hlavní postavy a nazveme si ji movement.

function movement() {
    if (keys[39]) {
        // šipka doprava
        hero.src = "images/right.png";
        player.x++;
    }

    if (keys[37]) {
        // šipka doleva
        hero.src = "images/left.png";
        player.x--;
    }

    if (keys[38]) {
        // šipka nahoru
        hero.src = "images/up.png";
        player.y--;
    }

    if (keys[40]) {
        // šipka dolů
        hero.src = "images/down.png";
        player.y++;
    }
}

V této funkci jsou 4 podmínky. Každá podmínka se kouká do pole keys a zjišťuje, jestli se stiskla šipka doprava, doleva, nahoru nebo dolů. V každé podmínce se i překreslí obrázek hlavní postavy podle směru, kterým jdeme. V každé podmínce potom měníme i pozici na ose x nebo y. Funkci zavoláme ve funkci draw.

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

Když si zkusíme nyní hru spustit a pohnout se libovolným směrem, tak pohyb funguje, má jen 2 drobnosti, na kterých musíme zapracovat. Zatím jsme nikde nedefinovali „náraz do zdi“, takže se hlavní postava může pohybovat libovolně po bludišti (dokonce i za něj). Může se ti stát, že postava při stisku klávesy zmizí a při dalším se zase objeví, je to způsobené canvasem jako takovým a bohužel s tím nic neuděláme.

A druhá věc, kterou dnes vyřešíme, naše postava zůstává vykreslená i na polích, kde se nenacházíme a to určitě není dobře.

Poznámka 2020 03 25 194215

Toto vyřešíme funkcí clearRect, kterou přidáme na začátek funkce draw.

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

Tato funkce nám zajistí, že se hlavní postava na začátku funkce smaže ze své konkrétní pozice a vykreslí se na nové pozici díky funkci drawImage na konci. Celý kód z dnešní hodiny najdeš zde.

Na závěr

Hurááá, hýbeme se! :D A naše hra pomalu získává finální podobu. Dobrá práce!

Další den

Předcházející den