0
\$\begingroup\$

I need help making this code work. It is made for the enemy AI to move and patrol, chase the player and attack the player.

The problem is when it starts to attack the player, then the player can move around the enemy and the enemy will not turn to face the player but just keeps attacking in front of him.

using System.Collections;
using System.Collections.Generic;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.EventSystems;

public class EnemyAI : MonoBehaviour
{
    public float minRandomDistance = 5.0f;
    public float maxRandomDistance = 10.0f;
    public float patrolSpeed = 2.0f;
    public float chaseSpeed = 5.0f;
    public float chaseRange = 10.0f;
    public float attackRange = 1f;
    public float rotationSpeed = 2f;
    public Transform player;

    private Animator animator;
    private NavMeshAgent navAgent;
    private Vector3 randomDestination;
    private bool isChasing = false;
    private bool isAttacking = false;
    private string[] attackAnimation = { "isAttacking1", "isAttacking2" };

    private void Start()
    {
        navAgent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
        SetRandomDestination();
    }

    private void Update()
    {
        if (isChasing)
        {
            ChasePlayer();
        }
        else
        {
            Patrol();
        }
        FaceMovementDirection();
    }

    private void Patrol()
    {
        if (!navAgent.pathPending && navAgent.remainingDistance < 0.5f)
        {
            SetRandomDestination();
        }

        // Check if the player is within chase range
        if (Vector3.Distance(transform.position, player.position) < chaseRange)
        {
            isChasing = true;
            navAgent.speed = chaseSpeed;
            animator.SetBool("isRunning", true);
        }
        else
        {
            isChasing = false;
            navAgent.speed = patrolSpeed;
            animator.SetBool("isRunning", false);
        }

        if (Vector3.Distance(transform.position, player.position) < attackRange)
        {
            isAttacking = true;
            navAgent.isStopped = true;

        }
        else
        {
            isAttacking = false;
            navAgent.isStopped = false;
        }
        foreach (string attackParam in attackAnimation)
        {
            animator.SetBool(attackParam, isAttacking);
        }
    }

    private void ChasePlayer()
    {
        // Move towards the player's position
        navAgent.SetDestination(player.position);

        // Check if the player is out of chase range
        if (Vector3.Distance(transform.position, player.position) > chaseRange)
        {
            isChasing = false;
            navAgent.speed = patrolSpeed;
            animator.SetBool("isRunning", false);
        }
        if (Vector3.Distance(transform.position, player.position) < attackRange)
        {
            isAttacking = true;
            navAgent.isStopped = true;

            // Rotate to face the player's position
            Vector3 directionToPlayer = player.position - transform.position;
            directionToPlayer.y = 0;

            Quaternion targetRotation = Quaternion.LookRotation(directionToPlayer);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);


            foreach (string attackParam in attackAnimation)
            {
                animator.SetBool(attackParam, isAttacking);
            }
        }
        else
        {
            isAttacking = false;
            navAgent.isStopped = false;
        }
        foreach (string attackParam in attackAnimation)
        {
            animator.SetBool(attackParam, isAttacking);
        }

    }

    private void SetRandomDestination()
    {
        // Generate a random direction and distance within the specified range
        Vector3 randomDirection = Random.insideUnitSphere;
        randomDirection.y = 0; // Keep the movement on the same plane
        Vector3 targetPosition = transform.position + randomDirection.normalized * Random.Range(minRandomDistance, maxRandomDistance);

        // Set the NavMeshAgent's destination
        navAgent.SetDestination(targetPosition);
    }
    private void FaceMovementDirection()
    {
        Vector3 moveDirection = navAgent.velocity.normalized;

        if (moveDirection.magnitude > 0.1f)
        {
            Quaternion targetRotation = Quaternion.LookRotation(-moveDirection);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * 500.0f);
        }

    }

}
\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

You already have code in the ChasePlayer() function that looks fine:

Quaternion targetRotation = Quaternion.LookRotation(directionToPlayer);
transform.rotation = Quaternion.RotateTowards(transform.rotation, targetRotation, Time.deltaTime * rotationSpeed);

I tested your script in Unity, and it works - it's just very slow. The problem is that you set the default rotationSpeed to 2. That's 2 degrees per second. There are 360 degrees in a circle, so at that speed it would take the enemy 180 seconds (3 full minutes) to turn in a full circle. Try using a much larger rotationSpeed like 90 or 180.

There's another problem too: FaceMovementDirection() makes the enemy look away from the direction it's moving:

 Quaternion targetRotation = Quaternion.LookRotation(-moveDirection);

Notice the negative before moveDirection? If this looks correct in the game, that means your character model is backwards. The code in ChasePlayer() that rotates the enemy to face the player makes the enemy look towards the player instead of away from the player. So currently, your enemies will walk backwards towards the player and then turn around to face the player.

\$\endgroup\$
3
  • \$\begingroup\$ You see that is the problem cause I used moveDirection without - and then the enemy moved backwards so then I added the - and now the enemy is moving in the right direction. so now when the enemy rotates he turns his back on the player, would it be safe to say the player is facing the wrong way then? \$\endgroup\$ Commented Aug 12, 2023 at 17:20
  • \$\begingroup\$ Or what would u say is the best fix for this problem? \$\endgroup\$ Commented Aug 12, 2023 at 21:03
  • \$\begingroup\$ If the enemy faces forward when you do Quaternion.LookRotation(-moveDirection), that means that the enemy model is backwards (it faces -Z, but Unity treats +Z as forward). The best way to fix this is in 3D modeling software such as Blender, 3D Max, or Maya. If you aren't able to fix it that way, and the mesh is an FBX, you can try the "Bake Axis Conversion" option in Unity, though IIRC that's never fixed the problem for me. Another option is to put the enemy in a container, rotated 180 degrees inside the container so that the enemy's mesh is facing Z+. Then move the container instead. \$\endgroup\$
    – Kevin
    Commented Aug 15, 2023 at 1:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .