Introducción al Desarrollo de Videojuegos con GameMaker · Módulo 12: Depuración, optimización, exportación y publicación.
Uso del depurador (Debugger) de GameMaker
Clase 56 de 60 · 60 min
También disponible en: EN
Introducción a la depuración en GameMaker
A lo largo de los módulos anteriores, has creado personajes con mecánicas de salto, colisiones sólidas con plataformas, enemigos patrulleros con inteligencia artificial básica, interfaces gráficas y niveles interconectados. Sin embargo, a medida que un proyecto de videojuegos crece en complejidad, es inevitable encontrarse con anomalías: un personaje que atraviesa una pared bajo circunstancias específicas, un contador de monedas que suma valores inesperados o un enemigo que deja de patrullar de manera repentina. En el desarrollo de software y videojuegos, estos fallos lógicos se denominan comúnmente errores o bugs, y el proceso metódico de identificarlos, aislarlos y solucionarlos se conoce como depuración (debugging).
Muchos desarrolladores novatos intentan diagnosticar fallos modificando código a ciegas o llenando sus scripts con llamadas a la función show_debug_message(). Si bien imprimir mensajes en la consola de salida (Output) es una técnica válida para diagnósticos rápidos, resulta completamente insuficiente cuando se requiere examinar el estado interno del juego en un fotograma exacto. GameMaker incluye una herramienta profesional de diagnóstico denominada Depurador de GameMaker (GameMaker Debugger). Esta suite permite pausar la ejecución del motor, examinar los valores de cada variable en la memoria RAM, recorrer el código instrucción por instrucción y rastrear la secuencia exacta de llamadas que provocaron un fallo imprevisto.
💡 Diferencia clave: show_debug_message() imprime cadenas de texto en la consola de salida mientras el juego sigue corriendo a 60 cuadros por segundo, lo que a menudo satura el registro. El Depurador interactivo (Debugger), por el contrario, detiene el tiempo del juego por completo y congela el motor en una línea exacta, permitiéndote inspeccionar cada variable de cualquier instancia viva sin alterar el ritmo de ejecución.
Tipos de errores: Sintaxis, Compilación y Tiempo de ejecución
Para utilizar el depurador eficazmente, primero es fundamental distinguir las tres categorías primordiales de errores que pueden surgir durante el ciclo de vida de un videojuego en GameMaker:
| Tipo de Error | Momento en que se detecta | Causa común | Herramienta de diagnóstico |
|---|---|---|---|
| Error de Sintaxis | Mientras se escribe el código | Falta de punto y coma, llaves sin cerrar, palabras clave mal escritas. | Subrayado rojo en el Editor de Código y panel de Errores de Sintaxis. |
| Error de Compilación | Al presionar Play (F5) o Debug (F6), antes de abrir el juego | Llamar a un recurso inexistente, macros duplicadas, conflictos de nombres. | Consola de compilación (Compiler Output) con código de detención. |
| Error en Tiempo de Ejecución (Runtime / Lógico) | Mientras el juego se está ejecutando activamente | División por cero, leer una variable no inicializada, desfase de arrays, colisiones fantasma. | Ventana de Fatal Error y el Depurador interactivo (Debugger). |
Los errores de sintaxis y compilación impiden que el juego siquiera genere un archivo ejecutable temporal. En cambio, los errores en tiempo de ejecución (runtime errors) y los fallos de lógica permiten que el juego inicie con aparente normalidad, pero provocan comportamientos incorrectos o el cierre forzoso de la aplicación en medio de una partida. Es en este último escenario donde el depurador se convierte en una herramienta indispensable para cualquier programador de videojuegos.
Ejecutar el juego en modo depuración (Debug Mode)
Para iniciar tu proyecto con los módulos de depuración activos, no debes utilizar el botón habitual de Play (o la tecla F5). En su lugar, debes hacer clic en el icono con forma de insecto situado junto al botón de reproducción en la barra de herramientas superior de GameMaker, o bien presionar el atajo de teclado F6. Al hacerlo, el entorno compila el proyecto inyectando símbolos de depuración y abre dos ventanas independientes: la ventana del juego (con el motor corriendo normalmente) y la ventana del Depurador de GameMaker.
La interfaz del depurador está dividida en varios paneles estratégicos: la barra de control de ejecución superior (con botones de pausa, reanudación y avance paso a paso), el explorador de recursos e instancias (Source / Instances), la ventana de código fuente activo (Code View), el visor de variables (Variables View) y la ventana de expresiones personalizadas (Watch View). Mientras el juego esté corriendo sin interrupciones, el depurador recopilará estadísticas de rendimiento, uso de memoria RAM y tasa de fotogramas (FPS reales). Sin embargo, su verdadero potencial se desbloquea al congelar el tiempo mediante puntos de parada.

