Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Fastest / Best way to check for units

Discussion in 'Scripting' started by Censureret, Dec 3, 2020.

  1. Censureret

    Censureret

    Joined:
    Jan 3, 2017
    Posts:
    361
    So i am creating an RTS where two "army" of units clash against each other each army will contain between 50 - 100 units.

    What I need them to do is to check for close enemies and attack what is closest.

    I have two approaches for solving this problem.

    1.

    I could make a trigger collider once a gameobject with the right tag enters i select that as the closest enemy and wait until that unit is either dead or the unit selecting it is dead.

    The benefits (as far as i can see) of this is that i wouldn't have to do ray casts every frame to check for enemies and instead wait until it was relevant.



    2.

    As the above suggests another way would be to make a raycast (either sphere or overlapping).

    While the unit hasn't found an enemy it would do this to cast every frame. which could be a drawback.


    What do other games do in this scenario? What is the best solution for RTS (AI) units to find their target (that seems natural)?
     
  2. thesupersoup

    thesupersoup

    Joined:
    Nov 27, 2017
    Posts:
    70
    One really cheap and easy way to check is to iterate between testing the square magnitude of the distance between the desired unit and any potential targets. Square magnitude tests will produce, as you can see, a floating-point result that's the square of the magnitude between Vector3 A (the friendly unit's transform.position) and Vector3 B (the enemy unit's transform.position).

    I know I'll get fact-checked here; square root operations aren't expensive like they used to be, sure, but this is also cheap on the programmer's cognition.

    Pseudocode might look like:
    Code (CSharp):
    1.  
    2. public GameObject GetClosestEnemy( GameObject friendlyUnitRoot )
    3. {
    4.      // The following uses a pseudocode method, I assume you're storing the enemies somehow
    5.      List<GameObject> enemies = GetAllEnemyUnitRootGameObjects();
    6.  
    7.      if( enemies == null || enemies.Count == 0 )
    8.           return null;
    9.  
    10.      GameObject closestEnemy = null;
    11.      float closestDistance = 0.0f;
    12.      Vector3 tempVec = Vector3.zero;
    13.      float sqrDistance = 0.0f;
    14.  
    15.      foreach( GameObject enemy in enemies )
    16.      {
    17.           // Final minus Initial is a Vector3 pointing from Initial point to Final point
    18.           tempVec = enemies[0].transform.position - friendlyUnitRoot.transform.position;
    19.  
    20.           // We could also call the vector magnitude the "distance"
    21.           sqrDistance = tempVec.sqrMagnitude;
    22.  
    23.           if( sqrDistance < closestDistance || closestEnemy == null )
    24.           {
    25.                closestEnemy = enemy;
    26.                closestDistance = sqrDistance;
    27.           }
    28.      }
    29.  
    30.      return closestEnemy;
    31. }
    32.  
    Sometimes, there's no way around it, and you really will have to check through each potential enemy target to figure out which is the closest. In those cases, it's best to just pick the most performant way to do it.

    For an additional performance bonus, you could only have one unit (or a small number of units) do this check per frame or fixed timestep. Once a unit "locks" a target, maybe only check once every 0.1f or 0.5f of a second to see if another target is closer, then adjust if needed. Although changing targets is more of a FPS thing; usually in RTS games even when AI made a decision to attack something it usually sticks to that target until either one of them is dead.
     
    Last edited: Dec 4, 2020