Autor Zpráva
KryVosa
Profil *
Mám takový problém. Mám jednoduchou HTML5 <canvas> kostičkovanou hru, přičemž každá kostička má vlastní vlastnosti:
gameGrid[X][Y].type = 
gameGrid[X][Y].building
gameGrid[X][Y].solider
gameGrid[X][Y].select
Všechny tyhle vlastnosti se v průběhu hry mění, v závislosti na určité akce, a o jejich vykreslení se stará takováto funkce:
function mainCAnim(X,Y){
mainCD.drawImage(img[gameGrid[X][Y].type],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].building],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].selected],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].solider],X*15,Y*15);
if(X==63){X=0;Y++}else X++;
if(X==63 && Y==32){X=0;Y=0};
setTimeout("mainCAnim("+X+","+Y+")",0);}
To mainCD.drawImage je vykreslení všech těchto vlastností na canvas.
Nevíte jak tuto funkci urychlit? Dát pryč setTimeout() jsem zkoušel, ale po chvíli mi to nekonečnou funkci ukončí.
1Pupik1989
Profil
Použij requestAnimationFrame nebo setTimeout-u nastav opakování na 1000/60. 1000 snímků za sekundu je zbytečné.
_es
Profil
KryVosa:
Jednoduché urýchlenie môže byť: Časté potíže, zajímavosti a poučné debaty » Nepoužívejte eval, ani jeho obdoby. Náročnosť bude spočívať asi hlavne v spôsobe vykresľovania, menej by mohlo záležať na iných veciach.
Chamurappi
Profil
Reaguji na 1Pupika1989:
1000 snímků za sekundu je zbytečné.
Má tam požadovanou prodlevu nulu milisekund, takže teoreticky by mohl mít nekonečno snímků za sekundu. Méně teoreticky ale minimální prodleva bývá 4 ms a prakticky bývá ještě větší v závislosti na tom, jak se systému daří.


Reaguji na KryVosu:
Proč nastavuješ pro každé políčko vlastní časovací smyčku? Proč nemáš jednu, která by řídila celé hrací pole najednou?

Nevíte jak tuto funkci urychlit?
Pokud existuje konečné rozumné množství kombinací typů, budov a vojáků, můžeš si všechny stavy předgenerovat na začátku hry do jiného <canvas>u a pak vykreslovat z něj.
1Pupik1989
Profil
Chamurappi: Nekonečno neni reálné. setTimeoutm s časem 0 má vždy prodlevu větší než obyčejný kód.
Leč javascript to vyhodnotí jako nekonečnou smyčku. Za prodleva na smyčku může být 60s, ale syntaktický analyzér to vyhodnotí jako nekonečné volání ala "maximum call stack exceed".
Radek9
Profil
1Pupik1989:
Nekonečno neni reálné.
On ale zmiňoval, že by mohl mít teoreticky nekonečno snímků. Což při zpoždění 0 ms dává smysl.

Leč javascript to vyhodnotí jako nekonečnou smyčku.
Nevyhodnotí, protože i timeout se zpožděním 0 ms se spouští asynchronně. Call stack tedy nepřeteče, protože se to volá odjinud a vždy postupně.
1Pupik1989
Profil
On ale zmiňoval, že by mohl mít
teoreticky nekonečno snímků. Což při
zpoždění 0 ms dává smysl.

Nedává, protože 0ms je prostě okamžitě. Javascript to zkrouhne a cyklus ořeže. Tudíž tam zustane jen vnitřek funkce, kterou vyhodnotí jako nekonečnou smyčku.

