Flash Sale! Up to 40% off on unlimited courses, tutorials and creative asset downloads Up to 40% off on unlimited assets SAVE NOW
Advertisement
  1. Game Development
  2. Platformer
Gamedevelopment

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

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

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

Colision de personajes

De acuerdo, la premisa es la siguiente: queremos hacer una plataforma en 2D con física simple, robusta, sensible, precisa y predecible. No queremos usar un gran motor de física 2D en este caso, y hay algunas razones para esto:

  • respuestas de colisión impredecibles
  • difícil de configurar movimientos de carácter precisos y robustos
  • mucho más complicado para trabajar
  • toma mucho más poder de procesamiento que la física simple

Por supuesto, también hay muchos pros en el uso de un motor de física disponible en el mercado, como ser capaz de configurar complejas interacciones físicas con bastante facilidad, pero eso no es lo que necesitamos para nuestro juego.

Un motor de física personalizado ayuda al juego a tener una sensación personalizada, ¡y eso es ealmente importante! Incluso si va a comenzar con una configuración relativamente básica, la forma en que las cosas se moverán e interactuarán entre sí siempre estará influenciada por sus propias reglas solamente, en lugar de las de los demás. ¡Hagámoslo!

Límites del Carácter

Comencemos por definir qué tipo de formas utilizaremos en nuestra física. Una de las formas más básicas que podemos usar para representar un objeto físico en un juego es un cuadro delimitador alineado del eje (AABB). AABB es básicamente un rectángulo no girado.

Example of an AABB

En muchos juegos de plataformas, los AABB son suficientes para aproximarse al cuerpo de cada objeto en el juego. Son extremadamente efectivos, porque es muy fácil calcular una superposición entre las AABB y requiere muy pocos datos: para describir una AABB, es suficiente conocer su centro y tamaño.

Sin más preámbulos, creemos una estructura para nuestra AABB.

Como se mencionó anteriormente, todo lo que necesitamos aquí en lo que se refiere a los datos son dos vectores; el primero será el centro de AABB, y el segundo el de la mitad. ¿Por qué medio? La mayoría de las veces, para los cálculos, necesitaremos la mitad del tamaño de todos modos, así que, en lugar de calcularlo cada vez, simplemente lo memorizaremos en lugar del tamaño completo.

Comencemos agregando un constructor, por lo que es posible crear la estructura con parámetros personalizados.

Con esto podemos crear las funciones de comprobación de colisión. Primero, hagamos una simple comprobación de si dos AABB colisionan entre sí. Esto es muy simple: solo necesitamos ver si la distancia entre los centros en cada eje es menor que la suma de la mitad de los tamaños.

Aquí hay una imagen que demuestra esta comprobación en el eje x; el eje y se verifica de la misma manera.

Demonstrating a check on the X-Axis

Como puede ver, si la suma de los tamaños medios fuera menor que la distancia entre los centros, no sería posible la superposición. Tenga en cuenta que en el código anterior, podemos evitar la comprobación de colisión anticipadamente si encontramos que los objetos no se superponen en el primer eje. La superposición debe existir en ambos ejes, si las AABB deben colisionar en el espacio 2D.

Objeto en movimiento

Comencemos creando una clase para un objeto que esté influenciado por la física del juego. Más tarde, usaremos esto como base para un objeto jugador real. Llamemos a esta clase MovingObject.

Ahora completemos esta clase con los datos. Necesitaremos mucha información para este objeto:

  • Posición y posición del cuadro anterior
  • Velocidad y velocidad del cuadro anterior
  • escala
  • AABB y un desplazamiento para él (para que podamos alinearlo con un sprite)
  • es un objeto en el suelo y si estaba en el suelo último cuadro
  • es un objeto al lado de la pared a la izquierda y si estaba al lado del último cuadro
  • es un objeto al lado de la pared a la derecha y si estaba al lado del último cuadro
  • es objeto en el techo y si estaba en el último techo

La posición, la velocidad y la escala son vectores en 2D.

Ahora agreguemos el AABB y el desplazamiento. El desplazamiento es necesario para que podamos hacer coincidir libremente el AABB con el objeto del objeto.

Y, finalmente, declaremos las variables que indican el estado de posición del objeto, ya sea en el suelo, junto a una pared o en el techo. Estos son muy importantes porque nos dejarán saber si podemos saltar o, por ejemplo, necesitamos reproducir un sonido después de chocar contra una pared.

Estos son los básicos. Ahora, creemos una función que actualizará el objeto. Por ahora no vamos a configurar todo, solo lo suficiente para que podamos comenzar a crear controles básicos de caracteres.

Lo primero que querremos hacer aquí es guardar los datos del cuadro anterior en las variables apropiadas.

Ahora actualicemos la posición usando la velocidad actual.

