Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Game Development
  2. Game Physics
Gamedevelopment

Física básica de plataformas en 2D, parte 6: Respuesta de colisión entre objetos

by
Difficulty:BeginnerLength:LongLanguages:
This post is part of a series called Basic 2D Platformer Physics .
Basic 2D Platformer Physics, Part 5: Object vs. Object Collision Detection
Basic 2D Platformer Physics, Part 7: Slopes Groundwork

Spanish (Español) translation by Elías Nicolás (you can also view the original English article)

En la entrega anterior de la serie, implementamos un mecanismo de detección de colisión entre los objetos del juego. En esta parte, usaremos el mecanismo de detección de colisión para construir una respuesta física simple pero robusta entre los objetos.

La demostración muestra el resultado final de este tutorial. Usa WASD para mover el personaje. El botón central del mouse genera una plataforma unidireccional, el botón derecho del mouse engendra un mosaico sólido y la barra espaciadora genera un clon de caracteres. Los controles deslizantes cambian el tamaño del personaje del jugador.

La demostración se publicó bajo Unity 5.4.0f3 y el código fuente también es compatible con esta versión de Unity.

Respuesta de colisión

Ahora que tenemos todos los datos de colisión del trabajo que hemos realizado en la parte anterior, podemos agregar una respuesta simple a los objetos en colisión. Nuestro objetivo aquí es hacer posible que los objetos no se atraviesen como si estuvieran en un plano diferente; queremos que sean sólidos y actúen como un obstáculo o una plataforma para otros objetos. Para eso, tenemos que hacer una sola cosa: mover el objeto de una superposición, si ocurre.

Cubra los Datos Adicionales

Necesitaremos algunos datos adicionales para la clase MovingObject para manejar la respuesta objeto contra objeto. Antes que nada, es bueno tener un booleano para marcar un objeto como cinemático, es decir, este objeto no será empujado por ningún otro objeto.

Estos objetos funcionarán bien como plataformas, y también pueden ser plataformas móviles. Se supone que son las cosas más pesadas, por lo que su posición no se corregirá de ninguna manera; otros objetos necesitarán alejarse para dejar espacio para ellos.

Los otros datos que me gustaría tener son información sobre si estamos parados sobre un objeto o hacia su lado izquierdo o derecho, etc. Hasta ahora solo podíamos interactuar con los mosaicos, pero ahora también podemos interactuar con otros objetos.

Para traer algo de armonía a esto, necesitaremos un nuevo conjunto de variables que describan si el personaje está empujando algo a la izquierda, derecha, arriba o abajo.

Ahora son muchas variables. En un entorno de producción, valdría la pena convertirlos en banderas y tener un solo entero en lugar de todos estos booleanos, pero en aras de la simplicidad manejaremos estos como están.

Como puede notar, aquí tenemos datos bastante precisos. Sabemos si el personaje empuja o empuja un obstáculo en una dirección particular en general, pero también podemos preguntar fácilmente si estamos al lado de un azulejo o un objeto.

Salir de la superposición

Vamos a crear la función UpdatePhysicsResponse, en la que manejaremos la respuesta objeto contra objeto.

En primer lugar, si el objeto está marcado como cinemático, simplemente volvemos. No manejamos la respuesta porque el objeto cinemático no necesita responder a ningún otro objeto; los otros objetos necesitan responder a él.

Ahora, esto supone que no necesitaremos un objeto cinemático para tener los datos correctos con respecto a si está empujando un objeto en el lado izquierdo, etc. Si ese no es el caso, entonces tendría que modificarse un poco, lo que profundizare más adelante.

Ahora comencemos a manejar las variables que acabamos de declarar recientemente.

Guardamos los resultados del cuadro anterior en las variables apropiadas y por ahora suponemos que no estamos tocando ningún otro objeto.

Comencemos iterando a través de todos nuestros datos de colisión ahora.

Primero, manejemos los casos en que los objetos apenas se tocan entre sí, sin superponerse realmente. En este caso, sabemos que realmente no tenemos que mover nada, solo establecemos las variables.

Como se mencionó anteriormente, el indicador de que los objetos se están tocando es que la superposición en uno de los ejes es igual a 0. Comencemos por verificar el eje x.

Si la condición es verdadera, necesitamos ver si el otro objeto está en el lado izquierdo o derecho de nuestra AABB.

Finalmente, si está a la derecha, configure mPushesRightObject en true y configure la velocidad para que no sea mayor que 0, porque nuestro objeto ya no puede moverse hacia la derecha ya que la ruta está bloqueada.

Manejemos el lado izquierdo de la misma manera.

