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

Física básica de plataformas en 2D, parte 3

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Basic 2D Platformer Physics .
Basic 2D Platformer Physics, Part 2
Basic 2D Platformer Physics, Part 4

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

Plataformas de una vía

Ya que acabamos de terminar de trabajar en el control de colisión en el suelo, también podríamos agregar plataformas de un solo sentido mientras estamos en ello. Solo se referirán al control de colisión de tierra. Las plataformas unidireccionales difieren de los bloques sólidos en que detendrán un objeto solo si se cae. Además, también permitiremos que un personaje descienda de dicha plataforma.

En primer lugar, cuando queremos dejar una plataforma de un solo sentido, básicamente queremos ignorar la colisión con el suelo. Una manera fácil de hacerlo aquí es configurar una compensación, después de pasar, que el personaje u objeto ya no colisionará con una plataforma.

Por ejemplo, si el personaje ya está dos píxeles debajo de la parte superior de la plataforma, ya no debería detectar una colisión. En ese caso, cuando queremos dejar la plataforma, todo lo que tenemos que hacer es mover el personaje dos píxeles hacia abajo. Vamos a crear esta constante de desplazamiento.

Ahora agreguemos una variable que nos dirá si un objeto se encuentra actualmente en una plataforma unidireccional.

Modifiquemos la definición de la función HasGround para tomar también una referencia a un booleano que se establecerá si el objeto ha aterrizado en una plataforma unidireccional.

Ahora, después de comprobar si el mosaico en el que nos encontramos actualmente es un obstáculo, y no lo es, debemos verificar si se trata de una plataforma de un solo sentido.

Como se explicó anteriormente, también debemos asegurarnos de que esta colisión se ignore si hemos caído más allá del cOneWayPlatformThreshold debajo de la plataforma.

Por supuesto, no podemos simplemente comparar la diferencia entre la parte superior del mosaico y el sensor, porque es fácil imaginar que incluso si estamos cayendo, podríamos estar muy por debajo de dos píxeles desde la parte superior de la plataforma. Para que las plataformas de un solo sentido detenga un objeto, queremos que la distancia del sensor entre la parte superior del mosaico y el sensor sea menor o igual que el cOneWayPlatformThreshold más el desplazamiento desde la posición de este marco al anterior.

Finalmente, hay una cosa más a considerar. Cuando encontramos una plataforma unidireccional, no podemos salir del ciclo, porque hay situaciones en las que el personaje está parcialmente en una plataforma y parcialmente en un bloque sólido.

Realmente no deberíamos considerar tal posición como "en una plataforma de un solo sentido", porque realmente no podemos descender desde allí, el bloque sólido nos está deteniendo. Es por eso que primero tenemos que seguir buscando un bloque sólido, y si se encuentra uno antes de que devolvamos el resultado, también debemos configurar onOneWayPlatform como falso.

Ahora, si revisamos todos los mosaicos que necesitamos verificar horizontalmente y encontramos una plataforma unidireccional pero no bloques sólidos, entonces podemos estar seguros de que estamos en una plataforma unidireccional desde la cual podemos desplegar.

Eso es todo, así que ahora agreguemos a la clase de personaje una opción para desplegar la plataforma. Tanto en el estado stand como en el run, necesitamos agregar el siguiente código.

Vamos a ver cómo funciona.

Todo funciona correctamente

Manejar colisiones para el techo

Necesitamos crear una función análoga al HasGround para cada lado de la AABB, así que comencemos con el techo. Las diferencias son las siguientes:

  • La línea del sensor está por encima de la AABB en lugar de estar debajo de ella
  • Comprobamos que no haya azulejos en el techo de abajo hacia arriba, ya que estamos avanzando
  • No es necesario manejar plataformas de una sola dirección

Aquí está la función modificada.

Manejar colisiones para el muro izquierdo

De manera similar a la forma en que manejamos el control de colisión para el techo y la tierra, también necesitamos verificar si el objeto choca con la pared de la izquierda o la pared de la derecha. Comencemos desde la pared izquierda. La idea aquí es más o menos la misma, pero hay algunas diferencias:

  • La línea del sensor está en el lado izquierdo de la AABB.
  • El ciclo for interno necesita iterar a través de los mosaicos verticalmente, porque el sensor ahora es una línea vertical.    
  • El bucle externo necesita iterar a través de los mosaicos horizontalmente para ver si no nos hemos saltado una pared cuando nos movemos con una gran velocidad horizontal.

Manejar colisiones para el muro derecho

Finalmente, creemos la función CollidesWithRightWall, que como se puede imaginar, hará algo muy similar a CollidesWithLeftWall, pero en lugar de usar un sensor a la izquierda, usaremos un sensor en el lado derecho del personaje.

