problem with assigning agent destination using scripts

hi im trying to make an ai patrol an area and if it spots the player it follows, but it chases the player no matter its sight range, code attached below, thanks.

using System.Collections;
using System.Collections.Generic;
using Unity.AI.Navigation;
using UnityEngine;
using UnityEngine.AI;

public class EnemyLogic : MonoBehaviour
{
    public GameObject Player;
    NavMeshAgent agent;
    public Transform[] waypoints;
    void Start()
    {
        int childnum = 0;
        agent = gameObject.GetComponent<NavMeshAgent>();
        foreach (Transform child in GameObject.Find("Waypoints").transform)
        {
            childnum++;
        }
        waypoints = new Transform[childnum];
        childnum = 0;
        foreach (Transform child in GameObject.Find("Waypoints").transform)
        {
            waypoints[childnum] = child;
            childnum++;
        }
    }

    // Update is called once per frame
    void Update()
    {
        Collider[] colliders = Physics.OverlapSphere(gameObject.transform.position, 25f, layerMask: LayerMask.NameToLayer("Player"));
        if (colliders.Length <1)
        {
            foreach (Transform waypoint in waypoints)
            {
                agent.destination = waypoint.position;
                float distance = 0;
                while (!(distance > 0.1f))
                {
                    distance = (gameObject.transform.position - waypoint.position).magnitude;
                }
            }
        }
        else
        {
            agent.destination = Player.transform.position;
        }
    }
}

We just had a talk about while loops in the other thread!!

This is Spiney’s post:

You can’t do what you’re doing in line 39 above.

That should probably be an if() statement, but again, not sure what exactly it is intended to do.

It feels like perhaps that is a defective implementation of “find the nearest waypoint,” or at least if that is what it is, it won’t get you what you think…

Unity will lock up 100% of the time EVERY millisecond your scripting code is running.

Nothing will render, no input will be processed, no Debug.Log() will come out, no GameObjects or transforms will appear to update.

Absolutely NOTHING will happen… until your code either:

  • returns from whatever function it is running

  • yields from whatever coroutine it is running

As long as your code is looping, Unity isn’t going to do even a single frame of change. Nothing.

No exceptions.

“Yield early, yield often, yield like your game depends on it… it does!” - Kurt Dekker

Meanwhile, to fix your actual issue, you still need to learn how to debug:

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

2 Likes

Oh, regarding spiny, since this version of my code doesn’t lock itself up i thought that its fixed and the useless while loop is so that the agent doesnt switch between waypoints every frame and only switches waypoints after it arrived at the previous waypoint, thanks.

It isn’t locking up as your code is probably never entering the loop in your testing. As it stands, as soon as your code does enter that loop, it will go infinite and lock up the application.

Again, you probably want this to be an if-statement, and not a while loop.

Thanks

I just fixed the while loop thing but the code is still broken, thanks.

Yes, and …

See above.

Writing code is easy. Silly easy. Anyone can do it.

Debugging is where the actual work happens, where you actually make the code you wrote work.

Again:

By debugging you can find out exactly what your program is doing so you can fix it.

Use the above techniques to get the information you need in order to reason about what the problem is.

You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.

Once you understand what the problem is, you may begin to reason about a solution to the problem.

Since this is the second post on the same issue and I don’t think the actual issue was understood in the first question, I like to point out some major problems and misunderstandings I see with this code.

Update is a callback that is called by Unity once every frame. So that foreach loop inside the Update callback makes no sense. Unity’s scripting layer is single threaded. So your Update method HAS TO finish within this frame or NOTHING in Unity will advance or react to anything. Unity hands over the control into your hands. Absolutely nothing is happening while your code is running. So it makes no sense to iterate through all waypoint inside Update. You would go through all waypoints within a single frame.

For waypoint movement you either want to use a coroutine which can be interrupted / suspended so Unity can actually continue, or you want to remove all your loops and do your logic in Update. There are tons of examples for waypoint scripts on the internet. In general you want to remember the index of the current waypoint and in update you would just check how far you are from the current waypoint. When you reached the position you would increase the waypoint index in order to move to the next one. Of course it requires some additional checks what should happen once you reached the last one.

1 Like

Thanks, this is my first rodeo so forgive me for my lack of understanding

I rewrote to code and it partially works

using System.Collections;
using System.Collections.Generic;
using Unity.AI.Navigation;
using UnityEngine;
using UnityEngine.AI;

public class EnemyLogic : MonoBehaviour
{
    public GameObject Player;
    NavMeshAgent agent;
    public Transform[] waypoints;
    public int toWaypoint = 0;
    public bool moving = false;
    private bool personalSpottedEnemy;
    private EnemiesManager enemiesManager;
    void Start()
    {
        enemiesManager = GameObject.Find("GameManager").GetComponent<EnemiesManager>();
        int childnum = 0;
        agent = gameObject.GetComponent<NavMeshAgent>();
        foreach (Transform child in GameObject.Find("Waypoints").transform)
        {
            childnum++;
        }
        waypoints = new Transform[childnum];
        childnum = 0;
        foreach (Transform child in GameObject.Find("Waypoints").transform)
        {
            waypoints[childnum] = child;
            childnum++;
        }
    }

    // Update is called once per frame
    void Update()
    {
        personalSpottedEnemy = false;
        Collider[] colliders = Physics.OverlapSphere(gameObject.transform.position, 25f);
        foreach (Collider collider in colliders)
        {
            if (collider.CompareTag("Player"))
            {
                agent.destination = Player.transform.position;
                enemiesManager.SpottedPlayer=true;
                personalSpottedEnemy=true;
            }
        }
        if (personalSpottedEnemy==false)
        {
            patrol();
        }
    }
    void patrol()
    {
        if ((agent.gameObject.transform.position - waypoints[toWaypoint].position).magnitude < 1f)
        {
            if (toWaypoint > waypoints.Length)
            {
                toWaypoint++;
            }
            else
            {
                toWaypoint = 0;
            }
            moving = false;
        }
        if (moving == false)
        {
            agent.destination = waypoints[toWaypoint].position;
            moving = true;
        }
    }
}