udemy - ¿La mejor forma de juego simple en Javascript?
programa tus primeros juegos html5 con javascript mega (6)
¿Esto haría?
setInterval(updateGameState, 1000 / 25);
Donde 25 es tu FPS deseado. También puede colocar allí la cantidad de milisegundos entre cuadros, que a 25 fps sería 40 ms (1000/25 = 40).
¿Hay una forma sencilla de hacer un bucle de juego en JavaScript? algo como...
onTimerTick() {
// update game state
}
Esta página lo resume muy bien: http://nokarma.org/2011/02/02/javascript-game-development-the-game-loop/index.html
Hay varias formas de lograr esto utilizando JavaScript, dependiendo de su aplicación. Un setInterval () o incluso con una sentencia while () haría el truco. Esto no funcionará para un bucle de juego. JavaScript interpretado por el navegador, por lo que es propenso a las interrupciones. Las interrupciones harán que el juego de tu juego se sienta nervioso.
Las propiedades webkitRequestAnimationFrame de CSS3 tienen como objetivo corregir esto mediante la gestión del bucle de representación en sí. Sin embargo, esta no es la forma más eficiente de hacerlo y será más propensa a tener nerviosismo si tiene muchos objetos que se están actualizando.
Este es un buen sitio web para comenzar con:
http://nokarma.org/2011/02/02/javascript-game-development-the-game-loop/index.html
Este sitio tiene buena información sobre los conceptos básicos para hacer un bucle de juego. No toca ningún tipo de diseño orientado a objetos de ninguna manera. La forma más precisa de lograr tiempos precisos es mediante el uso de la función de fecha.
while ((new Date).getTime() > nextGameTick && loops < maxFrameSkip) {
Game.update();
nextGameTick += skipTicks;
loops++;
}
Esto no tiene en cuenta cómo se desvía setTimeout a altas frecuencias. Esto también hará que las cosas pierdan la sincronización y se pongan nerviosas. JavaScript se desviará +/- 18ms por segundo.
var start, tick = 0;
var f = function() {
if (!start) start = new Date().getTime();
var now = new Date().getTime();
if (now < start + tick*1000) {
setTimeout(f, 0);
} else {
tick++;
var diff = now - start;
var drift = diff % 1000;
$(''<li>'').text(drift + "ms").appendTo(''#results'');
setTimeout(f, 990);
}
};
setTimeout(f, 990);
Ahora vamos a poner todo esto en un ejemplo de trabajo. Queremos inyectar nuestro bucle de juego en el bucle de representación gestionado de WebKit. Esto ayudará a suavizar los gráficos renderizados. También queremos dividir las funciones de dibujar y actualizar. Esto actualizará los objetos en nuestra escena de representación antes de calcular cuándo se debe dibujar el siguiente fotograma. El bucle de juego también debe saltarse los cuadros de robo si la actualización lleva demasiado tiempo.
Index.html
<html>
<head>
<!--load scripts-->
</head>
<!--
render canvas into body, alternative you can use div, but disable
right click and hide cursor on parent div
-->
<body oncontextmenu="return false" style="overflow:hidden;cursor:none;-webkit-user-select: none;-moz-user-select: none;-ms-user-select: none;user-select: none;">
<script type="text/javascript" charset="utf-8">
Game.initialize();
window.onEachFrame(Game.run);
</script>
</body>
</html>
Juego.js
var Game = {};
Game.fps = 60;
Game.maxFrameSkip = 10;
Game.skipTicks = 1000 / Game.fps;
Game.initialize = function() {
this.entities = [];
this.viewport = document.body;
this.input = new Input();
this.debug = new Debug();
this.debug.initialize(this.viewport);
this.screen = new Screen();
this.screen.initialize(this.viewport);
this.screen.setWorld(new World());
};
Game.update = function(tick) {
Game.tick = tick;
this.input.update();
this.debug.update();
this.screen.update();
};
Game.draw = function() {
this.debug.draw();
this.screen.clear();
this.screen.draw();
};
Game.pause = function() {
this.paused = (this.paused) ? false : true;
};
/*
* Runs the actual loop inside browser
*/
Game.run = (function() {
var loops = 0;
var nextGameTick = (new Date).getTime();
var startTime = (new Date).getTime();
return function() {
loops = 0;
while (!Game.paused && (new Date).getTime() > nextGameTick && loops < Game.maxFrameSkip) {
Game.update(nextGameTick - startTime);
nextGameTick += Game.skipTicks;
loops++;
}
Game.draw();
};
})();
(function() {
var onEachFrame;
if (window.requestAnimationFrame) {
onEachFrame = function(cb) {
var _cb = function() {
cb();
requestAnimationFrame(_cb);
};
_cb();
};
} else if (window.webkitRequestAnimationFrame) {
onEachFrame = function(cb) {
var _cb = function() {
cb();
webkitRequestAnimationFrame(_cb);
};
_cb();
};
} else if (window.mozRequestAnimationFrame) {
onEachFrame = function(cb) {
var _cb = function() {
cb();
mozRequestAnimationFrame(_cb);
};
_cb();
};
} else {
onEachFrame = function(cb) {
setInterval(cb, Game.skipTicks);
};
}
window.onEachFrame = onEachFrame;
})();
Aun mas informacion
Puede encontrar un ejemplo completo de trabajo y todo el código aquí. He convertido esta respuesta en un marco javascript descargable desde el que puedes construir tus juegos.
Sí. Quieres setInterval
:
function myMainLoop () {
// do stuff...
}
setInterval(myMainLoop, 30);
requestAnimationFrame es una excelente alternativa disponible en la mayoría de los navegadores ahora. Hace lo que estás haciendo con setInterval, pero de una forma totalmente horneada. Probablemente, lo mejor de todo es que solo se ejecuta mientras la pestaña está enfocada. Esa podría ser una razón para no usarlo si quiere que las cosas se ejecuten en segundo plano, pero a menudo (especialmente para los bucles de renderizado que solo importan cuando se ven) es genial no usar recursos cuando la pestaña no está activa.
El uso es bastante simple:
function gameLoop(){
window.requestAnimationFrame(gameLoop);
Game.update();
}
Odio publicar en hilos viejos, pero este es un resultado superior de Google para "javascript game loop", por lo que realmente debe incluir requestAnimationFrame.
Pollyfill para navegadores antiguos copiados de paulirish :
(function() {
var lastTime = 0;
var vendors = [''ms'', ''moz'', ''webkit'', ''o''];
for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
window.requestAnimationFrame = window[vendors[x]+''RequestAnimationFrame''];
window.cancelAnimationFrame = window[vendors[x]+''CancelAnimationFrame'']
|| window[vendors[x]+''CancelRequestAnimationFrame''];
}
if (!window.requestAnimationFrame)
window.requestAnimationFrame = function(callback, element) {
var currTime = new Date().getTime();
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
var id = window.setTimeout(function() { callback(currTime + timeToCall); },
timeToCall);
lastTime = currTime + timeToCall;
return id;
};
if (!window.cancelAnimationFrame)
window.cancelAnimationFrame = function(id) {
clearTimeout(id);
};
}());
Una explicación más profunda y consejos de uso en creativeJS
setInterval(onTimerTick, 33); // 33 milliseconds = ~ 30 frames per sec
function onTimerTick() {
// Do stuff.
}