Finalmente, sabemos que no necesitaremos hacer nada más aquí, así que continuemos con la siguiente iteración de bucle.

Manejemos el eje y de la misma manera.

Este es también un buen lugar para establecer las variables para un cuerpo cinemático, si es que necesitamos hacerlo. No nos importaría si la superposición es igual a cero o no, porque de todos modos no vamos a mover un objeto cinemático. También necesitaríamos omitir el ajuste de velocidad ya que no queremos detener un objeto cinemático. Sin embargo, omitiremos hacer todo esto para la demostración, ya que no vamos a usar las variables auxiliares para objetos cinemáticos.

Ahora que está cubierto, podemos manejar los objetos que se han superpuesto correctamente con nuestra AABB. Sin embargo, antes de hacer eso, permítanme explicar el enfoque que tomé para la respuesta de colisión en la demostración.

En primer lugar, si el objeto no se mueve y nos topamos con él, el otro objeto no se moverá. Lo tratamos como un cuerpo cinemático. Decidí ir por este camino porque creo que es más genérico, y el comportamiento de empuje siempre se puede manejar más adelante en la actualización personalizada de un objeto en particular.

When we bump into another object the other object should not move

Si ambos objetos se movieron durante la colisión, dividimos la superposición entre ellos en función de su velocidad. Cuanto más rápido iban, la mayor parte del valor de superposición se reubicaría.

El último punto es que, de forma similar al enfoque de respuesta de mapa de mosaico, si un objeto se cae y mientras baja rasguña otro objeto incluso en un píxel horizontalmente, el objeto no se deslizará y continuará hacia abajo, sino que se colocará en ese píxel.

When we bump into another object the other object should not move even if its coming vertically

Creo que este es el enfoque más maleable, y modificarlo no debería ser muy difícil si quieres manejar alguna respuesta de manera diferente.

Continuemos la implementación calculando el vector de velocidad absoluta para ambos objetos durante la colisión. También necesitaremos la suma de las velocidades, así que sabemos qué porcentaje de la superposición se debe mover nuestro objeto.

Tenga en cuenta que en lugar de usar la velocidad guardada en los datos de colisión, estamos utilizando el desplazamiento entre la posición en el momento de la colisión y el marco anterior a eso. Esto será más preciso en este caso, ya que la velocidad representa el vector de movimiento antes de la corrección física. Las posiciones mismas se corrigen si el objeto ha golpeado un azulejo sólido, por ejemplo, así que si queremos obtener un vector de velocidad corregido debemos calcularlo así.

Ahora comencemos a calcular la relación de velocidad para nuestro objeto. Si el otro objeto es cinemático, estableceremos la relación de velocidad en uno, para asegurarnos de mover todo el vector de superposición, respetando la regla de que el objeto cinemático no debe moverse.

Ahora comencemos con un caso extraño en el que ambos objetos se superponen pero ninguno tiene velocidad alguna. En realidad, esto no debería suceder, pero si un objeto se genera superponiendo otro objeto, nos gustaría que se separen de forma natural. En ese caso, nos gustaría que ambos se muevan en un 50% del vector de superposición.

Otro caso es cuando speedSum en el eje x es igual a cero. En ese caso calculamos la relación adecuada para el eje y, y establecemos que debemos mover el 50% de la superposición para el eje x.

Del mismo modo, manejamos el caso en el que speedSum es cero solo en el eje y, y para el último caso calculamos ambas proporciones adecuadamente.

Ahora que se calculan las relaciones, podemos ver cuánto necesitamos para compensar nuestro objeto.

Ahora, antes de decidir si debemos mover el objeto fuera de la colisión en el eje x o el eje y, calculemos la dirección desde la cual ocurrió la superposición. Hay tres posibilidades: o nos topamos con otro objeto horizontal, vertical o diagonalmente.

En el primer caso, queremos salir de la superposición en el eje x, en el segundo caso queremos salir de la superposición en el eje y, y en el último caso, queremos salir de la superposición en cualquiera de los dos; eje tenía la menor superposición.

Looking at our paths coming from each direction

Recuerde que para superponer con otro objeto necesitamos que las AABB se superpongan entre sí en los ejes xey. Para comprobar si chocamos con un objeto horizontalmente, veremos si el marco anterior ya estaba superponiendo el objeto en el eje y. Si ese es el caso, y no hemos estado superponiendo en el eje x, entonces la superposición debe haber sucedido porque en el marco actual las AABB comenzaron a superponerse en el eje x, y por lo tanto deducimos que tropezamos con otro objeto horizontalmente.

Primero, calculemos si nos superpusimos con la otra AABB en el cuadro anterior.

