Search Unity

Patrol Script Not Working as intended

Discussion in 'Scripting' started by denissuu, Jan 22, 2020.

  1. denissuu

    denissuu

    Joined:
    Nov 6, 2019
    Posts:
    162
    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 :

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5. public class Patrol : MonoBehaviour
    6. {
    7.     public Transform player;
    8.     public Transform[] moveSpots;
    9.     private int randomSpot;
    10.     NavMeshAgent nav;
    11.     public float distToPlayer = 5.0f;
    12.     public float chaseRadius = 20f;
    13.     public float facePlayerFactor = 20f;
    14.  
    15.     private float waitTime;
    16.     public float startWaitTime = 1f;
    17.     void Start()
    18.     {
    19.         waitTime = startWaitTime;
    20.         randomSpot = Random.Range(0, moveSpots.Length);
    21.     }
    22.  
    23.     private void Awake()
    24.     {
    25.         nav = GetComponent<NavMeshAgent>();
    26.         nav.enabled = true;
    27.     }
    28.  
    29.     // Update is called once per frame
    30.     void Update()
    31.     {
    32.         float distance = Vector3.Distance(player.position, transform.position);
    33.  
    34.         if(distance > chaseRadius)
    35.         {
    36.             Patroling();
    37.         }
    38.         else if(distance <= chaseRadius)
    39.         {
    40.             ChasePlayer();
    41.         }
    42.     }
    43.  
    44.     void Patroling()
    45.     {
    46.         nav.SetDestination(moveSpots[randomSpot].position);
    47.  
    48.         if(Vector3.Distance(transform.position, moveSpots[randomSpot].position) < 3.0f)
    49.         {
    50.             if(waitTime <= 0)
    51.             {
    52.                 randomSpot = Random.Range(0, moveSpots.Length);
    53.  
    54.                 waitTime = startWaitTime;
    55.             }
    56.             else
    57.             {
    58.                 waitTime -= Time.deltaTime;
    59.             }
    60.         }
    61.     }
    62.  
    63.     void ChasePlayer()
    64.     {
    65.         float distance = Vector3.Distance(player.position, transform.position);
    66.  
    67.         if (distance <= chaseRadius && distance > distToPlayer)
    68.         {
    69.             nav.SetDestination(player.position);
    70.         }
    71.     }
    72. }
    73.  
     
  2. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    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.
     
    denissuu likes this.
  3. denissuu

    denissuu

    Joined:
    Nov 6, 2019
    Posts:
    162

    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!
     
  4. PaulR

    PaulR

    Joined:
    Nov 14, 2012
    Posts:
    43
  5. denissuu

    denissuu

    Joined:
    Nov 6, 2019
    Posts:
    162
  6. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    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.
     
    Last edited: Jan 28, 2020
    denissuu likes this.
  7. denissuu

    denissuu

    Joined:
    Nov 6, 2019
    Posts:
    162


    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 :p
    And yeah I could just take a script from a tutorial but if I can fix mine then I wanna go with this one.
     
  8. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    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.
     
    denissuu likes this.
  9. denissuu

    denissuu

    Joined:
    Nov 6, 2019
    Posts:
    162

    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:



    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5. public class Patrol : MonoBehaviour
    6. {
    7.     public Transform player;
    8.     public Transform[] moveSpots;
    9.     private int randomSpot;
    10.     NavMeshAgent nav;
    11.     public float distToPlayer = 5.0f;
    12.     public float chaseRadius = 20f;
    13.     public float facePlayerFactor = 20f;
    14.  
    15.     private float waitTime;
    16.     public float startWaitTime = 1f;
    17.     Animator anim;
    18.  
    19.     void Start()
    20.     {
    21.         waitTime = startWaitTime;
    22.         randomSpot = Random.Range(0, moveSpots.Length);
    23.     }
    24.  
    25.     private void Awake()
    26.     {
    27.         nav = GetComponent<NavMeshAgent>();
    28.         nav.enabled = true;
    29.     }
    30.  
    31.     // Update is called once per frame
    32.     void Update()
    33.     {
    34.         float distance = Vector3.Distance(player.position, transform.position);
    35.  
    36.         if (distance > chaseRadius)
    37.         {
    38.             Patroling();
    39.          
    40.         }
    41.         else if (distance <= chaseRadius)
    42.         {
    43.             ChasePlayer();
    44.         }
    45.     }
    46.  
    47.     void Patroling()
    48.     {
    49.         Debug.Log("3");
    50.         if (Vector3.Distance(transform.position, moveSpots[randomSpot].position) < 2.0f)
    51.         {
    52.             Debug.Log("2");
    53.             nav.SetDestination(moveSpots[randomSpot].position);
    54.             if (waitTime <= 0)
    55.             {
    56.                 randomSpot = Random.Range(0, moveSpots.Length);
    57.                 waitTime = startWaitTime;
    58.                 anim.SetInteger("condition", 1);
    59.                 Debug.Log("1");
    60.             }
    61.             else
    62.             {
    63.                 waitTime -= Time.deltaTime;
    64.                 anim.SetInteger("condition", 2);
    65.                 Debug.Log("Stonks");
    66.             }
    67.         }
    68.     }
    69.  
    70.     void ChasePlayer()
    71.     {
    72.         float distance = Vector3.Distance(player.position, transform.position);
    73.  
    74.         if (distance <= chaseRadius && distance > distToPlayer)
    75.         {
    76.             nav.SetDestination(player.position);
    77.             anim.SetInteger("condition", 1);
    78.         }
    79.     }
    80. }
    81.  
     
  10. davidnibi

    davidnibi

    Joined:
    Dec 19, 2012
    Posts:
    426
    I would create:

    Code (CSharp):
    1. float distance
    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 :)
     
  11. denissuu

    denissuu

    Joined:
    Nov 6, 2019
    Posts:
    162
    Well I have tried that and the distance is always zero.Here is the code in case I did it wrong lol unknown.png unknown.png


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using UnityEngine.AI;
    5. public class Patrol : MonoBehaviour
    6. {
    7.     public Transform player;
    8.     public Transform[] moveSpots;
    9.     private int randomSpot;
    10.     NavMeshAgent nav;
    11.     public float distToPlayer = 5.0f;
    12.     public float chaseRadius = 20f;
    13.     public float facePlayerFactor = 20f;
    14.  
    15.     private float waitTime;
    16.     public float startWaitTime = 1f;
    17.     Animator anim;
    18.     public float distance;
    19.  
    20.     void Start()
    21.     {
    22.         waitTime = startWaitTime;
    23.         randomSpot = Random.Range(0, moveSpots.Length);
    24.     }
    25.  
    26.     private void Awake()
    27.     {
    28.         nav = GetComponent<NavMeshAgent>();
    29.         nav.enabled = true;
    30.     }
    31.  
    32.     // Update is called once per frame
    33.     void Update()
    34.     {
    35.         float distance = Vector3.Distance(player.position, transform.position);
    36.  
    37.         if (distance > chaseRadius)
    38.         {
    39.             Patroling();
    40.            
    41.         }
    42.         else if (distance <= chaseRadius)
    43.         {
    44.             ChasePlayer();
    45.         }
    46.     }
    47.  
    48.     void Patroling()
    49.     {
    50.         if (Vector3.Distance(transform.position, moveSpots[randomSpot].position) < 2.0f)
    51.         {
    52.             nav.SetDestination(moveSpots[randomSpot].position);
    53.             if (waitTime <= 0)
    54.             {
    55.                 randomSpot = Random.Range(0, moveSpots.Length);
    56.                 waitTime = startWaitTime;
    57.             }
    58.             else
    59.             {
    60.                 waitTime -= Time.deltaTime;
    61.             }
    62.         }
    63.     }
    64.  
    65.     void ChasePlayer()
    66.     {
    67.         float distance = Vector3.Distance(player.position, transform.position);
    68.  
    69.         if (distance <= chaseRadius && distance > distToPlayer)
    70.         {
    71.             nav.SetDestination(player.position);
    72.         }
    73.     }
    74. }
    75.  
    It seems that it's still fully broken now though.. Not even moving to the first point now.
     
  12. denissuu

    denissuu

    Joined:
    Nov 6, 2019
    Posts:
    162
    What do you think I should try next?
     
  13. Yoreki

    Yoreki

    Joined:
    Apr 10, 2019
    Posts:
    2,605
    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.
     
  14. davidnibi

    davidnibi

    Joined:
    Dec 19, 2012
    Posts:
    426
    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. ;)