Introducción al Desarrollo de Videojuegos con GameMaker · Módulo 2: Sprites, objetos, eventos, instancias y rooms.
Instancias en el escenario y jerarquías
Clase 9 de 60 · 45 min
También disponible en: EN
Introducción: El molde conceptual y la entidad física en el mundo de juego
Uno de los tropiezos más comunes al iniciarse en el desarrollo con GameMaker —y en la programación orientada a videojuegos en general— radica en confundir la definición de una entidad con la entidad viva dentro de la escena. Con frecuencia se escuchan expresiones como «puse el objeto jugador en la coordenada X» o «el objeto moneda desapareció cuando lo toqué». Aunque en una conversación cotidiana se entiende la idea, en términos técnicos y de arquitectura de software, esas afirmaciones son inexactas y pueden originar errores graves de programación cuando se escriben scripts en GML (GameMaker Language). En las lecciones previas aprendiste a crear sprites e integrarlos en objetos, así como a programar comportamientos básicos en los eventos Create, Step y Destroy. Sin embargo, todo lo configurado dentro del Asset Browser representa únicamente un molde, una especificación teórica o un plano arquitectónico. El objeto, por sí mismo, no existe en el espacio de juego: no tiene una coordenada en pantalla, no consume ciclos de dibujo en el motor de renderizado ni colisiona con nada mientras permanezca guardado en el panel de recursos. Para que cobre vida, dicho molde debe materializarse dentro de un escenario (Room). Esa materialización concreta es lo que llamamos una instancia.

