25/09/2018
En el desarrollo de videojuegos, el control del tiempo es fundamental. No siempre queremos que las acciones ocurran de forma instantánea. A veces, necesitamos una pequeña pausa para generar tensión, para mostrar un mensaje al jugador, o para asegurar una transición suave entre niveles. Un problema muy común, especialmente para los desarrolladores que se inician en GameMaker, es cómo implementar un retraso (delay) antes de una acción, como cambiar de sala, sin que el juego siga corriendo y potencialmente cause errores, como la muerte injusta del jugador. Este artículo es una guía exhaustiva para dominar las pausas y delays en GameMaker, explorando los métodos correctos y explicando por qué las viejas prácticas ya no son viables.

- El Problema de las Transiciones Instantáneas
- La Vieja Escuela: ¿Qué Pasó con la Función sleep()?
- La Solución Moderna y Eficiente: Las Alarmas
- Resolviendo el Dilema: Cómo Pausar la Acción de Verdad
- Alternativa Manual: Creando tu Propio Temporizador
- Tabla Comparativa: Alarmas vs. Contadores Manuales
- Preguntas Frecuentes (FAQ)
El Problema de las Transiciones Instantáneas
Imagina la siguiente escena: tu héroe acaba de superar un foso lleno de trampas, salta en el último segundo y presiona un interruptor que abre la puerta al siguiente nivel. La lógica del juego dicta que, al presionar el interruptor, se debe pasar a la siguiente sala. Si usas una función como room_goto_next() inmediatamente, la transición será abrupta. El jugador no tendrá ni un instante para saborear su victoria. Pero el problema es más profundo que una simple cuestión de ritmo.
Consideremos el escenario descrito por muchos desarrolladores: el jugador activa el interruptor, pero una caja que caía del techo sigue su curso durante una fracción de segundo antes de que la transición se complete. En esa fracción de segundo, la caja aplasta al jugador. ¿Qué sucede entonces? El juego podría entrar en un estado de error, intentando gestionar la muerte del jugador y la transición de sala al mismo tiempo, lo que podría resultar en un bug que rompa la partida. O, en el mejor de los casos, la experiencia del jugador se ve arruinada por una muerte que percibe como injusta. La solución es clara: necesitamos pausar la acción por un breve momento, digamos un segundo, para que la transición sea limpia y segura.
La Vieja Escuela: ¿Qué Pasó con la Función sleep()?
Los veteranos de versiones antiguas como GameMaker 8.1 recordarán una función llamada sleep(milliseconds). A primera vista, parecía la solución perfecta. Con una sola línea de código, podías detener todo durante el tiempo que quisieras. Si querías una pausa de un segundo, simplemente escribías sleep(1000). Sin embargo, esta función tenía un defecto fundamental: era bloqueante.
Una función bloqueante detiene por completo el hilo de ejecución del juego. Esto significa que el juego no solo deja de procesar la lógica de los enemigos o del jugador, sino que deja de hacer todo. No actualiza la pantalla, no procesa la entrada del usuario, no reproduce sonido. Para el sistema operativo, el juego parece haberse congelado. Esto a menudo provocaba que Windows o macOS mostraran el temido mensaje de "La aplicación no responde". Era una mala práctica que afectaba negativamente la experiencia del usuario y la estabilidad del programa. Por esta razón, la función sleep() fue eliminada en versiones más modernas de GameMaker Studio, obligando a los desarrolladores a adoptar métodos más inteligentes y eficientes: los métodos no bloqueantes.
La Solución Moderna y Eficiente: Las Alarmas
La forma más idiomática y recomendada de crear un delay en GameMaker es utilizando el sistema de alarmas. Cada instancia de un objeto en GameMaker tiene 12 alarmas incorporadas (de la 0 a la 11). Una alarma es esencialmente un temporizador que cuenta hacia abajo en cada paso del juego. Cuando llega a cero, ejecuta el código que se encuentra en su evento correspondiente.

