Introducción al Desarrollo de Videojuegos con GameMaker · Módulo 3: Fundamentos de programación con GML Code.
Sintaxis básica y variables en GML
Clase 11 de 60 · 60 min
También disponible en: EN
Introducción a GML Code y estructura sintáctica
En los módulos anteriores exploraste cómo GameMaker organiza los recursos visuales y estructurales de un proyecto: sprites, objetos, eventos y rooms. Hasta ahora, las propiedades de tus entidades han dependido en gran medida de los valores por defecto del motor. Sin embargo, para dotar a un videojuego de interactividad real, sistemas de combate, físicas personalizadas y dinámicas complejas, es imprescindible comunicarse directamente con el motor a través de código. GameMaker Language (GML) es el lenguaje nativo diseñado específicamente para esta tarea. Aunque existe GML Visual —un sistema basado en bloques de acciones visuales—, GML Code es el estándar de la industria para desarrolladores independientes y estudios profesionales debido a su velocidad de redacción, legibilidad, facilidad de control de versiones y versatilidad técnica.
La sintaxis de GML guarda una fuerte similitud con lenguajes de la familia C, tales como JavaScript, C# y C++. Se compone de instrucciones (o sentencias) que indican al compilador qué acción realizar en cada fotograma del juego. Cada instrucción ejecutada debe finalizar idealmente con un punto y coma (;). Aunque el compilador de GameMaker es permisivo y en muchas ocasiones tolera la omisión del punto y coma, prescindir de él es una mala práctica que suele provocar ambigüedades lógicas al trabajar con expresiones complejas o scripts avanzados. Asimismo, GML es un lenguaje sensible a mayúsculas y minúsculas (case-sensitive): una variable llamada 'puntos' no es igual a 'Puntos' ni a 'PUNTOS'. Si intentas acceder a una versión mal escrita de una variable, GameMaker lanzará un error fatal en tiempo de ejecución (runtime error) indicando que la variable no está definida.
Un componente esencial del código limpio y profesional son los comentarios. Los comentarios son notas escritas por el programador que el compilador ignora completamente durante la ejecución. En GML existen dos tipos estándar de comentarios: los de una sola línea, precedidos por dos barras inclinadas (//), y los comentarios de bloque o multilínea, delimitados entre una barra con asterisco al inicio y un asterisco con barra al cierre (/* ... */). Los comentarios deben usarse para documentar la intención detrás de cálculos matemáticos no evidentes, demarcar secciones de código o desactivar temporalmente fragmentos durante sesiones de prueba.
// Esto es un comentario de una sola línea
// Inicialización de la velocidad base del jugador
velocidad_caminar = 4;
/*
El siguiente bloque de código realiza un cálculo
complejo para determinar el multiplicador de puntuación
en función de las monedas obtenidas sin recibir daño.
*/
multiplicador_activo = true;Tipos de datos fundamentales en GameMaker
A diferencia de lenguajes de tipado estricto como C++ o Java, GML es un lenguaje de tipado dinámico. Esto significa que no necesitas declarar explícitamente si una variable almacenará un entero, un decimal o una cadena de texto al momento de crearla; el tipo de datos se deduce automáticamente a partir del valor asignado y puede cambiar si se le reasigna un valor distinto. No obstante, para programar videojuegos sin errores lógicos, es imperativo comprender la naturaleza de los tipos de datos primitivos que gestiona GameMaker en memoria.
Los números (Reals) representan cualquier valor numérico en GML. GameMaker no distingue formalmente a nivel de sintaxis entre enteros (como 1, 0, -15) y números de punto flotante o decimales (como 3.1415, -0.5, 8.0). Todos se procesan internamente con precisión numérica de coma flotante. Esto simplifica cálculos matemáticos continuos, como la aceleración o la gravedad, aunque requiere precaución cuando se comparan valores fraccionarios exactos. Para números extremadamente grandes (como sistemas de identificación de 64 bits), GameMaker ofrece el tipo especializado int64, pero en el 99% de las mecánicas de un juego 2D tradicional se utilizan números reales estándar.
Las cadenas de texto (Strings) son secuencias de caracteres alfanuméricos encerradas obligatoriamente entre comillas dobles ("...") o simples ('...'), siendo las comillas dobles el estándar recomendado en GML. Se utilizan para nombres de personajes, mensajes de diálogo, rutas de archivos y textos de interfaz de usuario. Las cadenas se pueden concatenar (unir) utilizando el operador de adición (+). Si necesitas concatenar un número con una cadena, debes convertir explícitamente el número a texto usando la función nativa string(valor); de lo contrario, el compilador generará un error de conflicto de tipos.
Los booleanos (Booleans) representan únicamente dos estados lógicos: verdadero (true) o falso (false). En el núcleo de GameMaker, true equivale matemáticamente al número 1 (o a cualquier valor real igual o superior a 0.5) y false equivale a 0 (o cualquier valor real inferior a 0.5). A pesar de esta dualidad numérica interna, se debe utilizar siempre true y false por legibilidad sintáctica. Por último, existen identificadores especiales como undefined (indica la ausencia total de un valor asignado o un resultado no encontrado) y noone (una constante con valor numérico -4 utilizada específicamente para indicar que ninguna instancia u objeto está asociado a una variable de referencia).
| Tipo de dato | Descripción en GML | Ejemplo sintáctico | Uso común en videojuegos |
|---|---|---|---|
| Real (Número) | Enteros y decimales de coma flotante. | vida = 100; gravedad = 0.45; | Posición (x, y), velocidad, daño, temporizadores. |
| String (Texto) | Secuencias alfanuméricas entre comillas. | nombre = "Héroe"; estado = "alerta"; | Diálogos, nombres de perfil, mensajes de interfaz. |
| Boolean (Lógico) | Valores de verdad: true o false. | en_suelo = true; derrotado = false; | Interruptores de estado, banderas de colisión, habilidades activas. |
| Especiales | Constantes del motor: undefined, noone. | objetivo = noone; dato = undefined; | Referencias a instancias vacías, retornos nulos de búsqueda. |
Variables en GML: Variables de Instancia vs. Variables Locales
Una variable es un espacio reservado en la memoria de la computadora que almacena un valor susceptible de cambiar durante la ejecución del programa. Imagina una variable como una caja etiquetada: la etiqueta es el nombre que le das como programador, y el contenido es el dato actual. En GameMaker, el alcance o ámbito (scope) de una variable determina desde dónde se puede leer, modificar y cuánto tiempo perdura en la memoria RAM antes de ser eliminada. Para dominar los fundamentos de programación, es vital distinguir con precisión quirúrgica los dos ámbitos más utilizados en la lógica cotidiana: las variables de instancia y las variables locales.
Una variable de instancia pertenece de forma exclusiva a una copia específica de un objeto en la room. Se declara simplemente asignándole un nombre y un valor dentro de un evento de la instancia, habitualmente en el evento Create. Una vez declarada, la variable de instancia vive todo el tiempo que la instancia exista en la room. Cualquier evento de esa misma instancia (como Step, Draw, Destroy o eventos de teclado) puede leer y modificar su valor libremente. Por ejemplo, la salud del jugador, su velocidad horizontal o su recuento de gemas son variables de instancia, ya que deben persistir a lo largo de múltiples fotogramas y ser compartidas entre distintos eventos del mismo objeto.
Por el contrario, una variable local se declara anteponiendo la palabra clave 'var' antes de su nombre (por ejemplo: var distancia = 0;). Una variable local no pertenece al objeto ni a la instancia; pertenece única y exclusivamente al bloque de código o evento en el que fue escrita. Tan pronto como el código de ese evento específico termina de ejecutarse en el fotograma actual, la variable local es destruida de inmediato de la memoria. Si declaras una variable con 'var' en el evento Create, no podrás acceder a ella en el evento Step. Las variables locales son ideales para cálculos temporales, operaciones matemáticas intermedias que solo sirven durante una fracción de segundo o índices de control de bucles, ya que previenen el consumo innecesario de memoria y evitan llenar el objeto de variables permanentes que solo se usarán una vez.

// ---------------------------------------------------------
// OBJETO: obj_player
// EVENTO: Create
// ---------------------------------------------------------
// Variables de instancia (persisten durante toda la vida del jugador)
vida_actual = 100;
vida_maxima = 100;
velocidad_movimiento = 3.5;
monedas_oro = 0;
estado_inmune = false;
// ---------------------------------------------------------
// OBJETO: obj_player
// EVENTO: Step
// ---------------------------------------------------------
// Supongamos que el jugador recoge una poción curativa.
// Usamos variables locales (var) para calcular el efecto sin ensuciar la instancia:
var _curacion_base = 25;
var _bonificacion = 5;
var _curacion_total = _curacion_base + _bonificacion;
// Modificamos la variable de instancia usando el cálculo temporal:
vida_actual = vida_actual + _curacion_total;
// Al terminar el evento Step, _curacion_base, _bonificacion y
// _curacion_total desaparecen automáticamente de la memoria.💡 Convención profesional recomendada: Muchos programadores de GML acostumbran anteponer un guion bajo (_) al nombre de las variables locales (por ejemplo: var _distancia_x = 0;). Esto ayuda a identificar visualmente de un solo vistazo si un dato es temporal o si se trata de una variable de instancia persistente.
Operadores aritméticos y de asignación compuesta
Los operadores son símbolos matemáticos que indican al motor qué operaciones de cómputo debe realizar sobre uno o más valores (llamados operandos). En el desarrollo de videojuegos, las matemáticas no son simplemente teoría abstracta: son la fuerza que impulsa el desplazamiento en pantalla, la reducción de barras de vida, los saltos parabólicos y el cálculo de áreas de impacto. GML soporta todos los operadores aritméticos básicos habituales, junto con operadores especializados de división y residuo.
La suma (+), resta (-), multiplicación (*) y división (/) operan de forma estándar. Junto a ellas, existen dos operadores de vital relevancia para el diseño 2D: la división entera (div) y el módulo o residuo (mod o %). El operador 'div' divide dos números y descarta por completo la parte fraccionaria, devolviendo únicamente el cociente entero. Por ejemplo, 14 div 4 resulta en 3. Es sumamente útil para determinar en qué casilla de un tilemap o cuadrícula de inventario se encuentra una coordenada exacta en píxeles. Por su parte, el operador de módulo ('mod' o '%') devuelve el residuo sobrante de esa división entera. Por ejemplo, 14 mod 4 devuelve 2. Este operador es crucial para ciclar valores en bucle (por ejemplo, para que una selección de armas regrese a 0 tras superar el límite de opciones).
| Operador | Nombre | Expresión de ejemplo | Resultado final |
|---|---|---|---|
| + | Adición / Concatenación | 10 + 5 / "Hola " + "Mundo" | 15 / "Hola Mundo" |
| - | Sustracción | 20 - 7 | 13 |
| * | Multiplicación | 4 * 3.5 | 14 |
| / | División continua | 10 / 4 | 2.5 |
| div | División entera | 10 div 4 | 2 |
| mod o % | Módulo (Residuo) | 10 mod 4 | 2 |
Además de los operadores aritméticos puros, GML incluye operadores de asignación compuesta que combinan una operación aritmética con la actualización directa del valor de la variable. Escribir 'puntos += 10;' es semántica y funcionalmente idéntico a redactar 'puntos = puntos + 10;', pero de manera mucho más compacta y legible. De igual forma dispones de -=, *= y /=. Por último, para sumar o restar exactamente 1 unidad, puedes utilizar los operadores de incremento (++) y decremento (--), comúnmente empleados en contadores (por ejemplo: municion--;).
En GML rige el orden estándar de precedencia matemática: las multiplicaciones, divisiones y residuos se evalúan siempre antes que las sumas y las restas. Si necesitas alterar este orden o asegurarte de que una suma ocurra antes que una multiplicación, debes emplear paréntesis redondos obligatoriamente. Por ejemplo, 5 + 2 * 10 dará como resultado 25, mientras que (5 + 2) * 10 dará 70. En programación de juegos, ante la menor duda, agrupa siempre tus operaciones complejas entre paréntesis para evitar errores imprevistos.
Caso práctico integrado: Configuración inicial de obj_player
Para consolidar estos conceptos, continuaremos construyendo los cimientos del proyecto retro de plataformas que acompañará todo el curso. En el Módulo 2 configuramos el sprite del jugador (spr_player) y creamos el objeto correspondiente (obj_player), situándolo en la sala inicial (rm_nivel_1). Hasta este momento, la instancia permanece inmóvil. En este paso programaremos sus variables estructurales y comprobaremos cómo interactúan las variables locales y de instancia en los eventos Create y Step.
Abre el recurso 'obj_player' en tu Workspace de GameMaker. Si aún no lo has hecho, asegúrate de que tiene asignado el sprite 'spr_player'. Haz clic en el botón 'Add Event' (Añadir Evento) y selecciona el evento 'Create'. En el editor de código que se desplegará a la derecha, escribe las variables iniciales que gobernarán la fisiología y habilidades del personaje.
// ---------------------------------------------------------
// OBJETO: obj_player
// EVENTO: Create
// PROPÓSITO: Inicialización de estadísticas del personaje
// ---------------------------------------------------------
// Atributos vitales
puntos_vida_maximos = 100;
puntos_vida_actuales = puntos_vida_maximos;
estado_vivo = true;
// Movilidad base (en píxeles por fotograma)
velocidad_caminar = 4;
velocidad_carrera = 6.5;
fuerza_salto = 9;
gravedad_base = 0.35;
// Economía y progreso en el nivel
monedas_recolectadas = 0;
puntuacion_total = 0;
// Mensaje de comprobación en consola de depuración
show_debug_message("obj_player inicializado correctamente con " + string(puntos_vida_actuales) + " HP.");La función 'show_debug_message()' recibe una cadena de texto y la imprime directamente en la ventana de salida inferior (Output Console) de GameMaker. Nota cómo hemos utilizado string(puntos_vida_actuales) para convertir el número real a texto y poder unirlo al resto de la frase mediante el operador de suma (+). Esta función es la herramienta diagnóstica más rápida para comprobar el valor interno de tus variables mientras el juego corre.
A continuación, añade el evento 'Step' a 'obj_player'. Como aprendiste en el módulo previo, el evento Step se ejecuta continuamente, una vez por cada fotograma del juego (por defecto, 60 veces por segundo). En este evento realizaremos un cálculo temporal utilizando variables locales para simular la acumulación de puntos pasivos por supervivencia, aplicando operadores aritméticos.
// ---------------------------------------------------------
// OBJETO: obj_player
// EVENTO: Step
// PROPÓSITO: Lógica continua y cálculos temporales
// ---------------------------------------------------------
// Verificamos si el personaje continúa con vida
if (estado_vivo == true)
{
// Declaramos variables locales para calcular una bonificación matemática
var _tasa_puntos_segundo = 10;
var _fotogramas_por_segundo = 60;
// Puntos fraccionarios calculados para este fotograma en específico:
var _incremento_fotograma = _tasa_puntos_segundo / _fotogramas_por_segundo;
// Acumulamos el resultado en la variable de instancia usando asignación compuesta
puntuacion_total += _incremento_fotograma;
}Ejercicios prácticos
Realiza las siguientes tres actividades prácticas para consolidar la declaración sintáctica, el control de ámbitos de memoria y las operaciones numéricas en GML Code antes de pasar a las estructuras condicionales.
Resumen
- GML Code es el estándar profesional de desarrollo en GameMaker; se basa en instrucciones secuenciales que deben culminar en punto y coma (;).
- El lenguaje es dinámicamente tipado y sensible a mayúsculas y minúsculas (case-sensitive), distinguiendo números reales, cadenas de texto (strings), booleanos y constantes como noone y undefined.
- Las variables de instancia (declaradas en eventos como Create) persisten a lo largo de la existencia del objeto y son accesibles desde todos sus eventos.
- Las variables locales (declaradas mediante 'var') son volátiles: existen exclusivamente durante la ejecución del bloque de código donde nacen y son liberadas inmediatamente de la memoria RAM.
- GML ofrece operadores aritméticos estándar (+, -, *, /), división entera (div) y módulo o residuo (mod o %), esenciales para mecánicas de rejillas, inventarios y cronómetros.
- Los operadores de asignación compuesta (+=, -=, *=, /=) y los de incremento/decremento (++, --) optimizan la escritura del código.
- La función 'show_debug_message()' combinada con la conversión 'string()' es el método elemental para inspeccionar datos en la consola de depuración en tiempo real.
Practica lo aprendido
Ejercicio 1 · 1 punto
¿Qué ocurre con una variable declarada con la palabra clave 'var' en GML una vez que el evento o bloque de código donde se escribió finaliza su ejecución?
Ejercicio 2 · 1 punto
Para declarar una variable local temporal que pertenezca solo al evento actual, se antepone la palabra clave . Asimismo, si deseas concatenar un número con una cadena de texto sin generar un error de tipos, debes transformar dicho número usando la función nativa .
Ejercicio 3 · 1 punto
Relaciona cada identificador o elemento de sintaxis de GML con su definición correspondiente:
- noone
- undefined
- //
- /* ... */
Ingresa para guardar tu progreso — Ingresar