Search Unity

Question pick a random object from the array if it is within some range

Discussion in 'Scripting' started by DYV, Jan 27, 2023.

  1. DYV

    DYV

    Joined:
    Aug 10, 2015
    Posts:
    58
    Hello! I have an array of enemies. I want to select a random enemy, but if it is within some distance of the player.
    Here is my script for the random enemy:
    Code (CSharp):
    1. public GameObject RandomEnemy()
    2.     {
    3.         GameObject[] gos;
    4.         gos = GameObject.FindGameObjectsWithTag("Enemy");
    5.         if (gos.Length != 0) { random = gos[Random.Range(0, gos.Length)]; }
    6.         return random;
    7.  
    8.     }
    But I need something like this:
    Code (CSharp):
    1. if (Vector3.Distance(playerPosition, go.transform.position) < someRange)
    and before I set "random" otherwise sometimes I will not receive anything from the array
    Could you help me?
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    Once you determine the range you want to use for detection, you should attempt to gather all enemies in that range. Then create a collection of only those enemies. There are different ways to do so. But if you have that collection, you can pick a random one from it.
     
  3. DYV

    DYV

    Joined:
    Aug 10, 2015
    Posts:
    58
    Thanks for the reply. I understand what needs to be done but I don't know how. That is the problem :). I am a very inexperienced programmer.
    Could you tell me how to do it? Interested in the most inexpensive method, since there can be a lot of enemies. I would really appreciate it.
     
  4. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,935
    Without knowing if the game is 2d or 3d, usually when you want to find something with respect to a point, you use raycasts or overlaps checks with the Physics/Physics2D classes. In the case of wanting to find a certain enemy within range, you would probably use an overlap Sphere/Circle:
    3d: https://docs.unity3d.com/ScriptReference/Physics.OverlapSphere.html
    2d: https://docs.unity3d.com/ScriptReference/Physics2D.OverlapCircleAll.html

    You can use that to easily find all enemies within a range around the player, then it's just a matter or selecting a random entry from the results. There's an infinite number of tutorials out there on how to use raycasts/overlaps.
     
  5. DYV

    DYV

    Joined:
    Aug 10, 2015
    Posts:
    58
    Thank you. This is a 3D game.
    OK, I can find all enemies. Let it be array 'gos'. And I can find all "go" from "gos" that are within the range around the player. How do I put all these valid "go" into a new array ( "validCos")?
     
  6. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,935
    Please read my post again.

    Use OverlapSphere to get all enemies within a certain range. Ideally you put enemies all on their own layer, and use a layer mask to only receive results on that layer. The method returns a collection of colliders, of which you can use
    GetComponent<T>
    to get whatever component you care about to deal damage or whatever.

    Like I said. Lots of tutorials out there on raycasts/overlap stuff.

    There's no need to use
    GameObject.FindGameObjectsWithTag
    or similar when you can just use an overlap sphere to find every enemy within the desired range.
     
  7. DYV

    DYV

    Joined:
    Aug 10, 2015
    Posts:
    58
    If I use OverlapSphere I will get not only enemies but other objects with collider too. Then I can choose only enemies ( GetComponent<Enemy>).
    But how can I choose random enemy then? That is what I can't realize.
     
  8. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,935
    As mentioned there's various ways to filter the results of an overlap sphere, such as using a LayerMask. Plenty of info on it in the docs: https://docs.unity3d.com/Manual/Layers.html

    When you have a collection of something, either a list of an array, you can access their elements via a numerical index. You just need to make a random number from 0 to the one less than the number of elements in your collection (as collections in C# are zero-index based).

    Honestly it's only three lines of code:
    Code (CSharp):
    1. Collider[] enemyColliders = Physics.OverlapSphere(transform.position, radius, enemyLayerMask);
    2. int randomIndex = UnityEngine.Random.Range(0, enemyColliders.Length);
    3. Collider randomEnemyCollider = enemyColliders[randomIndex];
     
  9. DYV

    DYV

    Joined:
    Aug 10, 2015
    Posts:
    58
    Thanks for the answer and your patience :) I just didn't want to use layers and was looking for an alternative way. But now I see that the method you suggested was much easier.