Distinción fundamental: Objeto vs. Instancia
Para interiorizar esta distinción de forma definitiva, podemos utilizar la analogía clásica de la pastelería o la arquitectura. Imagina un cortador de galletas de metal con silueta de estrella. El cortador define la forma, los bordes y las dimensiones ideales de la estrella, pero el cortador no es comestible ni ocupa espacio en una bandeja de horno. La masa horneada resultante de presionar el molde es la galleta real: puedes espolvorearla con azúcar, cubrirla con chocolate o comértela de un bocado sin destruir el cortador de metal. Si destruyes una galleta, el molde sigue intacto en tu cajón para hornear cientos más. En GameMaker, el recurso que creas en el Asset Browser bajo el prefijo `obj_` (por ejemplo, `obj_coin` u `obj_block`) es el cortador de galletas o el plano arquitectónico. Contiene el código fuente que dictará cómo deben comportarse las entidades creadas a partir de él, qué sprite mostrarán por defecto y a qué eventos responderán. Por otro lado, la instancia es cada una de las copias físicas e independientes que arrastras a la Room o que creas dinámicamente mediante código en tiempo de ejecución. Cada instancia ocupa un lugar específico en la memoria RAM del ordenador, posee una posición precisa (definida por sus variables internas `x` e `y`), y tiene asignado un identificador único numérico llamado `id`.
Esta separación tiene consecuencias críticas directas sobre la lógica en GML Code. Considera la siguiente situación: tienes cincuenta monedas repartidas en el nivel. Si ejecutas una instrucción que haga referencia al nombre del objeto global (`obj_coin`), podrías estar afectando a todas las monedas a la vez de forma imprevista o leyendo los datos de una de ellas de manera arbitraria. En cambio, si interactúas con la referencia a una instancia específica (su `id`), actuarás exclusivamente sobre esa moneda en particular (por ejemplo, hacer que esa única moneda explote en chispas al ser recolectada mientras las otras cuarenta y nueve continúan flotando en el escenario).
| Criterio | Objeto (Asset) | Instancia (En memoria / Room) |
|---|---|---|
| ¿Dónde reside? | En el Asset Browser (disco duro del proyecto). | En la Room activa y en la memoria RAM durante la ejecución. |
| ¿Tiene coordenadas (x, y)? | No. Es un concepto abstracto sin ubicación espacial. | Sí. Posee coordenadas absolutas `x` e `y` en píxeles. |
| Identificador | Índice del recurso (asset index, ej. `obj_player`). | Identificador único de instancia (referencia única, ej. `ref 100024`). |
| Ciclo de vida | Existe durante todo el desarrollo y compilación del juego. | Nace al cargar la Room o con `instance_create_layer()`; muere con `instance_destroy()`. |
| Modificación de variables | Modificar sus valores en el editor altera el valor predeterminado de futuras instancias. | Modificar sus variables altera únicamente esa entidad sin afectar a las demás. |
Colocación de instancias en la Room: Métodos y capas
El escenario de juego en GameMaker se denomina **Room**. Dentro de ella confluyen todos los elementos visuales y funcionales del nivel. Sin embargo, no es posible soltar elementos de manera caótica; GameMaker organiza el contenido del escenario mediante un sistema riguroso de capas (**Layers**), visible en el inspector lateral izquierdo del Room Editor. Para colocar una instancia en el escenario, la Room debe contar obligatoriamente con al menos una capa de tipo **Instance Layer** (Capas de Instancias). Por defecto, al crear una nueva Room, GameMaker genera automáticamente una capa llamada `Instances` y otra de fondo llamada `Background`. Si intentas arrastrar un objeto desde el Asset Browser hacia una capa de fondos (Background Layer) o una capa de mosaicos (Tile Layer), el editor mostrará un cursor de prohibición o bloqueará la acción, ya que esas capas no poseen la infraestructura interna para ejecutar código ni procesar eventos de ciclo de vida.
Para situar instancias con máxima precisión dentro del mundo de juego, existen varias técnicas en el Room Editor: 1. **Arrastrar y soltar clásico (Drag & Drop):** Haz clic sostenido sobre el objeto deseado dentro del Asset Browser (por ejemplo, `obj_block`) y arrástralo directamente sobre el lienzo de la Room, asegurándote de que la capa `Instances` esté seleccionada. Al soltar el botón del ratón, la instancia quedará anclada en esas coordenadas. 2. **Colocación rápida continua (Atajo Alt):** Si necesitas construir una hilera continua de suelo o una hilera de ladrillos para el videojuego de plataformas, arrastrar los objetos uno por uno resulta lento y tedioso. En GameMaker moderno, si seleccionas el objeto en el Asset Browser o en la paleta de la capa y mantienes presionada la tecla **Alt** (en Windows) u **Option** (en macOS) mientras haces clic o arrastras el cursor sobre el lienzo de la Room, estamparás instancias de forma continua como si utilizaras una brocha de pintura. 3. **Borrado rápido:** Manteniendo presionada la combinación **Alt + Clic derecho** (o seleccionando con el marco de selección y pulsando la tecla *Supr / Delete*), eliminarás inmediatamente las instancias situadas bajo el cursor sin alterar el resto de elementos del nivel.
💡 Comprobación de la rejilla (Grid): Para un juego de plataformas con estética retro, sitúa siempre la rejilla de la Room en dimensiones proporcionales a tus sprites (por ejemplo, 16x16 o 32x32 píxeles). Puedes alternar la visibilidad de la rejilla y el ajuste automático (Snap to Grid) mediante el menú superior del Room Editor. Esto evitará fisuras milimétricas entre plataformas que provocarían fallos en la detección de colisiones de tus personajes.
Propiedades individuales de las instancias en el Room Editor
Cuando una instancia ya forma parte del lienzo de la Room, deja de ser un clon estático y se convierte en una entidad parametrizable. Si haces doble clic sobre cualquier instancia colocada en el escenario, o si la seleccionas y abres la pestaña de inspección (**Inspector Panel**), accederás a sus propiedades locales e individuales. GameMaker expone un conjunto de variables internas que gobiernan el aspecto y la ubicación de esa instancia sin necesidad de alterar una sola línea de código en el objeto base. Estas variables son:
• **X e Y:** Coordenadas en píxeles dentro del plano cartesiano de la Room. En GameMaker, el origen `(0, 0)` se ubica en la esquina superior izquierda. Valores crecientes de `X` desplazan la entidad hacia la derecha; valores crecientes de `Y` la desplazan hacia abajo. • **Scale (image_xscale e image_yscale):** Multiplicadores de escala geométrica. Un valor de `1.0` representa el tamaño original del sprite en píxeles. Si estableces `image_xscale = 2.0`, la instancia duplicará su anchura. Si introduces un valor negativo, como `-1.0`, la instancia invertirá horizontalmente su orientación (efecto espejo), lo cual resulta muy útil para situar enemigos o elementos decorativos que miran hacia la izquierda desde el propio editor. • **Rotation (image_angle):** Grado de inclinación angular expresado en grados (0° a 360°), en sentido antihorario. Modificar esta propiedad en el editor rotará el sprite alrededor del origen establecido en el Sprite Editor. • **Colour Tint (image_blend):** Filtro de color de tinción aplicado sobre el sprite. Por defecto es blanco puro (`c_white` o `#FFFFFF`), lo que significa que el sprite se dibuja con sus colores originales. Si cambias el tinte de una instancia concreta de `obj_coin` a un tono rojo o púrpura, GameMaker multiplicará los canales cromáticos de esa instancia en particular, permitiéndote crear variantes visuales sin importar nuevos gráficos a la memoria. • **Alpha (image_alpha):** Nivel de opacidad que va desde `1.0` (completamente sólido y visible) hasta `0.0` (totalmente invisible y transparente).
Instance Creation Code y personalización avanzada
Modificar el aspecto físico mediante escalas o colores resulta conveniente, pero la verdadera potencia del diseño de niveles radica en modificar el **comportamiento lógico** de cada instancia individual. GameMaker ofrece dos métodos fundamentales para lograrlo: **Variable Definitions** y el **Instance Creation Code**. El **Instance Creation Code** es un bloque de script escrito en GML que se ejecuta de manera exclusiva para esa instancia en específico. Es fundamental comprender el orden cronológico en el que GameMaker inicializa una escena: cuando la Room arranca, primero se ejecuta el evento **Create** general del objeto; inmediatamente después, si esa instancia concreta tiene código en su *Creation Code*, dicho código se ejecuta, permitiendo sobreescribir las variables que se habían inicializado un instante antes en el evento Create.
Para abrir el Creation Code de una instancia, selecciónala en la Room, localiza el panel del Inspector y haz clic en el botón rotulado como **Creation Code**. Se abrirá una ventana de edición de código limpia asociada únicamente a esa entidad en la escena.
// -------------------------------------------------------------------------
// UBICACIÓN: Room Editor -> Clic en una instancia concreta de obj_moving_platform
// VENTANA: Instance Creation Code
// PROPÓSITO: Sobrescribir variables de patrullaje para esta plataforma específica
// -------------------------------------------------------------------------
// Por defecto, en el Create Event de obj_moving_platform definimos:
// move_speed = 2;
// travel_distance = 64;
// Aquí, para esta plataforma en particular situada en un abismo ancho:
move_speed = 3.5;
travel_distance = 256;
horizontal_direction = -1; // Comienza moviéndose hacia la izquierdaLa ventaja de este mecanismo es evidente: no necesitas crear diez objetos distintos en el Asset Browser (`obj_plataforma_rapida`, `obj_plataforma_lenta`, `obj_plataforma_larga`). Creas un único objeto arquitectónico genérico (`obj_moving_platform`), y personalizas su comportamiento en el mapa mediante parámetros individuales en cada nivel.
Jerarquías y herencia: El sistema de Objetos Padre e Hijo (Parenting)
A medida que el proyecto de plataformas 2D crece, la cantidad de objetos se multiplica rápidamente. Muy pronto tendrás bloques de piedra, bloques de ladrillo rompible, plataformas de madera, bloques interrogantes de recompensa y plataformas flotantes. Si el personaje principal debe colisionar y apoyarse sobre todos ellos, ¿significa que debemos programar un bloque de colisión individual para cada clase de bloque existente en el proyecto? La respuesta es un rotundo no. Si repitieras el código de colisiones para cada bloque individual, violarías el principio elemental de desarrollo de software conocido como DRY (*Don't Repeat Yourself* / No te repitas). Si en el futuro decides modificar la velocidad de caída o la física del personaje, tendrías que revisar y modificar decenas de eventos idénticos dispersos en múltiples objetos, lo que inevitablemente introduce errores y dificulta el mantenimiento del juego. Para resolver esto, GameMaker incorpora una de las herramientas más elegantes y potentes de la programación: el sistema de **Parenting** (Objetos Padre e Hijo o Herencia).
El funcionamiento del Parenting se fundamenta en una regla taxonómica: «Todo Hijo es también de la familia del Padre». Cuando conviertes un objeto en **Hijo** de otro, el hijo hereda de forma automática: 1. Todos los eventos y líneas de código programadas en el objeto Padre. 2. Las variables y definiciones configuradas en el Padre. 3. La capacidad de ser detectado en funciones de colisión cuando se pregunta por el Padre. Por ejemplo, si creas un objeto sin sprite llamado `obj_solid_parent` (Padre de sólidos), y luego en las propiedades de `obj_block`, `obj_stone` y `obj_wood_platform` asignas como su *Parent* a `obj_solid_parent`, el motor tratará a todos ellos como miembros de la categoría `obj_solid_parent`.
// -------------------------------------------------------------------------
// UBICACIÓN: obj_player -> Event: Step
// PROPÓSITO: Comprobar colisión sólida unificada gracias a la herencia
// -------------------------------------------------------------------------
// En lugar de verificar individualmente con múltiples condiciones:
// if (place_meeting(x, y + 1, obj_block) || place_meeting(x, y + 1, obj_stone) ...)
// Verificamos únicamente contra el Padre de todos los sólidos:
if (place_meeting(x, y + 1, obj_solid_parent))
{
// El jugador está tocando cualquier superficie sólida del juego,
// ya sea un ladrillo, un bloque de piedra o una plataforma flotante.
is_grounded = true;
}
else
{
is_grounded = false;
}Sobrescritura de eventos y la función event_inherited()
Un comportamiento clave de la herencia es la **sobrescritura** (overriding). Si un objeto Padre tiene código en su evento Create, y el objeto Hijo no define ningún evento Create, el hijo ejecutará fielmente el código del padre sin hacer nada especial. Sin embargo, en el instante en que creas un evento Create propio dentro del Hijo, GameMaker asume que deseas ignorar el código del Padre para sustituirlo por el tuyo. En la mayoría de las ocasiones, no quieres sustituir el comportamiento del padre, sino **complementarlo**: deseas que el hijo ejecute toda la rutina básica del padre y, adicionalmente, ejecute una lógica particular propia. Para lograr esto sin duplicar código, GML provee la instrucción `event_inherited()`.
// -------------------------------------------------------------------------
// UBICACIÓN: obj_parent_hazard -> Event: Create
// PROPÓSITO: Inicializar propiedades universales de cualquier peligro del juego
// -------------------------------------------------------------------------
damage_amount = 1;
knockback_force = 4;
is_active = true;Ahora observa cómo configuramos un obstáculo específico, como un pozo de lava o pinchos venenosos (`obj_spikes`), que hereda de `obj_parent_hazard` pero necesita variables adicionales:
// -------------------------------------------------------------------------
// UBICACIÓN: obj_spikes (Hijo de obj_parent_hazard) -> Event: Create
// PROPÓSITO: Heredar la base del padre y añadir personalización propia
// -------------------------------------------------------------------------
// 1. Ejecutar íntegramente el Create Event de obj_parent_hazard:
event_inherited();
// 2. Personalizar o añadir propiedades específicas de este peligro:
damage_amount = 2; // Los pinchos causan más daño que el peligro estándar
poison_duration = 60; // Variable exclusiva que no poseen otros peligrosCaso práctico en el proyecto de plataformas: Bloques y peligros
Apliquemos todo lo aprendido en la estructura de nuestro videojuego de plataformas retro. Vamos a organizar la jerarquía básica para que los niveles contengan terrenos sólidos consistentes y elementos dañinos sin desordenar el proyecto. Sigue estos pasos ordenados dentro de GameMaker: 1. **Creación de padres estructurales:** En el Asset Browser, dentro de la carpeta `Objects`, crea un nuevo objeto llamado `obj_solid_parent`. No le asignes sprite. Marca su casilla como *Visible: false* (ya que será solo un contenedor lógico). Este objeto no necesita eventos propios por ahora. 2. **Creación de objetos sólidos derivados:** Crea `obj_block` con el sprite de ladrillos retro `spr_block`, y crea `obj_stone` con el sprite de piedra `spr_stone`. En ambos objetos, abre la sección **Parent** en el panel de propiedades del objeto y selecciona `obj_solid_parent`. 3. **Creación de la jerarquía de peligros:** Crea un objeto vacío llamado `obj_hazard_parent`. Añade en su evento Create las variables `damage_value = 1;` y `can_damage = true;`. 4. **Creación de pinchos (`obj_spikes`):** Asígnale su sprite `spr_spikes`. Configura su Parent como `obj_hazard_parent`. No necesitas escribir código en su Create a menos que desees modificar los daños base.
Ejercicios prácticos
Lleva a cabo las siguientes tres actividades prácticas para afianzar el dominio espacial de la Room y la arquitectura de jerarquías en tu proyecto de plataformas:
Resumen
- Un Objeto es una plantilla o plano conceptual almacenado en el Asset Browser; una Instancia es la copia física y activa con coordenadas e identidad propia dentro de una Room.
- Las instancias deben colocarse siempre dentro de capas compatibles de tipo 'Instance Layer'; arrastrarlas a capas de fondos o mosaicos está restringido por el motor.
- El atajo 'Alt' (u 'Option' en macOS) en el Room Editor permite pintar instancias de forma continua, acelerando la creación de escenarios y plataformas.
- Cada instancia en el escenario posee variables locales inherentes como x, y, image_xscale, image_yscale, image_angle, image_blend e image_alpha, accesibles desde el Inspector.
- El Instance Creation Code se ejecuta inmediatamente después del evento Create de la instancia, permitiendo sobreescribir valores de variables para esa copia concreta en ese nivel.
- El sistema de Parenting (Herencia) permite agrupar objetos bajo ancestros comunes (como obj_solid_parent), simplificando drásticamente las comprobaciones de colisión.
- La instrucción event_inherited() permite que un objeto hijo ejecute el código de su evento ancestro antes de aplicar modificaciones o variables exclusivas.
Practica lo aprendido
Ejercicio 1 · 1 punto
Dentro de la arquitectura de GameMaker, el funciona como el molde o plano conceptual sin coordenadas en pantalla, mientras que la es la copia concreta materializada en el escenario que posee memoria, posición y un identificador propio.
Ejercicio 2 · 1 punto
¿Qué sucede si intentas arrastrar un objeto desde el Asset Browser hacia una capa de tipo Background Layer o Tile Layer en el Room Editor?
Ejercicio 3 · 1 punto
Empareja cada propiedad o variable interna de una instancia con su efecto o función en el Room Editor:
- image_xscale con valor -1.0
- image_alpha con valor 0.0
- image_blend
- id
Ingresa para guardar tu progreso — Ingresar