Paso a Paso: Implementando un Delay con Alarmas
Usemos el ejemplo de la transición de sala. Queremos que, después de presionar un interruptor, el juego espere un segundo y luego cambie de sala.
- Activar la Alarma: En el objeto que gestiona la transición (podría ser el propio interruptor o un objeto controlador), en el evento que se dispara al completarse el objetivo (por ejemplo, un evento de colisión con el jugador), escribiremos el siguiente código:
// Esto activa la alarma 0 para que se dispare después de un segundo. alarm[0] = room_speed; La variable incorporada room_speed es clave aquí. Representa el número de fotogramas por segundo (FPS) a los que está configurada tu sala. Al asignar este valor a una alarma, le estamos diciendo que cuente exactamente ese número de pasos, lo que equivale a un segundo de tiempo real en el juego.
- Crear el Evento de Alarma: Ahora, en el mismo objeto, necesitas añadir el evento correspondiente a la alarma que has configurado. Haz clic en "Add Event", luego selecciona "Alarm" y elige "Alarm 0".
- Escribir la Acción Final: Dentro del evento "Alarm 0" que acabas de crear, coloca el código que quieres que se ejecute después de que haya pasado el segundo.
// Este código se ejecutará exactamente un segundo después de que la alarma fue activada. room_goto_next(); ¡Y ya está! Con este sistema, el juego no se congela. El bucle del juego sigue corriendo, las animaciones pueden continuar, pero la acción de cambiar de sala se retrasa de forma limpia y segura. Sin embargo, esto solo retrasa la acción, no pausa el juego. Para eso, necesitamos un paso más.
Resolviendo el Dilema: Cómo Pausar la Acción de Verdad
Hemos logrado retrasar la transición, pero el problema original persiste: el jugador todavía puede morir durante ese segundo de espera. Para evitarlo, necesitamos implementar una máquina de estados. Este es un concepto de programación increíblemente poderoso y más sencillo de lo que parece.
La idea es tener una variable global que controle el estado actual del juego. Por ejemplo, en el evento "Create" de un objeto controlador que exista en todas las salas, podríamos inicializarlo:
global.gameState = "playing"; Ahora, en el evento "Step" de todos los objetos que deben pausarse (el jugador, los enemigos, las trampas), añadimos una simple comprobación al principio de su código:
// Al principio del evento Step del jugador, enemigos, etc. if (global.gameState != "playing") { exit; // No ejecutes el resto del código de este evento } Con esta estructura, solo tenemos que cambiar el valor de global.gameState para controlar todo el flujo del juego. Volviendo a nuestro ejemplo del interruptor:
// En el evento de colisión con el interruptor global.gameState = "transitioning"; // El juego está "pausado" alarm[0] = room_speed; Ahora, durante ese segundo de espera, el código de movimiento y lógica del jugador y los enemigos no se ejecutará. Estarán congelados en su sitio. En el evento "Alarm 0", justo antes de cambiar de sala, es una buena práctica resetear el estado:
// En el evento Alarm 0 global.gameState = "playing"; // Preparamos el estado para la siguiente sala room_goto_next(); Este enfoque es robusto, escalable y la forma profesional de gestionar pausas y flujos de juego complejos.

Alternativa Manual: Creando tu Propio Temporizador
Aunque las alarmas son fantásticas, hay un límite de 12 por objeto. Si necesitas gestionar múltiples delays simultáneos o quieres un control más explícito, puedes crear tu propio temporizador usando variables.
Este método replica la lógica de una alarma manualmente.
- Inicializar Variables: En el evento "Create" del objeto que controlará el delay:
delay_timer = -1; // Usamos -1 para indicar que el temporizador está inactivo - Gestionar el Contador en el Evento Step: Aquí es donde ocurre la magia.
// Si el temporizador está activo (no es -1) if (delay_timer > -1) { delay_timer--; // Restamos 1 en cada paso // Si el temporizador llega a 0 if (delay_timer <= 0) { // Ejecuta tu código aquí room_goto_next(); delay_timer = -1; // Desactivamos el temporizador para que no se repita } } - Activar el Temporizador: Para iniciar la cuenta atrás, simplemente asigna el número de pasos que quieres esperar. Para un segundo:
// En el evento que dispara el delay delay_timer = room_speed; Tabla Comparativa: Alarmas vs. Contadores Manuales
Ambos métodos son válidos, pero cada uno brilla en diferentes situaciones. Aquí tienes una comparación directa:
| Característica | Alarmas | Contadores Manuales |
|---|---|---|
| Facilidad de Uso | Muy fácil, integrado en el IDE con eventos separados. | Requiere más código y lógica manual en el evento Step. |
| Gestión | Automática. Una vez que la alarma se dispara, se resetea a -1. | Totalmente manual. Debes recordar resetear la variable. |
| Límite | 12 por instancia de objeto (alarm[0] a alarm[11]). | Ilimitado, solo depende de cuántas variables quieras crear. |
| Claridad del Código | Muy claro. La lógica de activación y ejecución están separadas. | Puede desordenar el evento Step si se gestionan muchos contadores. |
| Mejor para... | Delays simples y únicos, como recargas de armas, invencibilidad temporal o transiciones. | Sistemas complejos que requieren múltiples temporizadores simultáneos o delays dinámicos. |
Preguntas Frecuentes (FAQ)
¿Puedo usar sleep() en las versiones nuevas de GameMaker?
No, la función sleep() fue eliminada de GameMaker Language (GML) en las versiones de Studio. Aunque encontraras una forma de replicar su comportamiento, no deberías hacerlo. Las funciones bloqueantes son una mala práctica de programación que lleva a juegos inestables y con mala experiencia de usuario.
¿Qué pasa si el room_speed cambia? ¿Mi delay seguirá siendo de un segundo?
Sí. La belleza de usar alarm[0] = room_speed; es que es dinámico. Si cambias los FPS de la sala de 30 a 60, room_speed valdrá 60, y la alarma seguirá esperando el número de pasos equivalente a un segundo en esa nueva velocidad.
¿Cómo creo un delay de menos (o más) de un segundo?
Simplemente usa múltiplos o fracciones de room_speed. Por ejemplo:
- Medio segundo:
alarm[0] = room_speed / 2; - Tres segundos:
alarm[0] = room_speed * 3; - Diez fotogramas:
alarm[0] = 10;
¿Por qué mi personaje sigue muriendo durante la pausa?
Este es el punto más importante. Configurar una alarma solo retrasa una acción específica, no pausa el juego entero. El bucle del juego sigue ejecutando el código de todos los demás objetos. Para evitar esto, debes implementar un sistema que detenga la lógica de los objetos, como la máquina de estados que explicamos anteriormente. Es la única forma de garantizar una pausa real y segura.
Si quieres conocer otros artículos parecidos a Crear Pausas y Delays en GameMaker: Guía Completa puedes visitar la categoría Juegos.
