Lekce 7 - hra¤
Cílem je vytvořit hru "vyhýbání se překážkám", kdy hráč dole se snaží nenarazit do zábran. Ovládání pomocí tlačítek A a B, viz simulátor:
Řešení
Sprites¤
Při vytváření hry budeme používat "herní engine" zabudovaný do micro:bitu, je v zelených blocích v pokročilé sekci. Tento engine podporuje tzv. sprites - herní prvky, které jsou velké jeden pixel (jedna LED na displeji), a mají vlastnosti:
- Pozice (x a y)
- Směr (orientace, není vidět na displeji, ale funkce
pusuň sprite
posouvá tímto směrem) - Jas
- Blikání
Všechny tyto vlastnosti jsou ve sprite takzvaně zapouzdřené, a "cestují" vždy spolu. Sprite je nový datový typ, lze je tedy uložit do proměnných (a seznamů) a všechny tyto vlastnosti jsou v dané proměnné uložené dohromady.
Sprites se vykresulí na displej automaticky, není třeba volat žádné leds.plot
ani nic podobného, stačí spritu nastavit pozici, a on se na ní bude vykreslovat.
Naopak, dokud běží hra, nelze na displej kreslit jinak než pomocí spritu - pokud toto potřebujete, je třeba engine zastavit pomocí game.pause
bloku.
Hráč¤
Hráč bude jeden ze spritů. Bude neustále na Y pozici 4 (úplně dole), a poblikávat. Ve výchozím stavu bude uprostřed, tedy na X pozici 2. Bude také blikat, aby byl odlišený od překážek.
let hrac: game.LedSprite = null
hrac = game.createSprite(2, 4)
hrac.set(LedSpriteProperty.Blink, 300)
Pohyb hráče je s game engine snadný, stačí přidat dva handlery pro události tlačítek:
let hrac: game.LedSprite = null
input.onButtonPressed(Button.A, function () {
hrac.change(LedSpriteProperty.X, -1)
})
input.onButtonPressed(Button.B, function () {
hrac.change(LedSpriteProperty.X, 1)
})
Překážky¤
Překázky budou vodorovné čáry s dírami, každá tvořena několika sprity (pamatujte, sprite je vždy jen jeden pixel).
Přidávání překážek¤
Vytvoříme si funkci, která přidává novou překážku:
- Překážka bude vždy úplně nahoře,
y = 0
- Překážka bude široká na celý displej, ale bude někde náhodně mít díru o velikosti 2.
- Sprity překážky naházíme do pole (seznamu), abychom je mohli později posouvat.
Na začátku programu jednu překážku přidáme.
let holeX = 0
let hrac: game.LedSprite = null
let prekazky: game.LedSprite[] = []
prekazky = []
hrac = game.createSprite(2, 4)
hrac.set(LedSpriteProperty.Blink, 300)
pridejPrekazku()
function pridejPrekazku () {
holeX = randint(0, 3)
for (let index = 0; index <= 4; index++) {
if (index < holeX || index > holeX + 1) {
prekazky.push(game.createSprite(index, 0))
}
}
}
Pohyb překážek¤
Překážky se musí pohybovat směrem dolů, všem spritům v seznamu prekazky
tedy musíme přičítat k y
souřadnici jedničku, periodicky.
Současně, pokud se překážka dotkne hráče, hra skoční.
let hrac: game.LedSprite = null
let prekazky: game.LedSprite[] = []
function presunPrekazky () {
for (let pr of prekazky) {
pr.change(LedSpriteProperty.Y, 1)
if (pr.isTouching(hrac)) {
game.gameOver()
break;
}
}
}
basic.forever(function () {
basic.pause(1000)
presunPrekazky()
})
Mizení překážek¤
Další krok je mizení překážek, které dosáhnou spodku displeje. To přidáme do presunPrekazky
na začátek.
Je třeba jednak odstranit sprite ze seznamu prekazky
, ale také smazat samotný sprite z herního engine.
let hrac: game.LedSprite = null
let prekazky: game.LedSprite[] = []
function presunPrekazky () {
while (prekazky.length > 0 && prekazky[0].get(LedSpriteProperty.Y) == 4) {
prekazky.shift().delete()
}
for (let pr of prekazky) {
pr.change(LedSpriteProperty.Y, 1)
if (pr.isTouching(hrac)) {
game.gameOver()
break;
}
}
}
Generování nových překážek, skóre¤
Aby hra byla hrou, musíme přidávat nové překážky. To uděláme rozšířením forever
bloku, který už máme a který periodicky volá funkci presunPrekazky
.
Přibude do něj podmínka, která ověří, že poslední překážka je alespoň 3 od vršku displeje, a pokud ano, tak vytvoří novou překážku.
Na konec také přidáme zvyšování nahraného skóre - zvýšení skóre v tomto bloku odpovídá počítání řádků, které hráč přežil. Skóre je vidět po konci hry, až hráč do něčeho narazí.
let prekazky: game.LedSprite[] = []
function presunPrekazky () {
// ...
}
function pridejPrekazku () {
// ...
}
basic.forever(function () {
basic.pause(1000)
presunPrekazky()
if (prekazky.length == 0 || prekazky[prekazky.length - 1].get(LedSpriteProperty.Y) >= 3) {
pridejPrekazku()
}
game.setScore(game.score() + 1)
})
Zrychlování hry¤
Posledním vylepšením je postupné zrychlování, aby hra byla težší. Toho docílíme tak, že sekunduvou prodlevu nahradíme hodnotou z proměnné, kterou navíc budeme periodicky změnšovat na 98% původní hodnoty.
let prodlevaTicku = 1000
basic.forever(function () {
basic.pause(2000)
prodlevaTicku = prodlevaTicku * 0.98
})
let prekazky: game.LedSprite[] = []
function presunPrekazky () {
// ...
}
function pridejPrekazku () {
// ...
}
basic.forever(function () {
basic.pause(prodlevaTicku)
presunPrekazky()
if (prekazky.length == 0 || prekazky[prekazky.length - 1].get(LedSpriteProperty.Y) >= 3) {
pridejPrekazku()
}
game.setScore(game.score() + 1)
})