Zobrazení kódu je jedna věc, ale zpracování je jiná. Stojím si za tím na 100%, zkuste mě vyvést z omylu.
_es
Profil
[#7] 1Pupik1989:
Funkcia setTimeout funguje tak, že sa priradená funkcia zavolá až po príkazoch, ktoré sa majú vykonať za setTimeout.
Joker
Profil
1Pupik1989:
Nedává, protože 0ms je prostě okamžitě. Javascript to zkrouhne a cyklus ořeže.

Stojím si za tím na 100%, zkuste mě vyvést z omylu.

Čili tvrzení zní, že setTimeout(foo, 0); JavaScript při zpracování převede na foo(); tzn. ty dvě konstrukce jsou ekvivalentní, ano?
V tom případě tvrdím, že to není pravda.
Já tvrdím, že setTimeout(foo, 0) je pořád timeout a, přesně jak píše Chamurappi, volání se v praxi načasuje na další timeout, který ve skutečnosti nastane za delší čas, než 0ms.
Takže zatímco function foo() { foo(); } provede hodně rychle spousty volání a následně spadne na vyčerpání zásobníku, function foo() { setTimeout(foo, 0); } projde a volání bude provádět řádově pomaleji.

Tak to vyzkoušíme:

i = 0;
function foo() {
    i++;
    var tm = new Date();
    console.log(tm.getMilliseconds());
    // aby to někdy skončilo
    if (tm.valueOf() < max) {
        setTimeout(foo, 0);
    }
    else console.log(i);
}

max = new Date().valueOf() + 1000; // limit bude 1 sekunda
foo();

Na mém počítači bylo výsledkem zhruba 240-280 volání funkce foo, přitom rozestupy mezi voláními jsou nepravidelné, ta řada milisekund je: 366, 442, 442, 448, 451, 453, 455, …
Už z toho počtu volání (~260 za sekundu je málo) a rozdílných rozestupů mezi nimi je zřejmé, že to tvrzení z [#7] není pravdivé.

Nicméně ještě druhý test, pokud se označený řádek skriptu nahradí za foo();.
Pak je výsledek zhruba podle očekávání, řada vypadá 805, 805, 805, … („805“ bylo prvních 179 hodnot) a po zhruba 27 milisekundách a necelých 3800 voláních to spadlo na vyčerpání zásobníku.
_es
Profil
Jednoduchšie je to overiť, ak sa do stránky pridá:
<script>
setTimeout("alert('pokus')", 0);
document.write("pokus");
</script>
a potom sa nahradí za:
<script>
alert('pokus');
document.write("pokus");
</script>
Funkcia alert dokáže pozastaviť beh skriptu do kliknutia na OK. V prvom prípade sa však na stránke objaví text pokus už pred kliknutím. V druhom prípade však až po kliknutí.
KryVosa
Profil *
Chamurappi:
Proč nastavuješ pro každé políčko vlastní časovací smyčku? Proč nemáš jednu, která by řídila celé hrací pole najednou?

Myslíš že bych udělal něco jako je tohle?
function mainCAnim(X,Y){
mainCD.drawImage(img[gameGrid[X][Y].type],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].building],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].select],X*15,Y*15);X++;
mainCD.drawImage(img[gameGrid[X][Y].type],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].building],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].select],X*15,Y*15);X++;
mainCD.drawImage(img[gameGrid[X][Y].type],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].building],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].select],X*15,Y*15);X++;
mainCD.drawImage(img[gameGrid[X][Y].type],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].building],X*15,Y*15);
mainCD.drawImage(img[gameGrid[X][Y].select],X*15,Y*15);X++;
//A takhle dál až do počtu těchto trojřádků, který odpovídá počtu poliček na ose X....
if(Y==31)Y=0;else Y++;X=0;
setTimeout("mainCAnim("+X+","+Y+")",0);}

Nevím jestli by uživatel ocenil, kdyby si tohle celé musel stahovat. I když málokdo má dnes pomalejší net než počítač :)
Joker
Profil
KryVosa:
Umm, JavaScript, stejně jako skoro všechny programovací jazyky, umí i cykly ;-)
KryVosa
Profil *
Joker:
Jo, máš pravdu, sem blbej :)


Už to fachá, odhadem na 8 Fps, což jako odezva bohatě stačí. Díky moc.
1Pupik1989
Profil
Joker: Máš pravdu. Teď si připadám jak začátečník. Přísahal bych na svůj život, že jses zkoumal překladač javascriptu v nějakém prohlížeči a ten to právě ořízl jen na funkci. Od té doby asi bazíruji na tom, že je to špatné. Pokud najdu v kterém prohlížeči se to stalo, tak ho sem dám. Je to pár let, takže tomu dávám tak 15% šanci. Nicméně prodleva 0 je špatné řešení, na tom se shodneme snad všichni.
_es
Profil
1Pupik1989:
Nicméně prodleva 0 je špatné řešení, na tom se shodneme snad všichni.
Nemusí to byť vždy zlé riešenie, môže to byť príkaz v zmysle: „keď spravíš všetko zvyšné príkazy, tak sprav toto“, čo sa niekedy môže hodiť.
1Pupik1989
Profil
_es: Funkci dáš za poslední příkaz a zavolá se poslední. Pořád v tom žádný smysl nevidím. Docela by mě zajímala nějaká ukázka v praxi.
KryVosa
Profil *
Zkoušel jsem ten setTimeout("funkce()",0) nahradit requestAnimationFrame(funkce) a je to daleko pomalejší než moje řešení. Co dělám špatně?
_es
Profil
1Pupik1989:
Funkci dáš za poslední příkaz a zavolá se poslední. Pořád v tom žádný smysl nevidím.
Nemá to však rovnaký efekt. Ak sa použije setTimeout, tak prehliadač môže „stihnúť“ pred spustením časovača aj iné veci - napríklad nejakú interakciu s návštevníkom - nie je to celkom „blokujúca“ nekonečná slučka.

KryVosa:
Co dělám špatně?
Čo tak použiť nejaké normálnejšie cykly - napríklad for či while?
1Pupik1989
Profil
KryVosa: Neděláš nic špatně. requestAnimationFrame má za úkol držet 60 snímků za sekundu. Používá se do herní smyčky jako náhrada za setTimeout.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm: