- NavMesh agent
- Enemy movement
- Enemy Shooting
Enemy movement
In this part of tutorial, we will use NavMeshAgent. This component is attached to a mobile character in the game to allow it to navigate the Scene using the NavMesh.
The NavMesh is a class can be used to do spatial queries, like pathfinding and walkability tests, set the pathfinding cost for specific area types, and to tweak global behavior of pathfinding and avoidance.
In Start method, we need to initialize the target property (The player gameObject), the navMeshagent speed and acceleration and finally the animator controller.
void Start()
{
AttackingPlayer = false;
target = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
animator = GetComponent<Animator>();
agent.speed = Speed;
agent.acceleration = 150;
}
The Update method contains the enemy movement logic:
it is necessary to calculate the distance between the enemy and the player. If it is superior to the distance of attack, it means that the enemy has not arrived yet to the player, otherwise it has arrived well and must carry out a attack action.
We check every time the enemy’s heath, it it’s greater than 0. In the other case, the health less then or equal to 0, which means enemy has dead.
In this case, we set the navMeshAgent speed and acceleration to 0.
it’s not just that, Setting the navMeshAgent destination to the current position of enemy, in order to fix it at the last position in which it has dead.
The Update method looks like this:
void Update()
{
if(Health > 0)
{
animator.SetBool("IsWalking", true);
animator.SetBool("IsAttaking", false);
if (Vector3.Distance(transform.position, target.position) > AttackingDistance)
{
animator.SetBool("IsAttaking", false);
agent.SetDestination(target.position);
AttackingPlayer = false;
}
else
{
animator.SetBool("IsAttaking", true);
AttackingPlayer = true;
if(attakingCountDown <=0)
{
// TODO Update Player Health.
attakingCountDown = 1f / AttakingRate;
}
attakingCountDown -= Time.deltaTime;
}
}
else
{
agent.speed = 0;
agent.acceleration = 0;
agent.angularSpeed = 0;
animator.SetBool("IsFallingBack", true);
AttackingPlayer = false;
agent.SetDestination(transform.position);
Destroy(gameObject, 10);
}
}
The property “Isattaking” defined in zombieAnimatorController params, used to make the transition between the state Walking and the state Attacking for exemple.
This is the final state machine looks like:
Enmey TakeDamage
Finally, let’s add the method TakeDamage in which, we update the enemy health when shooting by player and destroy the CapsuleCollider when enemy’s health less then or equal to 0 .
public void TakeDamage(float range)
{
Health -= range;
if(Health <= 0)
{
// TODO Add money to player.
Destroy(transform.GetComponent<CapsuleCollider>());
}
}
In order to detect, the hits, we’ll use the method OnCollisionEnter in CapsuleMovement script:
private void OnCollisionEnter(Collision collision)
{
if(collision.transform.tag == "Enemy")
{
EnemyMovment enemy = collision.gameObject.GetComponent<EnemyMovment>();
enemy.TakeDamage(30);
Destroy(gameObject);
}
}
The hole EnemyMovement script looks like:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyMovment : MonoBehaviour
{
private Transform target;
private Animator animator;
private float attakingCountDown = 1f;
public float Speed = 50;
public float Health = 100;
public int AttackDamage;
public int AttackingDistance;
public bool AttackingPlayer;
public NavMeshAgent agent;
public float AttakingRate = 1f;
// Start is called before the first frame update
void Start()
{
AttackingPlayer = false;
target = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();
animator = GetComponent<Animator>();
agent.speed = Speed;
agent.acceleration = 150;
}
// Update is called once per frame
void Update()
{
if(Health > 0)
{
animator.SetBool("IsWalking", true);
animator.SetBool("IsAttaking", false);
if (Vector3.Distance(transform.position, target.position) > AttackingDistance)
{
animator.SetBool("IsAttaking", false);
agent.SetDestination(target.position);
AttackingPlayer = false;
}
else
{
animator.SetBool("IsAttaking", true);
AttackingPlayer = true;
if(attakingCountDown <=0)
{
// TODO Update Player Health.
attakingCountDown = 1f / AttakingRate;
}
attakingCountDown -= Time.deltaTime;
}
}
else
{
agent.speed = 0;
agent.acceleration = 0;
agent.angularSpeed = 0;
animator.SetBool("IsFallingBack", true);
AttackingPlayer = false;
agent.SetDestination(transform.position);
Destroy(gameObject, 10);
}
}
public void TakeDamage(float range)
{
Health -= range;
if(Health <= 0)
{
// TODO Add money to player.
Destroy(transform.GetComponent<CapsuleCollider>());
}
}
}
Follow Me For Updates
Subscribe to my YouTube channel or follow me on Twitter or GitHub to be notified when I post new content.