¡Hola developers! Hoy os traigo un pequeño tutorial sobre algo tan sencillo y útil como son las plataformas móviles para cualquier tipo de juego 2D. Construiremos una plataforma totalmente configurable a la que le podremos definir su tipo de movimiento (movimiento continuo o movimiento en ‘ping-pong’ con un máximo recorrido), la dirección del movimiento (horizontal, vertical o ambas) y su velocidad (tanto su velocidad vertical como su velocidad horizontal). Empecemos…

Creación del GameObject ‘PlataformaMovil’

Vamos a crear un GameObject vacío y le añadiremos los siguientes componentes:

  • BoxCollider: Será el que permitirá que nuestra plataforma sea colisionable y, por tanto, que cualquier objeto pueda posarse sobre ella.
  • SpriteRenderer: A su propiedad ‘Sprite‘ le asignaremos la imagen que queramos usar para nuestra plataforma.
GameObject 'PlataformaMovil'
GameObject ‘PlataformaMovil’

Creación del script ‘MovimientoPlataforma.cs’

Ahora vamos a crear el script que se encargará de mover la plataforma y en el que podremos configurar todos sus parámetros de movimiento, dirección y velocidad.

Comenzamos definiendo las variables públicas que luego nos interesará configurar desde el inspector y algunas variables privadas que necesitaremos:


using UnityEngine;
using System.Collections;
using System;

// Tipos enumerados para definir las direcciones
public enum DireccionH { Izquierda, Derecha }
public enum DireccionV { Arriba, Abajo }

public class MovimientoPlataforma : MonoBehaviour
{
    // Es la velocidad a la que se moverá la plataforma en el eje horizontal.
    public float VelocidadH = 0.3F;

    // Indica el sentido horizontal al que comenzará a moverse la plataforma.
    public DireccionH SentidoH = DireccionH.Derecha;

    // Es la velocidad a la que se moverá la plataforma en el eje vertical.
    public float VelocidadV = 0.0F;

    // Indica el sentido vertical al que comenzará a moverse la plataforma.
    public DireccionV SentidoV = DireccionV.Arriba;

    // Es el la distancia que recorrerá la plataforma en modo ping-pong.
    // Para desactivar el modo ping-pong, establecer esta variable a -1.
    public float MaxRecorridoPingPong = 5.0F;

    // Variables privadas
    private Transform PlatformTransform;
    private float WalkedDistanceH = 0.0F;
    private float WalkedDistanceV = 0.0F;
    private float ReferencePingPongHPosition;
    private float ReferencePingPongVPosition;
    private Vector3 InitialPlatformPosition;
}

Creamos la función Start() e inicializamos algunas variables:


    void Start ()
    {
        PlatformTransform = transform;

        // Guardamos la posición inicial de la plataforma
        InitialPlatformPosition = PlatformTransform.position;

        // Inicializamos la posición de referencia para el cálculo de rebote horizontal (ping-pong)
        ReferencePingPongHPosition = PlatformTransform.position.x;

        // Inicializamos la posición de referencia para el cálculo de rebote vertical (ping-pong)
        ReferencePingPongVPosition = PlatformTransform.position.y;
	}

Bien, ahora pasemos a la creación de la función Update(), en la que definiremos todo el comportamiento de la plataforma:


void Update ()
{
    // Calculamos la distancia horizontal recorrida desde el último rebote
    WalkedDistanceH = Math.Abs(PlatformTransform.position.x - ReferencePingPongHPosition);

    // Calculamos la distancia vertical recorrida desde el último rebote
    WalkedDistanceV = Math.Abs(PlatformTransform.position.y - ReferencePingPongVPosition);

    if (MaxRecorridoPingPong != -1 && WalkedDistanceH >= MaxRecorridoPingPong)
    {
        // Si la función de Ping-Pong esta activada y se ha hecho el máximo recorrido en horizontal, la plataforma cambia de sentido
        if (SentidoH == DireccionH.Izquierda)
        {
            SentidoH = DireccionH.Derecha;
        }
        else
        {
            SentidoH = DireccionH.Izquierda;
        }

        // Actualizamos la posición horizontal de referencia para el cálculo de rebote horizontal (ping-pong)
        ReferencePingPongHPosition = PlatformTransform.position.x;
    }

    if (MaxRecorridoPingPong != -1 && WalkedDistanceV >= MaxRecorridoPingPong)
    {
        // Si la función de Ping-Pong está activada y se ha hecho el máximo recorrido en vertical, la plataforma cambia de sentido
        if (SentidoV == DireccionV.Arriba)
        {
            SentidoV = DireccionV.Abajo;
        }
        else
        {
            SentidoV = DireccionV.Arriba;
        }

        // Actualizamos la posicion vertical de referencia para el calculo de rebote vertical (ping-pong)
        ReferencePingPongVPosition = PlatformTransform.position.y;
    }

    // Configuramos el sentido del movimiento horizontal
    if (SentidoH == DireccionH.Izquierda)
    {
        VelocidadH = -Math.Abs(VelocidadH);
    }
    else
    {
        VelocidadH = Math.Abs(VelocidadH);
    }

    // Configuramos el sentido del movimiento vertical
    if (SentidoV == DireccionV.Abajo)
    {
        VelocidadV = -Math.Abs(VelocidadV);
    }
    else
    {
        VelocidadV = Math.Abs(VelocidadV);
    }

    // Movemos la plataforma
    PlatformTransform.Translate(new Vector3(VelocidadH, VelocidadV, 0) * Time.deltaTime);
}

