Hi there! I’ve had a project for a while that I didn’t work at for 1 month, and now I just realised that there is something wrong in my patrol script.The enemy is supposed to chase the player if he is in a certain range and other than that he should go patrol randomly to MoveSpots Gameobjects that are placed in a array.The thing is that he is just going to one movespot and then keeps staying there even after the waitTime is over and seems to be rotating slowly.How could I fix that? I’ve been trying for a few hours… Also, if you have any solutions, please also explain them further so I can understand.I am pretty new to scripting and Unity overall, so I would appreciate that!
Thanks!
Here is the code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Patrol : MonoBehaviour
{
public Transform player;
public Transform[] moveSpots;
private int randomSpot;
NavMeshAgent nav;
public float distToPlayer = 5.0f;
public float chaseRadius = 20f;
public float facePlayerFactor = 20f;
private float waitTime;
public float startWaitTime = 1f;
void Start()
{
waitTime = startWaitTime;
randomSpot = Random.Range(0, moveSpots.Length);
}
private void Awake()
{
nav = GetComponent<NavMeshAgent>();
nav.enabled = true;
}
// Update is called once per frame
void Update()
{
float distance = Vector3.Distance(player.position, transform.position);
if(distance > chaseRadius)
{
Patroling();
}
else if(distance <= chaseRadius)
{
ChasePlayer();
}
}
void Patroling()
{
nav.SetDestination(moveSpots[randomSpot].position);
if(Vector3.Distance(transform.position, moveSpots[randomSpot].position) < 3.0f)
{
if(waitTime <= 0)
{
randomSpot = Random.Range(0, moveSpots.Length);
waitTime = startWaitTime;
}
else
{
waitTime -= Time.deltaTime;
}
}
}
void ChasePlayer()
{
float distance = Vector3.Distance(player.position, transform.position);
if (distance <= chaseRadius && distance > distToPlayer)
{
nav.SetDestination(player.position);
}
}
}
I dont see anything wrong with your code at first glance. For now i’d recommend you place some Debug.Log() messages through your code and see what gets executed, and which if’s actually get entered when. You should, for example, verify that ‘randomSpot’ actually changes. I’m not experienced with nav mesh agents, so it may be worth looking into the documentation. It may, for example, not be desirable to call SetDestination every frame like you are doing when patrolling. If so, you could just move it to where you calculate randomSpot.
Either way, as far as i know this would be better anyways performance-wise since SetDestination to my knowledge calculates a new path, which is computational heavy, thus you should only do this when the target actually changed.
You are also calculating distance to determine whether to patrol or chase the player, but each method then calculates the distance again. While not related to your problem, you could just pass the already calculated distance value to the function via a parameter.
Oh well then I’ve gotta do some debbuging yeah and I will also try to look into the documentation to try to optimize my code a bit.Thanks for the tips!
I haven’t used NavMeshAgent but maybe part of the problem is that you’re setting the destination each time?
Docs say that changing destinations can take a few frames to take effect.
I already mentioned this in my first comment, but you could just move the SetDestination part of patrolling to where you calculate randomSpot. Thus you would only set the destination if you actually have a new destination, not simply every frame. As for chasing the player, i’m not sure. However, that is also a pretty common concept so you should find plenty of tutorials around chasing players on a navmesh.
The same code that was here used to work in 2019.3.0f1 and currently I am in 0f5.Could that be the issue? Cause I can’t manage to solve it in any sorf of way and it seems that the code stops running as soon as it gets to the first if inside the patrol script.It sets the destination, then, from there things don’t work anymore and to be honest I’m really confused right now as a begginer
And yeah I could just take a script from a tutorial but if I can fix mine then I wanna go with this one.
I’m not following. The code worked in 19.3.0f1 and you are using 19.3.0f5 and it doesnt work? Or what do you mean?
If you made any changes to the code you could also repost it. If it throws exceptions (and you maybe missed them since you disabled your console or something) please post them as well.
Did you try putting the Patrolling SetDestination from line 46 to 53 as i suggested?
Anyways if you ever think your the script is stuck, i recommend placing some Debug.Log() messages throughout the code. If you suspect the code to not execute after SetDestination is called, print a message before and after that. You can also use this to print out values of some variables you suspect making trouble. It’s a great tool for quick debugging. For more extensive debugging i recommend using a proper Debugger, however i mostly never find this necessary. May be just me being lazy tho.
Also, you are not supposed to take some script from a tutorial. You are supposed to look through tutorials and guides in order to learn how to do these kinds of things. Just copying it wont do you any good. But going along with the tutorial (typing the code yourself helps too imho) and understanding what’s repsonsible for what and why things work, causes you to become better and able to do these things yourself. That’s how most people learn. ‘Copying’ something that works and dissecting it.
Haha well yeah I didn’t mean that I was going to copy it, I meant that I was going to go through it, see how it works and then maybe discover something that could help me fix my script.Copying something without even thinking about what you’re doing is pretty much useless.
And yes I’ve tried putting the SetDestination inside of the if and let it stay in the first place and it seems that the patroling script completely stopped running.I have placed some Debug.Log’s in there and it seems that it’s not even going through the first if.The Chasing part works fine though.So the issue is isolated to the Patrol part of the script only.
The only Debug Log that displays in the console is the one with “3”, before all the code.
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class Patrol : MonoBehaviour
{
public Transform player;
public Transform[] moveSpots;
private int randomSpot;
NavMeshAgent nav;
public float distToPlayer = 5.0f;
public float chaseRadius = 20f;
public float facePlayerFactor = 20f;
private float waitTime;
public float startWaitTime = 1f;
Animator anim;
void Start()
{
waitTime = startWaitTime;
randomSpot = Random.Range(0, moveSpots.Length);
}
private void Awake()
{
nav = GetComponent<NavMeshAgent>();
nav.enabled = true;
}
// Update is called once per frame
void Update()
{
float distance = Vector3.Distance(player.position, transform.position);
if (distance > chaseRadius)
{
Patroling();
}
else if (distance <= chaseRadius)
{
ChasePlayer();
}
}
void Patroling()
{
Debug.Log("3");
if (Vector3.Distance(transform.position, moveSpots[randomSpot].position) < 2.0f)
{
Debug.Log("2");
nav.SetDestination(moveSpots[randomSpot].position);
if (waitTime <= 0)
{
randomSpot = Random.Range(0, moveSpots.Length);
waitTime = startWaitTime;
anim.SetInteger("condition", 1);
Debug.Log("1");
}
else
{
waitTime -= Time.deltaTime;
anim.SetInteger("condition", 2);
Debug.Log("Stonks");
}
}
}
void ChasePlayer()
{
float distance = Vector3.Distance(player.position, transform.position);
if (distance <= chaseRadius && distance > distToPlayer)
{
nav.SetDestination(player.position);
anim.SetInteger("condition", 1);
}
}
}
with the other variable as a public to see what it’s value is in the inspector when the game is running (or create a Debug.Log, but I find inspector easier to read).
If it’s not completeing the first if command, distance isn’t larger than chaseRadius and you want to see why
You said that distance is always 0. To get more information you should try logging the position of player and transform. Unless they are the same, distance between the two also should not be 0. If they are the same, then that’s your problem.
Edit: Also, the idea of having a class variable ‘distance’ is that you calculate the value once (at the start of Update) and then use that. You still calculate the same distance at least 2 times. This shouldnt have anything to do with your issue, but is redundant and inefficient.
Copy new contents into a new script, and strip it back to test the distancing function - so you should only have a function that calculates the distance between the GameObject and the player target. You should get that working quickly, as Vector3.distance doesn’t do a lot (in the case of your script). I get this type of thing all the time, and if I have 500 lines of code, I found the easiest way is to just simplify it, it always works for me.
Also, I’d remove the float distance from the functions, just declare it at the beginning as you have, that’s all that’s needed.