Link

Enemigo2

Enemigo

Vamos a crear un enemigo que ataque y reste vida al jugador. Utilizaremos los sprites del paquete Dungeon Escape, en concreto los relativos a la araña.

Paso 1: Patrulla

El enemigo se moverá del punto A al punto B, por lo que en el script deberemos de definir dos variables SerializedField de tipo Transform.

[SerializeField] private Transform pointA, pointB;

El en juego posiciona dos GameObject con únicamente el transform que nos servirán de puntos para la patrulla.

Imagen

Es necesario que el punto A en el escenario coincida en la posición X, Y, Z con la posición inicial del GameObject del enemigo. Arrastra el punto A y el punto B a los campos dentro del editor para obtener sus posiciones desde el script.

Imagen

Se pretende que el enemigo se mueva entre los dos puntos:

private Vector3 currentTarget;

public virtual void Movement()
{
    // Si estamos en el punto A vamos al B y viceversa
    if (transform.position == pointA.position)
    {
        currentTarget = pointB.position;
        // No rotamos el objeto
        transform.localRotation = Quaternion.Euler(0, 0, 0);
    }
    else if (transform.position == pointB.position)
    {
        currentTarget = pointA.position;
        // Rotamos el objeto en el eje y 180 grados
        transform.localRotation = Quaternion.Euler(0, 180, 0);
    }
    // Movimiento a currentTarget
    transform.position = Vector2.MoveTowards(transform.position, currentTarget, velocidad * Time.deltaTime);
}

Con este método se puede mover el enemigo al punto currentTarget, cambiando este punto según llegue al punto A o B.

También es necesario crear las animaciones de patrulla y ataque como mínimo. Por último añade un collider y ajústalo al inicio del ataque de la animación. Será el área de daño del ataque.

Imagen

Desactiva el collider y ponlo en modo trigger.

Imagen

Paso 2: Ajuste de la animación

Debemos de ajustar la animación del ataque con el collider que hará colisión con nuestro personaje. Para ello debemos empezar a grabar la animación de ataque y activar el collider. Además deberemos de hacer que durante la animación se adapte más o menos al área deseada.

Imagen

Paso 3: Ataque cuando se detecta al personaje

Primeramente, debemos de comprobar siempre a la distancia que está el personaje. Para ello asignamos el tag Player a jugador:

Imagen

Y referenciamos el objeto dentro del script del personaje:

player = GameObject.FindGameObjectWithTag("Player");

public virtual void Update()
{
   // Obtenemos la distancia entre objetos, personaje y el actual enemigo
    Debug.Log(Vector2.Distance(player.transform.localPosition, transform.localPosition));
    Movement();
}

Calculada la distancia podemos escoger cuando atacar al jugador.

Imagen

Ahora necesitamos organizar las animaciones. Necesitamos un parámetro boolean para pasar de una a otra:

Imagen

Ya está casi todo listo, simplemente cuando estemos cerca del personaje lanzamos la animación y no se mueve:

public virtual void Movement()
{
  // Si está cerca ataca y no se mueve
  if (distance <= attackRange)
  {
      anim.SetBool("attacking", true);
  }
  else
  {
      // Movimiento a currentTarget cuando no ataca
      transform.position = Vector2.MoveTowards(transform.position, currentTarget, speed * Time.deltaTime);
  }
}

Imagen

Paso 4: Detectar el ataque

Una forma sencilla de registrar el daño es mediante un método público en algún script que controle la vida del jugador. Al principio del script tenemos referenciado al Player por lo que podemos acceder a cualquier elemento de sus componentes. Por ejemplo, si añadimos en el Enemigo la detección de la colisión:

private void OnTriggerEnter2D(Collider2D other)
{
    // Referencia al objeto jugador
    Comprobar_suelo script_jugador = player.GetComponent<Comprobar_suelo>();
    // Llamada al método de jugador
    script_jugador.danyo("araña");
}

Y en el script del jugador:

public void danyo(string atacante)
{
    Debug.Log("Me ha dañado un" + atacante);
}

Pero hay un problema, la colisión se detecta por cada frame, por lo que en un mismo ataque nuestro personaje recibirá más ataques de los que debiera. Para esto podemos implementar corutinas que nos permiten añadir un delay en el código:

// Coroutine que permite cambiar el valor de la variable cada hitDelay
IEnumerator damagePause()
{
    // Este código se ejecutará durante varios frames hasta que pase el tiempo
    yield return new WaitForSeconds(hitDelay);
    // Ha pasado el tiempo definido, se ejecuta la siguiente línea
    canDamage = true;
}

Y modificamos el OnTriggerEnter2D() para utilizar la coroutine:

private void OnTriggerEnter2D(Collider2D other)
{
    // Referencia al objeto jugador
    Comprobar_suelo script_jugador = player.GetComponent<Comprobar_suelo>();
    // Llamada al método de jugador
    script_jugador.danyo("araña");
    // Pausa entre daños en los ataques
    canDamage = false;
    damagePause();
}