Tengo un bucle de juego simple que dice así:
function update(progress){ //do something each second //do something else twice per second //do something else each two seconds } function draw() { //code here... } function gameLoop(timestamp) { update(progress) draw() var progress = (timestamp - lastRender) lastRender = timestamp window.requestAnimationFrame(gameLoop) } var lastRender = 0 window.requestAnimationFrame(gameLoop)
¿Cómo puedo asegurarme de ejecutar algunas acciones en la función de actualización cada medio segundo, segundo o dos segundos?
Gracias
Si desea definir el intervalo, deberá usar setInterval
. requestAnimationFrame
solo se actualizará en función de la frecuencia de actualización de la pantalla, por lo que no puede definir su propio intervalo con esto. Sin embargo, setInterval
tiene muchas desventajas, por lo que se recomienda sincronizar el intervalo con la frecuencia de actualización usando algo como esto:
let doUpdate = false setInterval(() => doUpdate = true), 1000) const render = () => { if (doUpdate) { // your code doUpdate = false } } window.requestAnimationFrame(render)
Si desea realizar una acción periódicamente al usar el bucle de juego basado en el tiempo delta, la idea básica es que mantenga un contador del tiempo transcurrido. Para cada iteración, luego agrega la diferencia de tiempo hasta que alcanza el período previsto.
Aplicado a su código, se vería así:
let oneSecondCounter = 0 let twoSecondCounter = 0 function update(progress){ oneSecondCounter += progress if (oneSecondCounter >= 1000) { // Code here will be executed every 1000ms oneSecondCounter = 0 } twoSecondCounter += progress if (twoSecondCounter >= 2000) { // Code here will be executed every 2000ms twoSecondCounter = 0 } } function draw() {} function gameLoop(timestamp) { var progress = (timestamp - lastRender) update(progress) draw() lastRender = timestamp window.requestAnimationFrame(gameLoop) } var lastRender = performance.now() window.requestAnimationFrame(gameLoop)
Sin embargo, esto significa que debe crear una variable de contador para cada acción periódica que desee realizar. En lugar de crear una variable separada, podemos agrupar el contador junto con la función usando un cierre. El cierre permite que cada función tenga su propio contador independiente.
El cierre que vamos a usar se ve así:
function initPeriodicFunction(fn, runEvery) { let counter = 0 return function (deltaTime) { counter += deltaTime if (counter >= runEvery) { fn() counter = 0 } } }
Ahora, en lugar de tener que crear una variable de contador para cada acción, podemos simplemente pasar una función a initPeriodicFunction
y obtener una nueva función que se ejecutará solo periódicamente.
// You can use an arrow function const runEverySecond = initPeriodicFunction(() => console.log('One second'), 1000) // Or you can pass a function function runThis() { console.log('Two seconds') } const runEveryTwoSeconds = initPeriodicFunction(runThis, 2000) function update(progress){ runEverySecond(progress) runEveryTwoSeconds(progress) }
Dependiendo de su caso de uso, el método anterior podría ser suficiente. Si va a realizar tareas más precisas (por ejemplo, motor de física), sería mejor separar la velocidad de fotogramas de la velocidad de actualización. Esto es similar a cómo funciona FixedUpdate
de Unity.
Imagina que quieres realizar una actualización de física cada 100 ms. Si de alguna manera la llamada de actualización se retrasó, por ejemplo, 600 ms después de la última actualización, en lugar de realizar una sola actualización, realizamos 6 actualizaciones, cada una con un fragmento de 100 ms. Esto da como resultado un cálculo paso a paso más preciso.
Para realizar este tipo de actualización fija, la función de inicialización debe modificarse de la siguiente manera:
function initPeriodicFunction(fn, runEvery) { let counter = 0 return function (deltaTime) { counter += deltaTime while (counter >= runEvery) { fn() counter -= runEvery } } }
Ahora, la función se ejecutará una o varias veces según el tiempo transcurrido desde la última llamada de actualización.
setInterval(function { //code that happends every second goes here }, 1000);
usa setIntervalo().
Esto crea un temporizador y llamará a la función cada x segundos.