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

Best way to get list of GameObjects. What garbage collection should I worry about?

Discussion in 'Scripting' started by SoftwareGeezers, Aug 12, 2014.

  1. SoftwareGeezers

    SoftwareGeezers

    Joined:
    Jun 22, 2013
    Posts:
    898
    I want to perform evaluations of lots of dynamically created and destroyed objects. I'm thinking of running a GameObject.Find once per frame/AI update and caching this for scripts to reference

    Code (csharp):
    1. class GameController{
    2.     public GameObject[] shots;
    3.     public GameObject[] bots;
    4.  
    5.     void AIUpdate(){
    6.         shots = GameObject.FindGameObjectsWithTag("shot");
    7.         bots = GameObject.FindGameObjectsWithTag("bot");
    8.     }
    9. }
    10.  
    11. class AIThing(){
    12.     public GameController gameControl;
    13.  
    14.     void Update(){
    15.         reference list of GOs in gameControl.shots
    16.     }
    17. }
    Would this work as is, or would I need to clear out the old GameObject[] arrays prior to using Find again?
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Have each GameObject register itself with GameController when it's created and unregister itself when it's destroyed. Don't need to ever do a Find.
     
    Oyedoyin1 likes this.
  3. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,738
    This would be pretty slow. I'm guessing you know that, which is why you're putting the updating in a controller and not in every object. GameObject.Find*WithTag is second only to GameObject.Find in terms of being slow.

    Here are the options that come to mind, in order from worst to best, performance- and usability-wise:
    1. GameObject.FindGameObjetsWithTag
    2. Attach a Shot or a Bot script to each relevant object, and use FindObjectsOfType<Shot> to find all the shots. This is going to be similarly slow, but will be much more versatile. However, it's a halfway step to the best option...
    3. Attach Shot or Bot scripts to the objects, and have them maintain their own list of objects. Use a static List<Shot> member, and add or remove shots from it in OnEnable and OnDisable. Your AIThing can reference Shot.listOfShots directly.

    And (to slightly more directly answer the question you actually asked) #3 has no worries about repeatedly overwriting an array - and calling FGOWTag every frame (as in your original proposal) would create quite a lot of garbage for the GC to handle, creating a lot of stuttering in your game.
     
  4. SoftwareGeezers

    SoftwareGeezers

    Joined:
    Jun 22, 2013
    Posts:
    898
    Many thanks. I was thinking about the object management approach but it was looking a little ugly. However, needs must when the Devil drives!

    Edit: Am I right in thinking you can use the List's Remove() method with the object to be removed and it'll find it? You don't have to search the list for the object and remove it manually? (You may be able to tell my knowledge of list structures is ancient and I'm not to speed on these new-fangled wonders ;))
     
    Last edited: Aug 12, 2014
  5. OceanBlue

    OceanBlue

    Joined:
    May 2, 2013
    Posts:
    251
    Can you give an example of this? I don't quite understand what you mean with register itself with GameController.
    Cheers
     
  6. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,738
    He's basically suggesting the same thing I was, with the only difference being where the data was being stored.
     
    OceanBlue likes this.
  7. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,738
    Yep.

    In its simplest form, this might look something like this:
    Code (csharp):
    1.  
    2. public static List<Shot> allshots;
    3.  
    4. void OnEnable() {
    5. if (allshots == null) allshots = new List<Shot>();
    6.  
    7. allshots.Add(this);
    8. }
    9.  
    10. void OnDisable() {
    11. allshots.Remove(this);
    12. }
    13.  
    14. //on your AI script
    15. if (Shot.allshots != null) {
    16. foreach (Shot thisshot in Shot.allshots) {
    17. //do something with thisshot
    18. }
    19. }
    20.  
     
    SoftwareGeezers likes this.
  8. SoftwareGeezers

    SoftwareGeezers

    Joined:
    Jun 22, 2013
    Posts:
    898
    I have a GameController object and script that other scripts can find and refer to. KelsoMRK is saying each time I create/destroy an object, record it in a list in my GameController script. If I want to access this list in other classes, I'd use
    Code (csharp):
    1. void Start(){
    2.     // just called once
    3.     controlScript = GameObject.Find("GameControllerObject").GetComponent<GameControlScript>();
    4. }
    5.  
    6. // reference in script
    7. controlScript.listOfShots[];
    8.  
    Note I cache the GameController objects when objects are instantiated, so I only do it the once. This is how I presently do things (old skool).

    StarManta is saying that I can create a static list as part of the Shot or Bot class and record objects there. The reference should then be class name if I want to access this list in other classes. If I want to access this list in other classes, I'd use
    Code (csharp):
    1. shotClass.listOfShots[];
    (New wave).

    The important advice being that each object should record itself somewhere to keep a running list rather than creating a full list over and over.