Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Resolved How can I make an enemy follow a trail created by a Player

Discussion in 'Scripting' started by Bl00dyFish, May 5, 2024.

  1. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    100
    Hello.
    I'm creating an enemy pathfinding system that follows a trail of GameObjecs left by the player. However, I'm running into a problem where the enemies stop for a while when they reach the closest GameObject.
    Also, I don't thnk my method for finding the closest GameObject in the trail works correctly, because the Enemies don't follow the trail exactly and sometimes go to a position really far along the trail.

    Code (CSharp):
    1.     public void EnemyAI_Move()
    2.     {
    3.         int moveValue;
    4.         closestChosenPosition = FindClosestLocation();
    5.  
    6.         if(Vector3.Distance(transform.position, closestChosenPosition.transform.position) >= 0.5f)
    7.         {
    8.             if (Vector3.Distance(transform.position, player.position) <= 50 && Vector3.Distance(transform.position, player.position) >= 1)
    9.             {
    10.  
    11.                 Vector3 movePosition = (closestChosenPosition.transform.position - transform.position).normalized;
    12.                 characterController.Move(movePosition * speed * Time.deltaTime);
    13.             }
    14.         }
    15.         else
    16.         {
    17.             closestChosenPosition = FindClosestLocation();
    18.         }
    19.  
    20.         Quaternion rotation = Quaternion.LookRotation(closestChosenPosition.transform.position - transform.position);
    21.         transform.rotation = rotation;
    22.  
    23.  
    24.         if (characterController.velocity != Vector3.zero)
    25.         {
    26.             moveValue = 1;
    27.         }
    28.         else
    29.         {
    30.             moveValue = 0;
    31.         }
    32.  
    33.         anim.SetFloat("Velocity", moveValue);
    34.     }
    35.  
    36.     GameObject FindClosestLocation()
    37.     {
    38.         List<float> distances = new List<float>();
    39.  
    40.         foreach(GameObject obj in FindObjectsByType<GameObject>(FindObjectsSortMode.None))
    41.         {
    42.             if(obj != null && obj.name.Contains("PlayerLocation"))
    43.             {
    44.                 float objDistance = Vector3.Distance(transform.position, obj.transform.position);
    45.  
    46.  
    47.                 distances.Add(objDistance);
    48.  
    49.                 if(objDistance == distances.Min())
    50.                 {
    51.                     GameObject closestLocation = obj;
    52.                     return closestLocation;
    53.                  
    54.                 }
    55.             }
    56.         }
    57.  
    58.         return null;
    59.      
    60.  
    61.  
    62.     }
     
    Last edited: May 7, 2024
  2. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    100
    Ok, I fixed up the FindClosestLocation method.

    Code (CSharp):
    1.    void FindClosestLocation()
    2.    {
    3.        float distance = 1000; //Start with a big number
    4.  
    5.  
    6.        foreach(GameObject obj in FindObjectsByType<GameObject>(FindObjectsSortMode.InstanceID))
    7.        {
    8.            if(obj != null && obj.name.Contains("PlayerLocation"))
    9.            {
    10.                float objDistance = Vector3.Distance(transform.position, obj.transform.position); //for each object we are determining if they are less than the distance, if they are the object is made the new distance, if an object is closer than that distance, the new distance is set and so on.
    11.              
    12.                if(objDistance < distance)
    13.                {
    14.                    if(Vector3.Distance(transform.position, obj.transform.position) >= 1.5f && obj != closestChosenPosition)
    15.                    {
    16.                      
    17.                        closestChosenPosition = obj;
    18.                        distance = objDistance;
    19.                    }
    20.  
    21.                }
    22.  
    23.  
    24.            }
    25.        }
    26.  
    27.  
    28.    }
    Now, my issue is finding out which closest object is newer using instance IDs. Because when there are two GameObjects at the same distance, I need to find which is newer so the enemy goes to that.
     
  3. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,933
    Your code and method just doesn't make a whole lot of sense.
    A better solution might be to have a list which stores the player positions, rather than iterating though every single game object in the scene and trying to use some InstanceID.
    Entries at the end of the list are newer entries.

    Code (csharp):
    1.  
    2.  
    3. List<Vector3> playerPositions;
    4.  
    5. public Vector3 FindClosestLocation ()
    6.     {
    7.         var closestDistance = float.MaxValue;
    8.         int closestIndex = -1;
    9.  
    10.         int i = 0;
    11.         foreach (Vector3 playerPositionEntry in playerPositions) {
    12.  
    13.             var dist = Vector3.Distance (transform.position, playerPositionEntry);
    14.             if (dist < closestDistance) {
    15.                 closestDistance = dist;
    16.                 closestIndex = i++;
    17.             }    
    18.         }
    19.  
    20.         Vector3 closestPosition = playerPositions [closestIndex];
    21.         return closestPosition;
    22.     }
    23.  
     
    Last edited: May 5, 2024
  4. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    100
    I tried this, but the enemy just gets stuck and stops moving
    Code (CSharp):
    1. public Vector3 FindClosestLocation()
    2. {
    3.  
    4.     float distance = float.MaxValue; //Start with a big number so we can go down
    5.     int closestIndex = 0;
    6.  
    7.     int i = 0;
    8.     foreach(GameObject playerPositionEntry in GameManager.instance.playerLocators)
    9.     {
    10.         var dist = Vector3.Distance(transform.position, playerPositionEntry.transform.position);
    11.         if (dist < distance)
    12.         {
    13.             distance = dist;
    14.             closestIndex = i++;
    15.         }
    16.     }
    17.     Vector3 closestLocation = GameManager.instance.playerLocators[closestIndex].transform.position;
    18.     return closestLocation;
    19.  
    20. }
     
    Last edited: May 5, 2024
  5. dstears

    dstears

    Joined:
    Sep 6, 2021
    Posts:
    151
    I think this code has a bug with how it updates closestIndex. In your foreach loop, the value "i" only updates when a new shorter distance is found and you use "i" to set closestIndex. This means that if several list entries are processed that are further away, then "i" will no accurately represent the index into the list.

    It may be simpler to use a for loop.
    Code (CSharp):
    1.  
    2.     List<Vector3> playerPositions;
    3.  
    4.     public Vector3 FindClosestLocation()
    5.     {
    6.         var closestDistance = float.MaxValue;
    7.         int closestIndex = -1;
    8.  
    9.         for (int i = 0; i < playerPositions.Count; i++)
    10.         {
    11.             var dist = Vector3.Distance(transform.position, playerPositions[i]);
    12.             if (dist < closestDistance)
    13.             {
    14.                 closestDistance = dist;
    15.                 closestIndex = i;
    16.             }
    17.         }
    18.  
    19.         Vector3 closestPosition = playerPositions[closestIndex];
    20.         return closestPosition;
    21.     }
    22.  
     
    ArachnidAnimal likes this.
  6. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    100
    Still doesn't work. The enemy just gets stuck when it reaches its destination (stops)
    Code (CSharp):
    1.   public Vector3 FindClosestLocation()
    2.   {
    3.  
    4.        float distance = float.MaxValue; //Start with a big number so we can go down
    5.        int closestIndex = -1;
    6.  
    7.        for(int i =  0; i < GameManager.instance.playerLocators.Count; i++)
    8.        {
    9.             var dist = Vector3.Distance(transform.position, GameManager.instance.playerLocators[i].transform.position);
    10.             if (dist < distance)
    11.             {
    12.  
    13.                   distance = dist;
    14.                   closestIndex = i;
    15.  
    16.            
    17.             }
    18.        }
    19.        Vector3 closestLocation = GameManager.instance.playerLocators[closestIndex].transform.position;
    20.        return closestLocation;
    21.  
    22.   }
     
  7. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    8,159
    Man you really need to learn to debug things on your end. Have you considered if the issue is elsewhere? All that method does is find the closest location.

    Start to debug to debug upwards through the logic.
     
    Kurt-Dekker likes this.
  8. ArachnidAnimal

    ArachnidAnimal

    Joined:
    Mar 3, 2015
    Posts:
    1,933
    Good catch.

    If the enemy reaches the closest point, then calling FindClosestLocation() again will just give you the same position you currently just arrived to.
    At some point you should remove all elements in the array/list that which are older and equal to the position you've just reached before you call FindClosestLocation() again.

    Ex:
    If you list is: pos1, pos2, pos3, pos4
    And the enemy goes to pos2, then pos1 and pos2 should be removed from the list/array.
     
    Last edited: May 6, 2024
    spiney199 likes this.
  9. Bl00dyFish

    Bl00dyFish

    Joined:
    Mar 12, 2022
    Posts:
    100
    UPDATE: I got it working!

    Here's the full code:
    Code (CSharp):
    1.    public void EnemyAI_Move()
    2.    {
    3.  
    4.        if(!followingPath && !followingPlayer)
    5.        {
    6.            closestChosenPosition = FindClosestLocation();
    7.            followingPath = true;
    8.        }
    9.  
    10.        if(closestChosenPosition == null)
    11.        {
    12.            followingPath = false;
    13.        }
    14.  
    15.  
    16.  
    17.        if(closestChosenPosition != null)
    18.        {
    19.            if (Vector3.Distance(transform.position, closestChosenPosition.transform.position) <= 1f)
    20.            {
    21.                visitedPositions.Add(closestChosenPosition);
    22.                closestChosenPosition = FindClosestLocation();
    23.            }
    24.            if (Vector3.Distance(transform.position, player.position) <= 50 && Vector3.Distance(transform.position, player.position) >= 1)
    25.            {
    26.  
    27.                Vector3 movePosition;
    28.                if (Vector3.Distance(transform.position, player.transform.position) <= 5f)
    29.                {
    30.                    followingPath = false;
    31.                    followingPlayer = true;
    32.  
    33.                    movePosition = (player.transform.position - transform.position).normalized;          
    34.                  
    35.                    Quaternion rotation = Quaternion.LookRotation(player.transform.position - transform.position);
    36.                    transform.rotation = rotation;
    37.  
    38.                    Debug.DrawLine(transform.position, player.transform.position, Color.red);
    39.  
    40.                }
    41.                else
    42.                {
    43.                     followingPlayer = false;
    44.  
    45.                     movePosition = (closestChosenPosition.transform.position - transform.position).normalized;
    46.                     Quaternion rotation = Quaternion.LookRotation(closestChosenPosition.transform.position - transform.position);
    47.                     transform.rotation = rotation;
    48.                }
    49.              
    50.                characterController.Move(movePosition * speed * Time.deltaTime);
    51.                Debug.DrawLine(transform.position, closestChosenPosition.transform.position, Color.green);
    52.  
    53.            }
    54.          
    55.  
    56.  
    57.        }
    58.  
    59.        int moveValue;
    60.        if (characterController.velocity != Vector3.zero)
    61.        {
    62.            moveValue = 1;
    63.        }
    64.        else
    65.        {
    66.            moveValue = 0;
    67.        }
    68.  
    69.        anim.SetFloat("Velocity", moveValue);
    70.  
    71.    }
    72.  
    73.    public GameObject FindClosestLocation()
    74.    {
    75.  
    76.        float distance = float.MaxValue; //Start with a big number so we can go down
    77.        int closestIndex = -1;
    78.      
    79.        allPositions = GameManager.instance.playerLocators.ToArray();
    80.      
    81.        positions.Clear();
    82.        foreach (GameObject i in allPositions)
    83.        {
    84.            if (!visitedPositions.Contains(i))
    85.            {
    86.                positions.Add(i);
    87.            }
    88.        }    
    89.  
    90.        for (int i = 0; i < positions.Count; i++)
    91.        {
    92.            var dist = Vector3.Distance(transform.position, positions[i].transform.position);
    93.            if (dist < distance)
    94.            {
    95.                distance = dist;
    96.                closestIndex = i;
    97.            }
    98.        }
    99.  
    100.        GameObject closestLocation = positions[closestIndex];
    101.        return closestLocation;
    102.  
    103.    }