Para inaugurar mi nuevo blog he querido hacer un pequeño tutorial básico sobre algo que he estado implementando actualmente para mi proyecto y que creo que es utilizado en muchísimos juegos de tipo plataformas 2D. Se trata de crear un sencillo sistema de ataque a distancia (por ejemplo lanzar shurikens) en el que podamos configurar tanto su dirección como su velocidad y que, asignado al GameObject de nuestro personaje y pulsando un botón de ataque, podamos lanzar un arma capaz de interactuar con el escenario (por ejemplo dañar a los enemigos). Para centrarnos en la realización de esta mecánica en concreto vamos a suponer que ya contamos con un GameObject que representa a nuestro personaje principal y el cual ya tiene su correspondiente script controlador (en nuestro caso lo llamaremos «PlayerController.cs«) encargado de implementar las acciones básicas del personaje como por ejemplo su movimiento.

Aclaración: En este post, cuando hago uso el término «Shuriken«, en ningún momento me estoy refiriendo al sistema de partículas de Unity, sino simplemente a un tipo de arma arrojadiza comúnmente utilizada por los ninjas que en este caso he usado de ejemplo, pero el sistema es igualmente aplicable para armas de tipo balas, flechas o cualquier otra cosa que so os ocurra 😀 Para evitar confusiones, aquí dejo su definición: shuriken.

Creación del GameObject ‘Shuriken’

Vamos a empezar por crear un nuevo GameObject vacío y que representará a nuestro shuriken. A continuación le añadiremos los siguientes componentes:

  • SphereCollider: nos aseguraremos de que le activaremos su propiedad ‘IsTrigger‘. En mi caso he escogido un collider de tipo esfera ya que es el que mejor se amolda a mi caso concreto, pero se podría usar cualquier otro tipo de collider como por ejemplo un BoxCollider.
  • Rigidbody: debido a que nuestra arma podrá ser configurada para moverse a altas velocidades, recomiendo establecer su propiedad ‘Collision Detection‘ a ‘Continuous‘ para una mejor detección de colisiones.
GameObject 'Shuriken'
GameObject ‘Shuriken’

Una vez creado este GameObject, vamos a añadirle como objeto hijo un GameObject que representará el sprite referente a nuestro shuriken. Este objeto sólo contendrá el componente ‘SpriteRenderer‘ con la imagen que queramos usar para nuestra arma.

Sub GameObject 'SpriteShuriken'
Sub GameObject ‘SpriteShuriken’
Sprite del shuriken
Sprite del shuriken

Aclaración: El motivo por el cual he usado un objeto hijo independiente para el sprite del shuriken, en vez de añadir directamente el componente ‘SpriteRenderer‘ en el objeto padre, es que siempre es mejor hacerlo así por si después decidimos crearle animaciones y no queremos que afecten al transform de nuestro objeto padre.

Creación del script ‘ArmaArrojadiza.cs’

Ahora vamos a crear el script que se encargará de controlar el comportamiento de nuestro shuriken. En este caso, el comportamiento que he implementado para cuando nuestro shuriken colisione con algo ha sido algo tan simple como comprobar que si la colisión se produce contra un enemigo (presuponemos que nuestros enemigos tienen el tag «Enemigo«), entonces decrementamos en 1 el número de vidas de dicho enemigo. Iré comentando lo que hace todo el script en el mismo código:


using UnityEngine;
using System.Collections;

//Creamos un tipo enumerado para definir la dirección
public enum Direccion { Horizontal, Vertical }

public class ArmaArrojadiza : MonoBehaviour
{
   //Variables públicas
   public Direccion DireccionArma = Direccion.Horizontal;
   public float Velocidad = 50.0F;

   //Variables privadas
   private Rigidbody thisRigidbody;

   void Start ()
   {
      thisRigidbody = GetComponent<Rigidbody>();
   }

   void Update ()
   {
      //Establecemos su velocidad y su dirección
      if (DireccionArma == Direccion.Horizontal)
      {
         //Movemos el arma en horizontal
         thisRigidbody.transform.Translate(new Vector3(Velocidad, 0, 0) * Time.deltaTime);
      }
      else
      {
         //Movemos el arma en vertical
         thisRigidbody.transform.Translate(new Vector3(0, Velocidad, 0) * Time.deltaTime);
      }
   }

   void OnTriggerEnter(Collider other)
   {
      if (other.tag == "Enemigo")
      {
         //Si el ataque colisiona contra un objeto con el tag 'Enemigo', se decrementan las vidas de dicho enemigo
         other.gameObject.GetComponent<ComportamientoEnemigo>().Vidas--;

         //Destruimos el objeto cuando colisione contra un enemigo
         Destroy(gameObject);
      }
   }
}

Aclaración: Damos por supuesta la existencia del script «ComportamientoEnemigo» asociado a cada enemigo que tendrá una variable pública llamada «Vidas» (de tipo ‘int’) donde se almacenará el número de vidas que le queden a dicho enemigo.

