How do I deal with collisions in GameMaker?

Dominando position_meeting en GameMaker

31/07/2020

Valoración: 4.3 (1336 votos)

El desarrollo de videojuegos es un arte de interacciones, y en el corazón de casi toda interacción se encuentra un sistema de colisiones. GameMaker ofrece un arsenal de funciones para detectar cuándo dos cosas se tocan, se superponen o interactúan. Desde el simple evento de colisión hasta complejas listas de instancias dentro de una forma, cada función tiene su propósito. Hoy nos sumergiremos en una de las herramientas más precisas y, a menudo, subestimadas de este arsenal: position_meeting(). Esta función no se preocupa por el tamaño de tu personaje o si toda su área choca con algo; se enfoca en una pregunta mucho más simple y poderosa: ¿hay algo en este punto exacto?

Índice de Contenido

El Ecosistema de Colisiones de GameMaker

Antes de analizar position_meeting() en detalle, es útil entender dónde encaja dentro del gran esquema de las colisiones en GameMaker. Las funciones se pueden agrupar por su complejidad y lo que devuelven, lo que nos da una visión clara de qué herramienta usar para cada trabajo.

What does position_meeting() do?
position_meeting () checks if a single point/pixel in the room is colliding with an instance of an object. Just like place_meeting (), it returns true or false. instance_place () and instance_position () are both the same as place_meeting () and position_meeting ().
Clasificación General de Funciones de Colisión
CategoríaFunción PrincipalCompruebaResultado
Básica (Booleana)place_meeting()Instancia vs. Instanciatrue / false
Básica (Booleana)position_meeting()Punto vs. Instanciatrue / false
Básica (ID de Instancia)instance_place()Instancia vs. InstanciaID de Instancia o noone
Básica (ID de Instancia)instance_position()Punto vs. InstanciaID de Instancia o noone
Intermedia (Formas)collision_circle(), collision_rectangle(), etc.Forma vs. InstanciaID de Instancia o noone
Avanzada (Listas)instance_place_list(), collision_circle_list(), etc.Instancia/Forma vs. Múltiples InstanciasNúmero de instancias y llena una lista con sus IDs

Como podemos ver, position_meeting() se encuentra en la categoría básica, pero su especialización en verificar un solo punto la hace indispensable para ciertas tareas que otras funciones manejan de forma menos eficiente.

Anatomía de `position_meeting()`

La función es engañosamente simple en su estructura, pero su poder reside en su precisión. La sintaxis es la siguiente:

position_meeting(x, y, obj);

Desglosemos sus argumentos:

  • x: La coordenada X en la habitación que deseas comprobar.
  • y: La coordenada Y en la habitación que deseas comprobar.
  • obj: El objeto o la instancia con la que quieres comprobar la colisión. Puedes usar un índice de objeto (como obj_Wall), un ID de instancia específico, o incluso las palabras clave especiales como all (todos los objetos) u other (en un evento de colisión).

El resultado de esta función es un valor booleano: devuelve true o false. Si en las coordenadas (x, y) que has especificado existe la máscara de colisión de una instancia del objeto obj, la función devolverá true. Si no hay nada en ese píxel exacto, devolverá false.

La Gran Diferencia: `position_meeting()` vs. `place_meeting()`

Una de las mayores fuentes de confusión para los desarrolladores que empiezan es la diferencia entre position_meeting() y su prima cercana, place_meeting(). Ambas devuelven true o false, pero lo que comprueban es fundamentalmente distinto.

  • place_meeting(x, y, obj) pregunta: "Si muevo la instancia que está ejecutando este código a la posición (x, y), ¿su máscara de colisión se superpondría con la máscara de una instancia de obj?"
  • position_meeting(x, y, obj) pregunta: "¿Está el punto exacto (x, y) dentro de la máscara de colisión de alguna instancia de obj?"

Imagina que tu personaje es un cuadrado. Con place_meeting, mueves todo el cuadrado a una nueva posición para ver si choca. Con position_meeting, es como si extendieras un dedo para tocar un solo píxel en la pantalla y preguntar si ese píxel pertenece a un muro.

Tabla Comparativa Rápida

Característicaposition_meeting()place_meeting()
Qué compruebaUn único punto (píxel) contra una máscara de instancia.La máscara de la instancia actual contra otra máscara de instancia.
ContextoIndependiente de la instancia que ejecuta el código.Relativo a la instancia que ejecuta el código.
Uso ComúnClics del ratón, disparos de tipo "raycast" simple, comprobaciones de sensores puntuales.Movimiento basado en colisiones (evitar paredes), comprobar si el personaje está en el suelo.

Aplicaciones Prácticas y Ejemplos de Código

La teoría está muy bien, pero veamos dónde brilla realmente position_meeting().

What is OBJ_ground in GameMaker?
For each of your ground objects, define obj_ground as their parent. This means that every time you reference obj_ground, you check both! Look up parent and child in the user manual, it is one of the tools that makes GameMaker so good. I am to understand that ground1 and ground2 are your 2 types of walkable objects.

1. Interacciones con el Ratón