La otra diferencia aquí es que en lugar de revisar las fichas de derecha a izquierda, las revisaremos de izquierda a derecha, ya que esa es la dirección de movimiento asumida.

Mueva el objeto fuera de la colisión

Todas nuestras funciones de detección de colisiones están listas, así que utilicémoslas para completar la respuesta de colisión contra el mapa de mosaico. Sin embargo, antes de hacer eso, tenemos que determinar el orden en que vamos a verificar las colisiones. Consideremos las siguientes situaciones.

En ambas situaciones, podemos ver que el personaje terminó superponiéndose con un mosaico, pero necesitamos descubrir cómo deberíamos resolver la superposición.

La situación de la izquierda es bastante simple: podemos ver que estamos cayendo directamente hacia abajo, y por eso definitivamente debemos aterrizar en la parte superior de la cuadra.

La situación de la derecha es un poco más complicada, ya que en realidad podríamos aterrizar en la misma esquina de la losa, y empujar al personaje hacia la cima es tan razonable como empujarlo hacia la derecha. Elegimos priorizar el movimiento horizontal. En realidad, no importa mucho qué alineación deseamos hacer primero; Ambas opciones se ven correctas en acción.

Vayamos a nuestra función UpdatePhysics y agreguemos las variables que contendrán los resultados de nuestras consultas de colisión.

Ahora comencemos mirando si debemos mover el objeto hacia la derecha. Las condiciones aquí son que:

  • la velocidad horizontal es menor o igual a cero
  • colisionamos con la pared izquierda
  • en el cuadro anterior no nos superpusimos con el mosaico en el eje horizontal, una situación similar a la de la derecha en la imagen de arriba

La última es una condición necesaria, porque si no se cumpliera, estaríamos ante una situación similar a la de la izquierda en la imagen de arriba, en la que seguramente no deberíamos mover al personaje hacia la derecha.

Si las condiciones son verdaderas, tenemos que alinear el lado izquierdo de nuestra AABB con el lado derecho de la loseta, asegurarnos de que dejamos de mover hacia la izquierda, y marcar que estamos al lado de la pared de la izquierda.

Si alguna de las condiciones además de la última es falsa, necesitamos establecer mPushesLeftWall en falso. Eso es porque la última condición que es falsa no necesariamente nos dice que el personaje no está empujando la pared, pero a la inversa, nos dice que ya estaba colisionando con ella en el cuadro anterior. Debido a esto, es mejor cambiar mPushesLeftWall a falso solo si alguna de las dos primeras condiciones también es falsa.

Ahora revisemos la colisión con la pared derecha.

Como puede ver, es la misma fórmula que utilizamos para verificar la colisión con la pared izquierda, pero reflejada.

Ya tenemos el código para verificar la colisión con el suelo, así que después de eso necesitamos verificar la colisión con el techo. Aquí tampoco hay nada nuevo, además no necesitamos hacer ningún control adicional, excepto que la velocidad vertical debe ser mayor o igual a cero y en realidad colisionamos con un mosaico que está encima de nosotros.

Redondea las esquinas

Antes de probar si las respuestas de colisión funcionan, hay una cosa más importante que hacer, que es redondear los valores de las esquinas que calculamos para las comprobaciones de colisión. Necesitamos hacer eso, de modo que nuestras comprobaciones no sean destruidas por errores de coma flotante, que pueden provenir de una posición extraña del mapa, una escala de caracteres o simplemente un tamaño extraño de AABB.

Primero, para nuestra comodidad, creemos una función que transforma un vector de flotadores en un vector de flotadores redondeados.

Ahora usemos esta función en cada prueba de colisión. Primero, arreglemos la función HasCeiling.

El siguiente es OnGround.

PushesRightWall.

Y finalmente, PushesLeftWall.

¡Eso debería resolver nuestros problemas!

Verifica los resultados

Eso va a ser todo. Vamos a probar cómo están funcionando nuestras colisiones ahora.

Resumen

¡Eso es todo por esta parte! Tenemos un conjunto de colisiones de mapas de mosaico totalmente funcional, que debería ser muy confiable. Sabemos en qué posición se encuentra el objeto actualmente: si está en el suelo, tocando un azulejo a la izquierda o a la derecha, o chocando un techo. También implementamos plataformas de una vía, que son una herramienta muy importante en todos los juegos de plataformas.

En la siguiente parte, agregaremos mecánicas para agarrar salientes, lo que aumentará aún más el posible movimiento del personaje, ¡así que estad atentos!

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.