Y solo por ahora, hagámoslo de modo que si la posición vertical es menor que cero, supongamos que el personaje está en el suelo. Esto es solo por ahora, así que podemos configurar los controles del personaje. Más adelante, haremos una colisión con un mapa de mosaico.

Después de esto, también necesitamos actualizar el centro de AABB, de modo que coincida con la nueva posición.

Para el proyecto de demostración, estoy usando Unity, y para actualizar la posición del objeto que se debe aplicar al componente de transformación, así que hagámoslo también. Lo mismo debe hacerse para la escala.

Como puede ver, la posición renderizada se redondea hacia arriba. Esto es para asegurarse de que el personaje renderizado siempre se ajuste a un píxel.

Controles de personaje

Datos

Ahora que tenemos nuestra clase básica MoveObject, podemos comenzar jugando con el movimiento del personaje. Después de todo, es una parte muy importante del juego, y se puede hacer de inmediato, sin necesidad de profundizar demasiado en los sistemas de juego, y estará listo cuando tengamos que probar nuestro carácter. colisiones de mapas.

Primero, creemos una clase de personaje y la derivamos de la clase MovingObject.

Tendremos que manejar algunas cosas aquí. Antes que nada, las entradas: hagamos una enumeración que cubra todos los controles del personaje. Vamos a crearlo en otro archivo y llamarlo KeyInput.

Como puede ver, nuestro personaje puede moverse hacia la izquierda, derecha, abajo y saltar hacia arriba. Desplazarnos hacia abajo solo funcionará en plataformas unidireccionales, cuando queremos pasar por encima de ellas.

Ahora declaremos dos matrices en la clase Character, una para las entradas del cuadro actual y otra para las del cuadro anterior. Dependiendo de un juego, esta configuración puede tener más o menos sentido. Normalmente, en lugar de guardar el estado de la clave en una matriz, se comprueba a demanda utilizando las funciones específicas de un motor o estructura. Sin embargo, tener una matriz que no esté estrictamente ligada a la entrada real puede ser beneficioso, por ejemplo, si queremos simular pulsaciones de teclas.

Estas matrices serán indexadas por KeyInput enum. Para usar fácilmente esas matrices, creemos algunas funciones que nos ayuden a verificar una clave específica.

Aquí no hay nada especial: queremos poder ver si se presionó una tecla, si se lanzó, o si está encendida o apagada.

Ahora creemos otra enumeración que contendrá todos los estados posibles del personaje.

Como puede ver, nuestro personaje puede quedarse quieto, caminar, saltar o agarrarse a una repisa. Ahora que ya está hecho, necesitamos agregar variables como la velocidad de salto, la velocidad de desplazamiento y el estado actual.

Por supuesto, se necesitan más datos aquí, como el sprite del personaje, pero cómo se verá esto depende mucho del tipo de motor que vayas a usar. Como estoy usando Unity, usaré una referencia a un Animator para asegurarme de que el sprite reproduce la animación para un estado apropiado.

Actualizar Ciclo

Bien, ahora podemos comenzar a trabajar en el ciclo de actualización. Lo que haremos aquí dependerá del estado actual del personaje.

Estado "Detenido"

Comencemos completando lo que se debe hacer cuando el personaje no se está moviendo, en el estado parado. En primer lugar, la velocidad debe establecerse en cero.

También queremos mostrar el sprite apropiado para el estado.

Ahora, si el personaje no está en el suelo, ya no puede mantenerse, así que tenemos que cambiar el estado para saltar.

Si se presiona la tecla GoLeft o GoRight, tendremos que cambiar nuestro estado para caminar.

En caso de que se presione la tecla Jump, queremos establecer la velocidad vertical a la velocidad de salto y cambiar el estado para saltar.

Eso va a ser todo para este estado, al menos por ahora.

Estado caminata

Ahora vamos a crear una lógica para movernos en el suelo y comenzar a reproducir la animación caminando.

Aquí, si no presionamos el botón izquierdo o derecho o ambos se presionan, queremos volver al estado fijo.

Si se presiona la tecla GoRight, debemos establecer la velocidad horizontal en mWalkSpeed y asegurarnos de que el sprite se escala apropiadamente; la escala horizontal debe cambiarse si queremos voltear el sprite horizontalmente.

También debemos movernos solo si no hay ningún obstáculo adelante, por lo que si mPushesRightWall se establece en verdadero, entonces la velocidad horizontal se debe establecer en cero si nos movemos hacia la derecha.

También tenemos que manejar el lado izquierdo de la misma manera.

Como hicimos para el estado parado, necesitamos ver si se presiona un botón de salto, y establecer la velocidad vertical si es así.

De lo contrario, si el personaje no está en el suelo, entonces necesita cambiar el estado para saltar también, pero sin agregar velocidad vertical, por lo que simplemente se cae.

Eso es todo para caminar. Pasemos al estado de salto.

Estado de Salto