Este es el caso de uso por excelencia. Si quieres saber si el jugador está haciendo clic en un botón o en un objeto interactivo, position_meeting() es tu mejor aliado.

// En el evento Step de un objeto 'obj_Button' if (position_meeting(mouse_x, mouse_y, id)) { // El cursor del ratón está sobre esta instancia del botón image_index = 1; // Cambiar al sprite de "resaltado" if (mouse_check_button_pressed(mb_left)) { // El jugador ha hecho clic en el botón // Ejecutar la acción del botón aquí } } else { image_index = 0; // Volver al sprite normal }

2. Detección de Impactos Precisos

Imagina una bala que se mueve muy rápido. En lugar de usar una máscara de colisión grande, puedes simplemente comprobar el punto exacto donde terminará en el siguiente fotograma.

// En el evento Step de un objeto 'obj_Bullet' var _target_x = x + lengthdir_x(speed, direction); var _target_y = y + lengthdir_y(speed, direction); if (position_meeting(_target_x, _target_y, obj_Enemy)) { // La bala está a punto de golpear a un enemigo en el siguiente paso // Aquí podrías obtener la instancia con instance_position y dañarla var _enemy_hit = instance_position(_target_x, _target_y, obj_Enemy); if (_enemy_hit != noone) { _enemy_hit.hp -= damage; instance_destroy(); // Destruir la bala } } else { // Mover la bala si no hay colisión x = _target_x; y = _target_y; }

3. Sensores para Inteligencia Artificial

Un enemigo puede usar position_meeting() para "sondear" su entorno. Por ejemplo, para comprobar si hay un obstáculo justo delante antes de moverse.

// En el evento Step de un objeto 'obj_Guard' // Comprobar un punto 20 píxeles delante del guardia var _check_x = x + lengthdir_x(20, direction); var _check_y = y + lengthdir_y(20, direction); if (position_meeting(_check_x, _check_y, obj_Wall)) { // Hay una pared delante, ¡gira! direction += 90; } else { // Camino despejado, avanza speed = 2; }

Más Allá del Booleano: `instance_position()`

A veces, saber que has chocado con *algo* no es suficiente; necesitas saber exactamente *con qué* has chocado para poder interactuar con ello. Aquí es donde entra en juego instance_position(). Funciona exactamente igual que position_meeting(), pero con una diferencia crucial en lo que devuelve:

  • position_meeting() devuelve true o false.
  • instance_position() devuelve el ID único de la primera instancia encontrada en ese punto, o la palabra clave especial noone si no se encuentra ninguna.

Esto te permite obtener una referencia directa a la instancia con la que has colisionado y modificar sus variables, llamarla en otras funciones o destruirla. El ejemplo de la bala anterior ya lo utiliza para aplicar daño al enemigo específico que fue golpeado.

Preguntas Frecuentes (FAQ)

P: ¿Funciona `position_meeting` con mapas de tiles (Tilemaps)?
R: ¡Sí! Puedes pasar el ID de un elemento de mapa de tiles (obtenido con layer_tilemap_get_id()) en lugar de un ID de objeto. La función comprobará si el punto especificado colisiona con cualquier tile en ese mapa que tenga una máscara de colisión asignada.
P: Mi llamada a `position_meeting()` siempre devuelve `false`, ¿por qué?
R: Hay varias causas comunes: 1) Asegúrate de que las coordenadas que estás comprobando son correctas. 2) Verifica que el objeto con el que intentas colisionar tiene una máscara de colisión válida y visible en el editor de sprites. 3) Comprueba que una instancia del objeto realmente existe en la habitación en la posición que estás verificando. 4) Si usas máscaras precisas, asegúrate de que el punto cae sobre un píxel opaco del sprite, no en una parte transparente.
P: ¿Puedo comprobar la colisión con varios tipos de objetos a la vez?
R: La forma más eficiente de hacerlo es crear un objeto padre (por ejemplo, obj_Solid) y asignarlo como padre a todos los objetos que quieres comprobar (obj_Wall, obj_Crate, etc.). Luego, simplemente haces una llamada: position_meeting(x, y, obj_Solid). Esto comprobará la colisión con el padre y todos sus hijos.
P: ¿Es `position_meeting` una función costosa en términos de rendimiento?
R: No, es una de las funciones de colisión más rápidas y eficientes que ofrece GameMaker porque la lógica de comprobar un solo punto contra una máscara es muy simple para el procesador. Es mucho más ligera que las comprobaciones basadas en formas complejas o listas.

Conclusión

Aunque a primera vista pueda parecer limitada, position_meeting() es una herramienta de una precisión quirúrgica. Es la elección perfecta cuando el contexto de la colisión no depende de un área, sino de un punto singular. Desde la interfaz de usuario hasta la balística y la IA, dominar esta función te abrirá nuevas vías para crear mecánicas de juego limpias, eficientes y receptivas. La próxima vez que necesites saber si algo está exactamente *aquí*, sabrás exactamente qué función llamar.

Si quieres conocer otros artículos parecidos a Dominando position_meeting en GameMaker puedes visitar la categoría Guías.

Subir