Došli jsme k poznání, že kód pro zachytávání stisků kláves:
document.addEventListener('keypress', function(event){ if(event.key=== 'w' || event.key=== 'W'){ zrychli(); } //dalsi klavesy });
není dokonalý - událost keypress je totiž ta chvíle, kdy je písmenko po zmáčknutí napsáno (např. do dokumentu). Proto se při držení klávesy vykoná jedna akce (například pohyb vlevo), chvíli se počká a pak se bude vykonávat opakovaně.
Proto by se v takto naprogramované hře dalo snadno podvádět - lze totiž počáteční prodlevu i kadenci opakování nastavit v Ovládacích panelech/klávesnice (mimochodem, dialog nastavení klávesnice - viz obrázek - se v aktuální verzi Windows 10 neliší od prastarých WindowsXP).
Budeme tedy sledovat jiné události - keydown a keyup - okamžik, kdy jde klávesa dolů (=je zamáčknuta) a kdy se vrací nahoru. Tyto události ovšem i pro dlouhé držení (např. chci dlouho zrychlovat autíčko) vykonají pouze jednou. Proto není žádoucí, aby volaly přímo akci pridej(). Místo toho si zkusíme představit, že máme tabulku, ve které je informace, zda je momentálně klávesa držena, či ne. Po zamáčknutí w by tabulka vypadala takto:
Klávesa | Proměnná | Zmáčknuta? |
---|---|---|
w | zmacknutoZrychli | true |
s | zmacknutoZpomal | false |
a | zmacknutoDoleva | false |
d | zmacknutoDoprava | false |
V kódu to bude (zde pouze pro klávesu w, zbytek doplňte sami :)) takto:
//deklarace globalni promenne zmacknutoZrychli = false; document.addEventListener('keydown', function(event){ //klavesa byla zmacknuta if(event.key=== 'w' || event.key=== 'W'){ zmacknutoZrychli=true; } //todo:dalsi klavesy }); document.addEventListener('keyup', function(event){ //klavesa byla odmacknuta if(event.key=== 'w' || event.key=== 'W'){ zmacknutoZrychli=false; } //todo:dalsi klavesy });
Po této úpravě samozřejmě nebude funkce zrychli() volána přímo zmáčknutím klávesy. Proto je potřeba tuto funkci volat v hlavním opakovaném cyklu (funkce render naplánovaná pomocí setInterval, resp. requestAnimationFrame)
//Funkce ktera bude volana znovu a znovu = herní loop function render(){ //Ovlivneni na zaklade stavu klaves if(zmacknutoZrychli){ zrychli(); } //todo: další akce //todo přepočítání x,y na základě rychlosti - viz další část textu //nastav aktualni stav do prvku document.getElementById('monster').style.top=y+"px"; document.getElementById('monster').style.left=x+"px"; } //Naplánování herního loopu každých 33ms setInterval(render,33);
Poznámka: aby byla hra skutečně stejně hratelná pro všechny, je třeba pamatovat, že 33ms není úplně spolehlivých - mezi jednotlivými snímky může uplynout i víc času. Jako námět pro rozšíření bychom tedy mohli měřit dobu skutečně uplynulou od minulého snímku a přenásobovat tím přírustky k pozici (= jak daleko se auto pohne)
Dosud jsme autíčko pohybovali pouze ve chvíli zmáčknutí klávesy, a to jeho maximální rychlostí. Jak to ovšem funguje s reálnými pohybujícími se předměty? Rychlost se nezvyšuje skokově. Dokud držíme nohu na plynu, rychlost roste. Když nohu z plynu sundáme (nebo začneme brzdit), rychlost se začne snižovat (až klesne k nule).
Z programátorského hlediska budeme potřebovat v naší hře zavést novou proměnnou (případně dvě, pro každou ze souřadnic x,y) - rychlost. Měl by platit vzoreček:
polohaX_nova=polohaX_stara + rychlostX * uplynulyCas
zjednodušeně (spoléháme se na správnost časování intervalem):
polohaX=polohaX + rychlostX
což se dá napsat i způsobem:
polohaX+=rychlostX
Toto se odehraje v každém výpočtu snímku (funkce render). Rychlost není v km/h či m/s jak jsme zvyklí z reálného života - v našem kontextu má zřejmě jednotku „uražené pixely za dobu mezi dvěma snímky“
Pro ještě lepší dojem z autíčka zkuste rychlost ovlivňovat i přirozeným zpomalováním (aerodynamickým odporem, třením pneumatik). Pozor, nestačí prostě nějakou hodnotu od rychlosti odečítat - rychlost může být i záporná = v opačném směru! Musíte udělat podmínku, která rychlost snižuje, pokud je rychlost větší než 0 a zvyšuje, pokud je menší než 0.