Home > Software design >  How Can I Freeze Enemy Ai Position In Unity?
How Can I Freeze Enemy Ai Position In Unity?

Time:04-30

I am making a FPS game in Unity, one of my player's abilities is to 'freeze' any enemy. I've tried this in 3 ways at the moment:

  • using Rigidbody.Constraints
  • Setting Target waypoint to the enemies current position.
  • Resetting the path.

I use waypoints to make my enemies patrol the map.

Enemy Movement Code:

public class EnemyControls : MonoBehaviour
{
    NavMeshAgent agent;

    private Rigidbody rb;
    [SerializeField] Animator animator;

    bool isPatroling;

    public GameObject waypoints;

    int waypointIndex;
    Vector3 target;

    float xWanderRange;
    float zWanderRange;

    private float freezeDur = 1.5f;

    void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
        animator = GetComponent<Animator>();
    }

    void Start()
    {
        animator.SetBool("isPatroling", true);

        waypointIndex = 0;
        UpdateDestination();
    }

    void Update()
    {
        // checking if ai has reached destination or last waypoint.
        if (waypointIndex == waypoints.transform.childCount - 1 && agent.remainingDistance < 0.5f)
        {
            xWanderRange = Random.Range(-10.0f, 10.0f);
            zWanderRange = Random.Range(-10.0f, 10.0f);

            // checks that the distance is big enough to move enemy.
            if ((xWanderRange < -5.0f || xWanderRange > 5.0f) && (zWanderRange < -5.0f || zWanderRange > 5.0f))
            {
                Vector3 targetPosition = new Vector3(xWanderRange, 0, zWanderRange)   transform.position;

                NavMeshHit hit;
                if (NavMesh.SamplePosition(targetPosition, out hit, 1.0f, NavMesh.AllAreas))
                {
                    agent.destination = hit.position;
                }
            }
        }

        else if (agent.remainingDistance < 1.0f)
        {
           // Debug.Log("Reached destination");
            IterateWaypointIndex();
            UpdateDestination();
        }
    }

    void UpdateDestination()
    {
        target = waypoints.transform.GetChild(waypointIndex).position;
        agent.SetDestination(target);
    }

    void IterateWaypointIndex()
    {
        waypointIndex  ;
        if (waypointIndex == waypoints.transform.childCount)
        {
            waypointIndex = 0;
        }
    }

    public void StopEnemy()
    {
        // make enemy destination their position.
        // agent.destination = transform.position;

        Debug.Log("freeze enemy");
        agent.ResetPath();

        animator.SetBool("isPatroling", false);

       // Invoke("UpdateDestination", freezeDur);
    }
}

CodePudding user response:

What went wrong with the methods you tried? I would just put an isFrozen bit in there and bail on the Update step if it is, like:

public class EnemyControls : MonoBehaviour
{
    private bool isFrozen = false;
    // stuff
    void Update()
    {
        if(isFrozen)
        {
            return;
        }
        // more Update stuff
    }

    // more stuff

    public void StopEnemy()
    {
        // make enemy destination their position.
        // agent.destination = transform.position;
        
        Debug.Log("freeze enemy");
        isFrozen = true;
       
        animator.SetBool("isPatroling", false);
        
        // Invoke("UpdateDestination", freezeDur);
    }

CodePudding user response:

float timer = 0;
bool isFrozen = false;
void Update()
    {
    if(isFrozen){
        timer = Time.deltaTime; //If isFrozen is true, ten add time to our timer

        if(timer > freezeDur){ // If the timer reaches freezeDur then unfreeze and reset the timer.
            isFrozen = false;
            timer = 0;

        }
    return; //finally return statement so you will not execute code below this loop so the agent wont be able to move untill he is unfrozen.
    }

        // checking if ai has reached destination or last waypoint.
        if (waypointIndex == waypoints.transform.childCount - 1 && agent.remainingDistance < 0.5f)
        {
            xWanderRange = Random.Range(-10.0f, 10.0f);
            zWanderRange = Random.Range(-10.0f, 10.0f);

            // checks that the distance is big enough to move enemy.
            if ((xWanderRange < -5.0f || xWanderRange > 5.0f) && (zWanderRange < -5.0f || zWanderRange > 5.0f))
            {
                Vector3 targetPosition = new Vector3(xWanderRange, 0, zWanderRange)   transform.position;

                NavMeshHit hit;
                if (NavMesh.SamplePosition(targetPosition, out hit, 1.0f, NavMesh.AllAreas))
                {
                    agent.destination = hit.position;
                }
            }
        }

        else if (agent.remainingDistance < 1.0f)
        {
           // Debug.Log("Reached destination");
            IterateWaypointIndex();
            UpdateDestination();
        }
    }

public void StopEnemy()
{
    // make enemy destination their position.
    // agent.destination = transform.position;

    Debug.Log("freeze enemy");
    //agent.ResetPath();

    animator.SetBool("isPatroling", false);
agent.destination = transform.position; //Set the destination to its current position to stop the NPC
isFrozen = true; //Set this to true to check in update (Needs refactoring dont use Update too much. Try coroutines?
   // Invoke("UpdateDestination", freezeDur);
}

See the //Comments above for explanation of my alterations. Good luck!

  • Related