Comencemos configurando una animación apropiada para el sprite.

En el estado Jump, necesitamos agregar gravedad a la velocidad del personaje, por lo que va más y más rápido hacia el suelo.

Pero sería sensato agregar un límite, por lo que el personaje no puede caer demasiado rápido.

En muchos juegos, cuando el personaje está en el aire, la maniobrabilidad disminuye, pero vamos a buscar controles muy simples y precisos que permitan una flexibilidad total en el aire. Entonces, si presionamos la tecla GoLeft o GoRight, el personaje se mueve en la dirección mientras salta tan rápido como lo haría si estuviera en el suelo. En este caso, simplemente podemos copiar la lógica de movimiento desde el estado de caminar.

Finalmente, haremos el salto más alto si el botón de salto se presiona más. Para hacer esto, lo que realmente haremos es bajar el salto si no se presiona el botón de salto.

Como puede ver, si no se presiona la tecla de salto y la velocidad vertical es positiva, ajustamos la velocidad al valor máximo cMinJumpSpeed ​​ (200 píxeles por segundo). Esto significa que si tocáramos simplemente el botón de salto, la velocidad del salto, en lugar de ser igual a mJumpSpeed ​​(410 por defecto), bajará a 200, y por lo tanto el salto será más corto.

Como todavía no tenemos ninguna geometría de nivel, debemos omitir la implementación de GrabLedge por el momento.

Actualice las Entradas Previas

Una vez que el marco está terminado, podemos actualizar las entradas anteriores. Vamos a crear una nueva función para esto. Todo lo que tendremos que hacer aquí es mover los valores de estado de la clave de la matriz mInputs a la matriz mPrevInputs.

Al final de la función CharacterUpdate, todavía tenemos que hacer un par de cosas. El primero es actualizar la física.

Ahora que la física está actualizada, podemos ver si deberíamos reproducir cualquier sonido. Queremos reproducir un sonido cuando el personaje golpea cualquier superficie, pero en este momento solo puede tocar el suelo porque la colisión con mosaicos aún no está implementada.

Comprobemos si el personaje acaba de caer al suelo. Es muy fácil hacerlo con la configuración actual; solo tenemos que buscar si el personaje está en el suelo en este momento, pero no estaba en el cuadro anterior.

Finalmente, actualicemos las entradas anteriores.

Con todo, así es como debe verse ahora la función CharacterUpdate, con pequeñas diferencias según el tipo de motor o marco que esté utilizando.

Inicia el personaje

Vamos a escribir una función Init para el personaje. Esta función tomará las matrices de entrada como los parámetros. Los suministraremos de la clase de administrador más adelante. Aparte de esto, tenemos que hacer cosas como:

  • asignar la escala
  • asignar la velocidad de salto
  • asignar la velocidad de caminata
  • establecer la posición inicial
  • establecer el AABB

Aquí utilizaremos algunas de las constantes definidas.

En el caso de la demostración, podemos establecer la posición inicial a la posición en el editor.

Para AABB, necesitamos establecer el desplazamiento y el medio tamaño. El desplazamiento en el caso del sprite de la demostración debe ser de la mitad del tamaño.

Ahora podemos ocuparnos del resto de las variables.

Necesitamos llamar a esta función desde el administrador del juego. El administrador puede configurarse de muchas maneras, todas dependiendo de las herramientas que esté usando, pero en general la idea es la misma. En el inicio del administrador, necesitamos crear las matrices de entrada, crear un jugador e iniciarlo.

Además, en la actualización del administrador, necesitamos actualizar las entradas del jugador y del jugador.

Tenga en cuenta que actualizamos la física del personaje en la actualización fija. Esto asegurará que los saltos siempre tengan la misma altura, sin importar la velocidad de fotogramas con la que trabaje nuestro juego. Hay un excelente artículo de Glenn Fiedler sobre cómo solucionar el paso del tiempo, en caso de que no estés usando Unity.

Pruebe el controlador de caracteres

En este punto, podemos probar el movimiento del personaje y ver cómo se siente. Si no nos gusta, siempre podemos cambiar los parámetros o la forma en que se cambia la velocidad al presionar las teclas.

An animation of the character controller

Resumen

Los controles de los personajes pueden parecer muy ligeros y no tan agradables como un movimiento basado en el impulso para algunos, pero esto es todo una cuestión de qué tipo de controles se adaptan mejor a tu juego. Afortunadamente, simplemente cambiar la forma en que se mueve el personaje es bastante fácil; es suficiente para modificar cómo cambia el valor de velocidad en los estados de caminata y salto.

Eso es todo por la primera parte de la serie. Hemos terminado con un esquema de movimiento de personajes simple, pero no mucho más. Lo más importante es que preparamos el camino para la siguiente parte, en la que haremos que el personaje interactúe con un mapa de mosaicos.

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.