Asignar el script ‘ArmaArrojadiza.cs’ al GameObject ‘Shuriken’

Una vez tenemos implementado nuestro script, se lo asignamos al GameObject de nuestro shuriken.

Script 'ArmaArrojadiza.cs' asignado en el GameObject 'Shuriken'
Script ‘ArmaArrojadiza.cs’ asignado en el GameObject ‘Shuriken’

Creación del prefab ‘Shuriken’

Ya tenemos construido por completo el objeto que representará a nuestro shuriken, lo que haremos ahora será simplemente crear un prefab de éste simplemente arrastrando el objeto desde nuestra vista de Hierarchy a la carpeta de prefabs de nuestro proyecto.

Lanzar shurikens desde el jugador

Ya que tenemos preparado nuestro prefab ‘Shuriken’, solo nos faltaría hacer que nuestro jugador, a través de la pulsación de un botón de disparo, sea capaz de lanzar shurikens en cualquiera de las 4 direcciones (arriba, abajo, izquierda o derecha). Para ello modificaremos su script ‘PlayerController.cs‘ que, como dije al principio, suponemos que ya tiene asignado el objeto de nuestro personaje.


using UnityEngine;
using System.Collections;
using System;

public class PlayerController : MonoBehaviour
{
   //Creamos una variable pública donde asignar nuestro prefab 'Shuriken'
   public GameObject ShurikenPrefab;

   void Update ()
   {
      //Si pulsamos el botón 'Fire1'...
      if (ShurikenPrefab != null && Input.GetButtonDown("Fire1"))
      {
         //Accedemos al script 'ArmaArrojadiza.cs' del prefab
         ArmaArrojadiza scriptShuriken = ShurikenPrefab.GetComponent<ArmaArrojadiza>();

         if (Input.GetAxis("Vertical") > 0)
         {
            //Ataque hacia arriba
            scriptShuriken.DireccionArma = Direccion.Vertical;
            scriptShuriken.Velocidad = Math.Abs(scriptShuriken.Velocidad);
         }
         else if (Input.GetAxis("Vertical") < 0)
         {
            //Ataque hacia abajo
            scriptShuriken.DireccionArma = Direccion.Vertical;
            scriptShuriken.Velocidad = -Math.Abs(scriptShuriken.Velocidad);
         }
         else if (Input.GetAxis("Horizontal") > 0)
         {
            //Ataque hacia la derecha
            scriptShuriken.DireccionArma = Direccion.Horizontal;
            scriptShuriken.Velocidad = Math.Abs(scriptShuriken.Velocidad);
         }
         else if (Input.GetAxis("Horizontal") < 0)
         {
            //Ataque hacia la izquierda
            scriptShuriken.DireccionArma = Direccion.Horizontal;
            scriptShuriken.Velocidad = -Math.Abs(scriptShuriken.Velocidad);
         }

         //Creamos una instancia del prefab en nuestra escena, concretamente en la posición de nuestro personaje
         Instantiate(ShurikenPrefab, transform.position, Quaternion.identity);
      }
   }
}

Una última mejora

Tal y como está montado ahora mismo, el sistema de ataque funciona, pero ¿qué ocurre si lanzamos un shuriken y éste no colisiona con ningún enemigo?… pues que seguirá avanzando hasta el infinito y ese GameObject nunca será destruido, por tanto ocuparía memoria y si llegamos a lanzar muchos shurikens podría ser catastrófico para el rendimiento del juego. Para solucionar esto haremos uso de un evento que nos proporciona Unity llamado OnBecameInvisible(), lo he descubierto hace poco y me parece maravilloso. El evento funciona nivel de un objeto que contenga un SpriteRenderer y lo que hace es ejecutar el código que le escribamos dentro cuando el objeto salga del ángulo de visión de nuestra cámara. Entonces, para hacer uso de esto, vamos a crearnos un nuevo script llamado «ShurikenDestroyer.cs» y se lo asignaremos al objeto hijo de nuestro prefab (el que contiene el componente ‘SpriteRenderer‘). Aquí el código del script:


using UnityEngine;
using System.Collections;

public class ShurikenDestroyer : MonoBehaviour
{
   void OnBecameInvisible ()
   {
      //Destruimos el objeto padre cuando salga fuera de la pantalla
      Destroy(transform.parent.gameObject);
   }
}

De este modo, cuando cualquiera de nuestros shurikens salgan de la pantalla, serán destruidos automáticamente.

¡Pues eso es todo amigos! El resultado final será que, cada vez que el jugador pulse el botón «Fire1», se disparará un shuriken en la dirección que estemos pulsando. Recordemos que la velocidad del shuriken puede ser configurada cuando queramos desde el prefab. A continuación os muestro una captura del resultado final en mi proyecto:

Resultado final
Resultado final

Espero que os haya gustado mi primera publicación sobre desarrollo en Unity3D y que, sobre todo, ¡os haya sido útil! 😉 Cualquier comentario o duda ya saben que pueden escribirme en la sección de comentarios del post, ¡muchas gracias y saludos!