Así funciona el bucle del videojuego
Input, actualizar, renderizar — el latido del videojuego
Cada videojuego que has jugado — desde el Pong hasta el último éxito de mundo abierto — lo mueve un solo latido: el bucle del juego. El bloque de código que no se detiene. Mientras el bucle corre, el juego está vivo. Cuando se detiene, el juego termina. Entender cómo funciona es el primer paso para hacer tus propios videojuegos.
El bucle más simple
En el núcleo, un bucle de juego hace tres cosas, una y otra vez: revisa el input, actualiza el estado del juego (posiciones, puntajes, física) y renderiza el siguiente cuadro en pantalla. En pseudocódigo se ve así:
while (gameIsRunning) { // Mientras el juego esté corriendo
processInput(); // Procesa el input
update(); // Actualiza el estado del juego
render(); // Renderiza el siguiente cuadro en pantalla
}
Eso es todo. Sin magia. El bucle corre tan rápido como la máquina lo permita (o como tú lo limites). Cada vuelta es un “tic” del reloj del juego. Mueves al jugador, actualizas a los enemigos, resuelves colisiones y pintas el resultado. Repites hasta que el jugador cierra.
Por qué los cuadros por segundo no son fijos
En las máquinas arcade y consolas viejas la lógica corría a un ritmo fijo, por ejemplo 60 veces por segundo. En computadoras y celulares de hoy el ritmo varía: una escena pesada puede ir a 50 FPS y un menú simple a 120 FPS. Si atas la lógica del juego a “una actualización por cuadro”, el juego irá más rápido en hardware potente y más lento en uno débil. Un personaje que se mueve 10 píxeles por cuadro cruzaría la pantalla en la mitad del tiempo a 120 FPS que a 60 FPS. Eso se siente roto e injusto.
La solución es usar el tiempo delta (suele
escribirse dt): el tiempo en segundos (o milisegundos)
desde el cuadro anterior. Multiplicas el movimiento y otros cambios
por dt. Así, “10 píxeles por segundo” se vuelve
position += 10 * dt. El personaje recorre la misma
distancia por segundo sin importar cuántos cuadros renderice la
máquina. El juego queda independiente del framerate.
Actualizar vs renderizar
Conviene tener claro la diferencia entre “actualizar” y “renderizar”. Actualizar es donde cambias el mundo del juego: física, IA, timers, input. Renderizar es donde llevas ese estado a la pantalla. Puedes actualizar varias veces en un cuadro (por ejemplo física a paso fijo) y renderizar una sola vez, o saltarte un render si el cuadro se atrasó. Muchos motores hacen “actualizar a 60 Hz, renderizar cuando se pueda” para que la física sea estable y la imagen varíe.
El bucle en el navegador
En el navegador no escribes while (true). El navegador
te da requestAnimationFrame (a veces
abreviado rAF). Le pasas una función; el navegador la
llama antes del siguiente refresco, casi siempre al ritmo de la
pantalla (60 o 120 Hz). Tu “bucle” es: pedir el siguiente cuadro y
en esa función hacer tu actualización y tu render. Una llamada por
cuadro, con un tiempo que puedes medir para obtener dt.
Mira el bucle en acción
Es el mismo bucle: en cada cuadro actualizamos la posición de la pelota con el tiempo delta y luego renderizamos. Pausa y usa “Avanzar 1 cuadro” para hacer una actualización y un render a la vez.
En la demo de arriba la posición de la pelota se actualiza con
position += velocity * dt. Su velocidad está en
“unidades por segundo”, no “unidades por cuadro”. Los números
muestran el cuadro actual, los FPS y el tiempo delta. Al pausar se
detiene el bucle; “Avanzar 1 cuadro” hace una actualización y un
render para que veas el bucle dar un solo tic.
Paso fijo vs paso variable
Algunos juegos usan un paso fijo para la física
(por ejemplo siempre 1/60 s por paso). Pueden ejecutar varios pasos
de física en un cuadro si el cuadro fue largo, para que la
simulación no se desincronice del tiempo real. Otros usan
paso variable: una actualización por cuadro, con
dt igual al tiempo real transcurrido. Cada enfoque
tiene sus pros y contras: el fijo es estable y reproducible; el
variable es más simple y es suficiente para muchos juegos. Los motores
profesionales suelen mezclar (física fija, render variable).
Un solo bucle para todos
No importa qué tan grande sea el juego, la idea es la misma: un bucle, input → actualizar → renderizar, con el tiempo (tiempo delta) impulsando los cambios. Cuando lo ves así, puedes entrar a sistemas de entrada, pipelines de renderizado y motores de física sabiendo que todos se conectan a este latido. Dominar el bucle es tener la base sobre la que se construye todo lo demás.
Un bucle. Input, actualizar, renderizar. Repetir.
Aplico las mismas ideas en Second Runner, una extensión
de Chrome de estilo arcade que escribí en JavaScript. Cada minijuego
corre con requestAnimationFrame: leemos la entrada
(posición del ratón), avanzamos la simulación (pelota y paletas)
usando el tiempo transcurrido para que el movimiento sea estable aunque
cambien los FPS, y luego dibujamos en el canvas — el mismo ritmo
entrada → actualizar → renderizar que describe este post. Puedes
instalarla desde
Chrome Web Store — Second Runner.
Referencias & lecturas adicionales
- Preguntas etiquetadas «game-loop» (QA Stack) — hilos en español sobre el bucle central del juego: paso de tiempo fijo o variable, render independiente de la actualización, arquitectura y más.
- Programación de videojuegos con SDL (PDF) — manual práctico con C/C++ y SDL; el bucle del juego aparece en el contexto de un proyecto real y el ciclo de actualización y dibujo.
- Fundamentos de programación de videojuegos (Game Byte Bite) — tutorial introductorio en español: fases de entrada, actualización y renderizado, y la relación con los FPS.
- Patrón Game Loop (Java Design Patterns, español) — propósito del patrón, ejemplo con código y variantes (por fotogramas, paso variable, paso fijo).
¿Aún no tienes suficiente de Lumænaut_? Lee esto...
- Puliendo LeetCode — Día 1: Two Sum — un recorrido amigable de fuerza bruta a una solución O(n) con hash map.
- Los 8 paradigmas de algoritmos — ocho formas de pensar que aparecen una y otra vez en problemas clásicos.
- Episodio 2: Todo lo que no sé sobre bloggear — bitácora detrás del sitio: dominios, SEO y aprender en público.