Ahora configuremos la condición para salir de la superposición horizontalmente. Como se explicó anteriormente, necesitábamos haber superpuesto en el eje Y y no superpuesto en el eje x en el cuadro anterior.

Si ese no es el caso, saldremos de la superposición en el eje y.

Como se mencionó anteriormente, también tenemos que cubrir el escenario de toparse con el objeto diagonalmente. Chocamos con el objeto en diagonal si nuestras AABB no se superponían en el cuadro anterior en ninguno de los ejes, porque sabemos que en el cuadro actual se superponen en ambos, por lo que la colisión debe haber sucedido en ambos ejes simultáneamente.

Pero queremos salir de la superposición en el eje en caso de una protuberancia diagonal solo si la superposición en el eje x es menor que la superposición en el eje y.

Eso es todos los casos resueltos. Ahora realmente necesitamos mover el objeto de la superposición.

Como puede ver, lo manejamos de manera muy similar al caso en que apenas tocamos otra AABB, pero adicionalmente movemos nuestro objeto por la compensación calculada.

La corrección vertical se realiza de la misma manera.

Eso es casi todo; solo hay una advertencia más que cubrir. Imagine el escenario en el que aterrizamos en dos objetos simultáneamente. Tenemos dos instancias de datos de colisión casi idénticas. A medida que iteramos a través de todas las colisiones, corregimos la posición de la colisión con el primer objeto, moviéndonos un poco hacia arriba.

Luego, manejamos la colisión para el segundo objeto. La superposición guardada en el momento de la colisión ya no está actualizada, como ya nos hemos movido desde la posición original, y si tuviéramos que manejar la segunda colisión de la misma manera que manejamos la primera, volveríamos a subir un poco , haciendo que nuestro objeto sea corregido el doble de la distancia que se suponía que debía.

Vertically landing on a group of objects

Para solucionar este problema, realizaremos un seguimiento de cuánto hemos corregido ya el objeto. Declaremos el vector offsetSum justo antes de comenzar a iterar a través de todas las colisiones.

Ahora, asegurémonos de sumar todas las compensaciones que aplicamos a nuestro objeto en este vector.

Y, por último, vamos a compensar la superposición de cada colisión consecutiva por el vector acumulativo de correcciones que hemos realizado hasta ahora.

Ahora si aterrizamos en dos objetos de la misma altura al mismo tiempo, la primera colisión se procesará correctamente y la superposición de la segunda colisión se compensaría a cero, lo que ya no movería nuestro objeto.

Vertically landing on a group of objects

Ahora que nuestra función está lista, asegurémonos de usarla. Un buen lugar para llamar a esta función sería después de la llamada CheckCollisions. Esto requerirá que dividamos nuestra función UpdatePhysics en dos partes, así que vamos a crear la segunda parte ahora mismo, en la clase MovingObject.

En la segunda parte llamamos a nuestra función UpdatePhysicsResponse recién terminada y actualizamos las variables generales izquierda, derecha, inferior y superior. Después de esto, solo tenemos que aplicar el puesto.

Ahora, en el ciclo de actualización del juego principal, llamemos a la segunda parte de la actualización de física después de la llamada a CheckCollisions.

¡Hecho! Ahora nuestros objetos no pueden superponerse entre sí. Por supuesto, en una configuración de juego tendríamos que agregar algunas cosas como grupos de colisión, etc., por lo que no es obligatorio detectar o responder a una colisión con cada objeto, pero estos son elementos que dependen de cómo desee tener las cosas establecidas en su juego, por lo que no vamos a profundizar en eso.

Resumen

Eso es todo por otra parte de la simple serie de física de plataformas 2D. Hicimos uso del mecanismo de detección de colisión implementado en la parte anterior para crear una respuesta física simple entre los objetos.

Con estas herramientas, es posible crear objetos estándar, como plataformas móviles, bloques de empuje, obstáculos personalizados y muchos otros tipos de objetos que no pueden ser parte del mapa de mosaicos, pero que aún deben formar parte del terreno nivelado de alguna manera. Hay una característica más que nuestra implementación de la física aún no tiene, y esas son las pendientes.

Esperemos que en la siguiente parte comencemos a ampliar nuestro mapa de mosaicos con el soporte para estos, que completaría el conjunto básico de características que debería tener una implementación de física sencilla para un juego de plataformas en 2D, y eso terminaría con la serie.

Por supuesto, siempre hay margen de mejora, así que si tienes alguna pregunta o consejo sobre cómo hacer algo mejor, o simplemente tienes una opinión sobre el tutorial, ¡no dudes en utilizar la sección de comentarios para avisarme!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.