Search code examples
c#unity-game-engine

How to loop through unity gameobjects


I want to make a script that loops through all game objects with the tag, Enemy I modified a code snippet from here, and ended up with 2 errors.


Cannot Implicitly convert 'Unity.GameObject[]' to 'Unity.GameObject'

and

Error   CS1579  foreach statement cannot operate on variables of type 'GameObject' because 'GameObject' does not contain a public instance definition for 'GetEnumerator'

If anyone could tell me why this is happening or a solution to this I would be very grateful, thanks in advance! Here is my code:

void FixedUpdate()

{
    GameObject objects = GameObject.FindGameObjectsWithTag("Enemy");
    var objectCount = objects.Length;
    foreach (var obj in objects)
    {
        // Move the players accordingly
        //var rb = 
        Vector2 direction = (player.position - transform.position).normalized;
        obj.rigidbody.velocity = direction * moveSpeed;

    }
}

Solution

  • FindGameObjectsWithTag as the name hints returns a GameObject[].

    In order tog et the attached Rigidbody2D use GetComponent<Rigidbody2D>

    It should be either GameObject[] or simply var

    /*GameObject[]*/ var objects = GameObject.FindGameObjectsWithTag("Enemy");
    var objectCount = objects.Length;
    foreach (var obj in objects)
    {
        // Move the players accordingly
        var rb = obj.GetComponent<Rigidbody2D>()
        Vector2 direction = (player.position - transform.position).normalized;
        rb.velocity = direction * moveSpeed;
    }
    

    The second one was just a follow up error since you declared objects as a GameObject which indeed as the error says has no GetEnumerator implementation.


    In general it is not the best thing to use FindObjectsWithTag repeatedly. I would rather use a pattern with a static list of all existing instances like

    // Put this component on your enemy prefabs / objects
    public class EnemyController : MonoBehaviour
    {
        // every instance registers to and removes itself from here
        private static readonly HashSet<EnemyController> _instances = new HashSet<EnemyController>();
        
        // Readonly property, I would return a new HashSet so nobody on the outside can alter the content
        public static HashSet<EnemyController> Instances => new HashSet<EnemyController>(_instances);
    
        // If possible already drag the Rigidbody into this slot via the Inspector!
        [SerializedField] private Rigidbody2D rb;
    
        // public read-only access
        public Rigidbody2D Rb => rb;
    
        private void Awake()
        {
            if(!rb) rb = GetComponent<Rigidbody2D>();
            _instances.Add(this);
        }
    
    
        private void OnDestroy()
        {
            _instances.Remove(this);
        }
    }
    

    and then use

    var enemies = EnemyControler.Instances;
    foreach (var enemy in enemies)
    {
        // Move the players accordingly
        Vector2 direction = (player.position - transform.position).normalized;
        enemy.Rb.velocity = direction * moveSpeed;
    }