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

Question How to replace GameObject.Find or gameobject child by a for or foreach loop?

Discussion in 'Scripting' started by APSchmidt, Sep 20, 2023.

  1. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    4,448
    Hi,

    I'd like to replace three GameObject.Find lines in Start() by a for or forreach loop but I cannot figure out how to do that.

    Code (CSharp):
    1.     private GameObject defaultPosition, cameraPosition2, cameraPosition3;
    2.  
    3.     private void Start()
    4.     {
    5.         // Storing the camera positions
    6.         defaultPosition = GameObject.Find("DefaultPosition");
    7.         cameraPosition2 = GameObject.Find("CameraPosition (2)");
    8.         cameraPosition3 = GameObject.Find("CameraPosition (3)");
    9.     }
    These objects are children of the player; they are tagged and I use them to store different positions of the camera.

    Your help would be welcome, thank you.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    Then make your variables public and drag them in!!

    Don't fight The Unity Way(tm). :)

    (I think I posted this to you in the past...)

    Remember the first rule of GameObject.Find():

    Do not use GameObject.Find();

    More information: https://starmanta.gitbooks.io/unitytipsredux/content/first-question.html

    More information: https://forum.unity.com/threads/why-cant-i-find-the-other-objects.1360192/#post-8581066

    In general, DO NOT use Find-like or GetComponent/AddComponent-like methods unless there truly is no other way, eg, dynamic runtime discovery of arbitrary objects. These mechanisms are for extremely-advanced use ONLY.

    If something is built into your scene or prefab, make a script and drag the reference(s) in. That will let you experience the highest rate of The Unity Way(tm) success of accessing things in your game.
     
  3. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    4,448
    I could do that of course but it wouldn't tell me how to use a for loop instead. ;)
     
  4. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    521
    You don't have to make the properties public BTW you can keep them private if you add an attribute.

    Code (CSharp):
    1. [SerializeField]
    2. private GameObject defaultPosition
    More to the point what do you want to loop over in place of using Find and why?
     
  5. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,561
    This is a poor use for a for loop because all it would do is increase the surface area for bugs by about 12x or 18x, roughly, depending on how you measure it.

    Why not just look for examples of for() loops on the interwebs, rather than trying to hammer a poor idea in code (using GameObject.Find() is a BAD idea) through an inappropriate use of a simple language looping construct?

    For instance you'd probabky have to containerize each GameObject variable into either its own System.Action or else into some generic class that lets you marshal it back out... it's just not appropriate.

    "I have some leftover mashed potatoes from yesterday...

    how can I use it to fill some of the old nail holes in my walls?"
     
  6. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    What would you be for looping?

    A for loop implies you have a collection to loop over. You'd have to tell us what sort of collection you'd want to loop over and why you want to do it that way?

    When people mention GameObject.Find and replacing it, they're usually referring to how it's heavily suggested NOT to use GameObject.Find and would like a cleaner alternative.

    Well... that cleaner alternative is exactly what @Kurt-Dekker suggested.

    I mean if you REALLY want to use some loop. Well your conditions have various "collections" you could easily form:
    1) since they're children you can enumerate all the children (could use something like GetComponentsInChildren<Transform>(), or just enumerate the Transforms, etc)
    2) since they're tagged you could enumerate the FindObjectsWithTag collection
    3) you could attach a script to them that has a static collection that puts them in the collection on awake/onenable/start or whatever (timing becomes an issue here)

    But I mean... why? Why do it that way?

    Is this like a question on a test/homework/exam? If so... either there is more to the question that explains context, or it's just a really bad question on a test.
     
    Kurt-Dekker likes this.
  7. APSchmidt

    APSchmidt

    Joined:
    Aug 8, 2016
    Posts:
    4,448
  8. tleylan

    tleylan

    Joined:
    Jun 17, 2020
    Posts:
    521
    Kurt-Dekker likes this.
  9. SisusCo

    SisusCo

    Joined:
    Jan 29, 2019
    Posts:
    1,104
    As was already said, you cannot utilize a for/foreach loop here, because you need to assign values to distinct fields (
    defaultPosition
    ,
    cameraPosition2
    ...), not to indexes in a collection (
    cameraPositions[0]
    ,
    cameraPositions[1]
    ...).

    Well, in theory you could, if you were to define a custom indexer in the class to map from an index to a field using a switch expression - but I don't think that would make any sense for your use case...
    Code (CSharp):
    1. GameObject this[int index]
    2. {
    3.     set
    4.     {
    5.         switch(index)
    6.         {
    7.             case 0: defaultPosition = value; break;
    8.             case 1: cameraPosition2 = value; break;
    9.             case 2: cameraPosition3 = value; break;
    10.         }
    11.     }
    12. }
    13.  
    14. void Start()
    15. {
    16.     var names = new[] { "DefaultPosition", "CameraPosition (2)", "CameraPosition (3)" };
    17.     for(int i = 0; i < 3; i++)
    18.     {
    19.         this[i] = GameObject.Find(names[i]);
    20.     }
    21. }
    One thing you could do is use a tuple's deconstructor to assign to multiple fields in one go:
    Code (CSharp):
    1. void Start() => (defaultPosition, cameraPosition2, cameraPosition3)
    2.              = (Find("DefaultPosition"), Find("CameraPosition (2)"), Find("CameraPosition (3)"));
    But I don't think that would be more readable either than just three separate assignment operations :D
     
    Last edited: Sep 21, 2023
    Kurt-Dekker likes this.
  10. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,378
    Kurt-Dekker likes this.