¿Hay una manera simple de hacer un bucle de juego en JavaScript? algo así como ...¿La mejor forma de juego simple en Javascript?
onTimerTick() {
// update game state
}
¿Hay una manera simple de hacer un bucle de juego en JavaScript? algo así como ...¿La mejor forma de juego simple en Javascript?
onTimerTick() {
// update game state
}
Sip. Usted quiere setInterval
:
function myMainLoop() {
// do stuff...
}
setInterval(myMainLoop, 30);
Would this do?
setInterval(updateGameState, 1000/25);
Donde 25 es su FPS deseado. También podría poner allí la cantidad de milisegundos entre fotogramas, que a 25 fps sería de 40 ms (1000/25 = 40).
usted prolly quiere pasar la función, no es su resultado –
Tiene razón, corregido. –
no maneja deriva y causará latencia. No usa webkit –
Esta página resume muy bien: http://nokarma.org/2011/02/02/javascript-game-development-the-game-loop/index.html
Hay una cantidad variada de maneras de lograr esto usando 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 interrupciones. Las interrupciones harán que la reproducción de tu juego se sienta nerviosa.
Las propiedades webkitRequestAnimationFrame de CSS3 intentan corregir esto administrando el bucle de renderizado. Sin embargo, esta no es la manera más eficiente de hacer esto y será propenso a los nervios si tiene muchos de los objetos que se actualizan.
Este es un buen sitio para empezar con:
http://nokarma.org/2011/02/02/javascript-game-development-the-game-loop/index.html
Este sitio tiene una buena información sobre los fundamentos de 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 setTimeout se desplaza a altas frecuencias. Esto también llevará a que las cosas se desincronicen y se pongan nerviosas. JavaScript deriva +/- 18 ms 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 pongamos 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 dibujo y actualización. Esto actualizará los objetos en nuestra escena de renderizado antes de calcular cuándo se dibujará el siguiente cuadro. El bucle del juego también debe omitir los cuadros de sorteo si la actualización es demasiado larga.
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;
})();
aún más información
puede encontrar un ejemplo de trabajo completo, y todo el código aquí. He convertido esta respuesta en un marco descargable de JavaScript desde donde puedes construir tus juegos.
-1 Este es un lío poco estructurado y mal expresado de una respuesta con innumerables errores ortográficos y gramaticales. Lea [Cómo responder a procedimientos] (http://stackoverflow.com/help/how-to-answer). – Joe
arreglé la gramática y agregué un mejor código de ejemplo. –
Su respuesta es la más correcta y actualizada en la página, pero ahora tiene demasiado código de ejemplo. Los futuros lectores no se preocuparán por el diseño HTML, world.js, player.js, camera.js o tile.js. Por favor, solo incluya los elementos de su respuesta relevantes para manejar el tiempo para un bucle de juego usando requestAnimationFrame. –
requestAnimationFrame es una gran alternativa disponible en la mayoría de los navegadores de hoy. Hace lo que estás haciendo con setInterval, pero de una manera cocida. Probablemente lo mejor de todo es que solo se ejecuta mientras su pestaña está enfocada. Esa podría ser una razón no para usarla si desea que las cosas se ejecuten en segundo plano, pero a menudo (especialmente para los bucles de renderizado que solo importan cuando se ve) 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 escribir en hilos de edad, pero esto es un resultado superior para Google "bucle Javascript juego" por lo que realmente necesita 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);
};
}());
más profundos consejos explicación y de uso en creativeJS
En el mundo orientado a eventos de JavaScript es probable que no necesita hacer esto. ¿Por qué crees que necesitas esto? –
@Jon, ¿cómo vas a actualizar un juego cuando no se ha activado ningún evento? Muchos juegos están haciendo cosas incluso cuando no ... – James