Con esto, nuestra plataforma ya se movería correctamente, pero seguimos teniendo un problema, y es que cuando coloquemos a nuestro personaje (o cualquier otro objeto) encima de la plataforma, éste no será transportado por ella. Este problema ocurre debido a que, cuando nuestro script mueve la plataforma, está interactuando directamente sobre su transform, es decir, está cambiando continuamente sus corrdenadas en el espacio y dichas coordenadas son independientes de las coordenadas que tienen el resto de objetos, por tanto cada objeto se rige por su propio transform. Para arreglar esto existe una solución muy sencilla y se trata de hacer que, cada vez que un objeto toque la plataforma, automáticamente pase a convertirse en hijo de ésta. De este modo, los objetos afectados pasarán de tener unas coordenadas basadas en el espacio global de la escena a tener unas coordenadas basadas en el espacio local de la plataforma, por lo cual seguirán su movimiento. Veamos cómo hacer esto:

Añadir trigger al GameObject ‘PlataformaMovil’

Lo único que debemos hacer es añadir un nuevo BoxCollider al objeto de nuestra plataforma y activar la opción IsTrigger de dicho componente. Una vez hecho esto, lo único que tenemos que hacer es ponerle a este collider un ancho y un alto adecuados para que sobresalga un poco del otro BoxCollider que definimos al principio a la plataforma (el que no es trigger), tal y como muestro en la imagen:

GameObject 'PlataformaMovil'
GameObject ‘PlataformaMovil’
Plataforma con ambos colliders: el normal y el trigger
Plataforma con ambos colliders: el normal y el trigger

Modificar el script ‘MovimientoPlataforma.cs’

Ahora deberemos implementar los eventos OnTriggerStay() y OnTriggerExit() en nuestro script de movimiento de la plataforma para indicarle que, cada vez que un objeto entre dentro del trigger que le hemos definido, lo incluya como un objeto hijo. Será tan sencillo como esto:


void OnTriggerStay(Collider other)
{
    // Incluímos como hijo de la plataforma a cualquier objeto que se pose sobre ella
    other.transform.parent = transform;
}

void OnTriggerExit(Collider other)
{
    // Excluímos como hijo de la plataforma a cualquier objeto que se separe de ella
    other.transform.parent = null;
}

Asignar el script ‘MovimientoPlataforma.cs’ al GameObject ‘PlataformaMovil’

Una vez tenemos completado nuestro script, solo nos queda asignárselo al GameObject de nuestra plataforma.

Script 'MovimientoPlataforma' asignado al GameObject
Script ‘MovimientoPlataforma’ asignado al GameObject

Y eso es todo, ya tenemos nuestra plataforma móvil lista para usarla donde queramos y cómo queramos. Éstos son los diferentes comportamientos que tendría en función de cómo configuremos las variables del script en su inspector:

  • Movimiento horizontal en ping-pong
    • VelocidadH = velocidad a la que queramos que se mueve en el eje X.
    • SentidoH = Izquierda o Derecha.
    • VelocidadV = 0.
    • SentidoV = indiferente.
    • MaxRecorridoPingPong = distancia que queramos que recorra.
  • Movimiento horizontal continuo (sin ping-pong)
    • VelocidadH = velocidad a la que queramos que se mueve en el eje X.
    • SentidoH = Izquierda o Derecha.
    • VelocidadV = 0.
    • SentidoV = indiferente.
    • MaxRecorridoPingPong = -1.
  • Movimiento vertical en ping-pong
    • VelocidadH = 0.
    • SentidoH = indiferente.
    • VelocidadV = velocidad a la que queramos que se mueve en el eje Y.
    • SentidoV = Arriba o Abajo.
    • MaxRecorridoPingPong = distancia que queramos que recorra.
  • Movimiento vertical continuo (sin ping-pong)
    • VelocidadH = 0.
    • SentidoH = indiferente.
    • VelocidadV = velocidad a la que queramos que se mueve en el eje Y.
    • SentidoV = Arriba o Abajo.
    • MaxRecorridoPingPong = -1.
  • Movimiento diagonal con ping-pong
    • VelocidadH = velocidad a la que queramos que se mueve en el eje X.
    • SentidoH = Izquierda o Derecha.
    • VelocidadV = velocidad a la que queramos que se mueve en el eje Y.
    • SentidoV = Arriba o Abajo.
    • MaxRecorridoPingPong = distancia que queramos que recorra.
  • Movimiento diagonal continuo (sin ping-pong)
    • VelocidadH = velocidad a la que queramos que se mueve en el eje X.
    • SentidoH = Izquierda o Derecha.
    • VelocidadV = velocidad a la que queramos que se mueve en el eje Y.
    • SentidoV = Arriba o Abajo.
    • MaxRecorridoPingPong = -1.

Espero que les haya gustado y os haya sido útil el tutorial. Por supuesto, cualquier comentario, duda o sugerencia será bien recibido. ¡Saludos y gracias por su atención! 😉