Puntos de parada (Breakpoints) y navegación paso a paso
Un punto de parada (breakpoint) es una marca visual que le indica al compilador de depuración: 'Ejecuta el juego a toda velocidad, pero en el instante exacto en que vayas a procesar esta línea de código específica, congela la ejecución del juego por completo y dale el control al programador'. Los breakpoints no modifican el comportamiento del código ni alteran las variables; simplemente pausan el hilo de ejecución justo antes de que la línea marcada sea evaluada por el procesador.
Para colocar un punto de parada en GameMaker, abre cualquier script o evento de un objeto en el editor y haz clic izquierdo en el margen gris situado a la izquierda del número de línea, o coloca el cursor en dicha línea y presiona F9. Aparecerá un círculo rojo brillante confirmando que el punto de parada está armado. Puedes fijar tantos breakpoints como consideres necesario en diferentes objetos y eventos. Cuando el juego en modo depuración alcance ese fragmento de código, la ventana del juego se detendrá en el fotograma actual y la interfaz del depurador resaltará la línea activa en color amarillo.
Una vez que el juego se encuentra pausado sobre un punto de parada, dispones de cuatro controles fundamentales en la barra de herramientas del depurador para dirigir el flujo del programa con precisión milimétrica:
| Comando | Atajo | Función y Comportamiento |
|---|---|---|
| Continue (Continuar) | F5 | Reanuda la ejecución normal del juego a velocidad completa hasta que finalice o tropiece con el siguiente breakpoint activo. |
| Step In (Paso Adentro) | F11 | Avanza a la instrucción inmediatamente siguiente. Si la línea actual contiene una llamada a un script o función personalizada, ingresa dentro de dicha función para examinarla. |
| Step Over (Paso Sobre) | F10 | Ejecuta la línea actual por completo sin detenerse en los detalles internos de las funciones invocadas, situándose en la siguiente línea del evento actual. |
| Step Out (Paso Afuera) | Shift + F11 | Ejecuta el resto del script o función actual hasta su finalización y pausa la ejecución inmediatamente en la línea del código que originalmente llamó a esa función. |
Inspección de variables en tiempo real: Locales, de Instancia y Globales
Cuando la ejecución se congela en un breakpoint, el panel de variables (Variables) del depurador cobra vida. Este panel se organiza de forma jerárquica en pestañas y categorías que reflejan la arquitectura de memoria de GameMaker:
1. Variables Locales (Local): Muestra todas las variables declaradas con la palabra clave 'var' dentro del evento o función que se está ejecutando actualmente. Estas variables solo existen durante la fracción de milisegundo que dura dicho bloque de código y son destruidas al salir de él. Inspeccionarlas aquí permite confirmar si cálculos temporales, como distancias vectoriales o índices de bucle, contienen los valores esperados.
2. Variables de Instancia (Self / Instance): Muestra todas las variables asociadas a la instancia del objeto que está procesando el evento actual (por ejemplo, las coordenadas 'x' e 'y', 'hsp', 'vsp', 'hp', 'is_grounded' o 'sprite_index'). Puedes desplegar la lista completa, ver variables integradas del motor (Built-in) y variables definidas por ti en el evento Create. Además, el depurador te permite hacer doble clic sobre cualquier valor numérico, booleano o de texto y editarlo directamente en vivo para comprobar cómo reacciona el juego sin tener que reiniciar ni recompilar.
3. Variables Globales (Global): Presenta el estado de todas las variables globales del proyecto (declaradas mediante el prefijo global.). Es el lugar idóneo para monitorear el estado general de la partida, como el contador acumulado de monedas (global.coins), el identificador del nivel actual o la configuración de audio.
La ventana de seguimiento personalizado (Watch Window)
En proyectos medianos o avanzados, un objeto puede tener docenas de variables de instancia, lo que dificulta encontrar rápidamente el dato que necesitas en la pestaña general. Para resolver esto, el depurador cuenta con la ventana de seguimiento (Watch Window). En este panel puedes hacer clic derecho y seleccionar 'Add Watch' para escribir el nombre de cualquier variable o expresión que desees vigilar de forma prioritaria, como por ejemplo 'obj_player.vsp', 'point_distance(x, y, obj_player.x, obj_player.y)' o 'keyboard_check(vk_space)'.
A medida que utilizas los botones Step Over o Step In, las expresiones añadidas a la lista Watch se reevalúan en tiempo real. Si el valor de una variable cambia con respecto al paso anterior, el depurador resalta la fila en color (habitualmente rojo o amarillo), permitiéndote detectar con total claridad el instante milimétrico en que una variable sufre una mutación no deseada o se convierte en un valor erróneo como NaN (Not a Number) o undefined.
Ejemplo práctico: Diagnóstico de un error de salto infinito
Examinemos un caso de estudio real en el marco de nuestro videojuego de plataformas retro. Supongamos que en el objeto obj_player hemos programado las físicas de movimiento y salto en el evento Step. Al probar el juego, descubrimos un bug crítico: el jugador puede saltar indefinidamente en el aire sin tocar el suelo, como si tuviera un propulsor infinito.
A continuación se muestra el código implementado en obj_player dentro del evento Step:
// Objeto: obj_player
// Evento: Step
// 1. Capturar entradas de control
var _key_left = keyboard_check(vk_left) || keyboard_check(ord("A"));
var _key_right = keyboard_check(vk_right) || keyboard_check(ord("D"));
var _key_jump = keyboard_check_pressed(vk_space) || keyboard_check_pressed(ord("W"));
// 2. Calcular movimiento horizontal
var _move = _key_right - _key_left;
hsp = _move * walk_speed;
// 3. Aplicar gravedad constante si está en el aire
vsp += grv;
// 4. Lógica de salto (Aquí sospechamos que ocurre el fallo)
if (_key_jump && is_grounded)
{
vsp = -jump_speed;
}
// 5. Verificación de contacto con el suelo
if (place_meeting(x, y + 1, obj_solid))
{
is_grounded = true;
}
else
{
// Línea donde el programador olvidó actualizar la condición correctamente
// is_grounded = false; // <-- Comentada por error durante una prueba
}
// 6. Ejecución del movimiento y colisiones verticales
if (place_meeting(x, y + vsp, obj_solid))
{
while (!place_meeting(x, y + sign(vsp), obj_solid))
{
y += sign(vsp);
}
vsp = 0;
}
y += vsp;La Pila de Llamadas (Call Stack)
Cuando tu código se organiza mediante funciones modulares, constructores, métodos y eventos encadenados, a menudo un error ocurre no en el evento raíz, sino en lo profundo de una función invocada varias capas más abajo. La Pila de Llamadas (Call Stack) es el registro histórico que almacena el orden cronológico de ejecución que condujo al procesador hasta la línea actual.
Imagina que en el evento Step de un enemigo (obj_enemy_patrol) llamas a un script llamado 'enemy_attack_player()', y dentro de esa función se llama a otra función personalizada 'damage_player(target, amount)'. Si el juego se detiene en un breakpoint dentro de 'damage_player', la ventana Call Stack mostrará las siguientes capas superpuestas de abajo hacia arriba:
// Representación conceptual del Call Stack:
[3] damage_player() <- Línea actual detenida (Cima de la pila)
[2] enemy_attack_player() <- Función que invocó damage_player()
[1] obj_enemy_patrol : Step <- Evento inicial que originó la secuenciaAl hacer doble clic en cualquiera de las capas inferiores en la ventana Call Stack, el depurador cambiará la vista de código para mostrarte exactamente qué línea de esa función superior originó la llamada. Más importante aún: el visor de variables cambiará su contexto para mostrar los argumentos y variables locales de ese momento exacto en esa capa, permitiéndote rastrear si el parámetro recibido por la función era defectuoso desde su lugar de origen.
Anatomía de un Error Fatal en Tiempo de Ejecución (Runtime Error)
Incluso los desarrolladores más experimentados cometen errores que el compilador no puede predecir. Cuando esto sucede, GameMaker detiene el juego en seco y despliega una ventana emergente titulada 'Fatal Error'. Lejos de ser un mensaje arbitrario, este cuadro contiene información quirúrgica para resolver el problema en segundos si aprendes a descifrar su estructura.
💡 Atención a las discrepancias de nombres: En GML, las mayúsculas y minúsculas importan en muchas configuraciones, y un error tipográfico mínimo como escribir 'Player_speed' en lugar de 'player_speed' provocará inmediatamente una excepción de tipo 'Variable not set before reading it'.
Buenas prácticas de depuración profesional
Para evitar que la depuración se convierta en una tarea frustrante y desordenada, conviene adoptar una disciplina de trabajo fundamentada en métodos rigurosos:
Primero, aísla las variables. Si un cálculo matemático complejo de colisiones falla, descompón la fórmula en variables locales intermedias nombradas claramente. Esto te permitirá colocar un breakpoint en esa línea e inspeccionar el resultado parcial de cada subtérmino en la pestaña Local Variables del depurador en lugar de ver una sola expresión incomprensible.
Segundo, limpia los breakpoints antiguos. Cuando un proyecto acumula docenas de puntos de parada olvidados en diferentes scripts y objetos, ejecutar el juego en modo depuración se vuelve insoportable al detenerse continuamente por motivos ya resueltos. En la pestaña Breakpoints del depurador puedes ver una lista completa de todas las marcas activas en el proyecto y eliminarlas todas con un solo clic o desactivarlas selectivamente.
Tercero, utiliza aserciones y comprobaciones preventivas. En lugar de confiar ciegamente en que una instancia existe antes de acceder a sus propiedades, rodea el bloque con la función instance_exists(). Por ejemplo, antes de ejecutar 'target.x', comprueba siempre 'if (instance_exists(target))'. Esto previene que una instancia destruida en el fotograma anterior desencadene una excepción irrecuperable en el motor.
Ejercicios prácticos
Pon a prueba tus habilidades de diagnóstico y manejo del depurador con los siguientes tres ejercicios diseñados para consolidar el control sobre el flujo del programa y el rastreo de variables.
Resumen
- El depurador de GameMaker (Debug Mode, ejecutado con F6) es la herramienta central para diagnosticar errores lógicos e inspeccionar el estado del juego sin alterar su ritmo natural con mensajes dispersos.
- Los puntos de parada (breakpoints, activados con F9) congelan la ejecución del motor exactamente en la línea seleccionada, permitiendo examinar el entorno antes de que se ejecute la instrucción.
- Los comandos de navegación permiten explorar el flujo del programa con precisión: Step Over (F10) avanza línea por línea, Step In (F11) ingresa al interior de funciones o scripts llamados, y Continue (F5) reanuda el juego a velocidad completa.
- El panel de variables clasifica los datos en Locales (temporales de la función), de Instancia (propias del objeto activo) y Globales (persistentes para todo el juego), permitiendo su edición en caliente durante la pausa.
- La ventana Watch (Seguimiento) permite monitorizar expresiones y variables críticas en tiempo real, destacando visualmente cualquier alteración que sufran entre fotogramas.
- La Pila de Llamadas (Call Stack) desglosa el árbol de funciones y eventos que condujeron al punto actual, indispensable para rastrear el origen de fallos en arquitecturas de código jerárquicas y modulares.
- Los mensajes de 'Fatal Error' en tiempo de ejecución contienen información precisa sobre el objeto, evento, línea y causa exacta del fallo, como intentar leer variables inexistentes o acceder a índices fuera de rango.
Practica lo aprendido
Ejercicio 1 · 1 punto
¿Cuál es la diferencia principal entre utilizar la función show_debug_message() y emplear el Depurador interactivo (Debugger) de GameMaker?
Ejercicio 2 · 1 punto
Relaciona cada categoría o panel del depurador con la función descrita en el texto:
- Variables Locales (Local)
- Variables de Instancia (Self / Instance)
- Variables Globales (Global)
- Ventana de seguimiento (Watch Window)
Ejercicio 3 · 1 punto
Para iniciar el juego en modo depuración se debe presionar la tecla , mientras que para colocar o quitar un punto de parada (breakpoint) en una línea de código se utiliza la tecla .
Ingresa para guardar tu progreso — Ingresar