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.
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.
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.
Desactiva el collider y ponlo en modo trigger
.
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.
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
:
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.
Ahora necesitamos organizar las animaciones. Necesitamos un parámetro boolean
para pasar de una a otra:
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);
}
}
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();
}