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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

What is a clever way to acess a specific instance of an object?

Discussion in 'Scripting' started by Arcatus, Jul 30, 2015.

  1. Arcatus

    Arcatus

    Joined:
    May 27, 2015
    Posts:
    45
    I have , for example, 9 point soruce lights. Sometimes I want to access a specific instance of them; say light no. 3.

    I have a code similar to this;

    Code (CSharp):
    1.  
    2.  
    3. //first I setup a temporary array where I find all instances of the script I want.  
    4. ArmorLightScript[] armorLightTemp = lights.GetComponentsInChildren<ArmorLightScript>() ;
    5.  
    6. //I now know how many instances I have, so I initialize my array
    7.         armorLightSc = new ArmorLightScript[armorLightTemp.Length] ;
    8.  
    9.         int i;
    10. //then I access each of the instances, find the id, and sort my array accordingly.
    11.         foreach (ArmorLightScript tempSc in armorLightTemp )
    12.         {
    13.             i = tempSc.slotID;
    14.             armorLightSc[i] = tempSc;
    15.         }
    16.  
    I now know exactly whitch instance of the lightScript that is placed at each index of the armorLightSc array.

    The above method works, but it has some obvious weaknesses;

    1) If I don't give each instance an increasing ID, starting at 0 (since the ID must match the index in the final array) I will get an error.
    2) The ID can be set from a constructor script, or in the inspector as a public variable. The latter is not ideal, as any changes to the prefab will mess up the public variables.
    3) This is complicated. Complicated things break in a complicated way.

    Is it an option to set everying up in the inspector? It is tempting to assume that the hirachy is representative for the indexation of GetComponentsInChildren, but is that correct?
    • Parent
      • light 0
      • light 1
      • light 2
    Will GetComponentsInChildren on that hirachy always place light 1 at index 1?

    What if it looks like:
    • Parent
      • light 0
        • light 1
      • light 2


    or:
    • Parent
      • Banana
      • Apple
      • Kangaroo

    Will Apple be at index 1 every time?

    Is there a better, and safer, way to do this?
     
    Last edited: Jul 30, 2015
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    How do you expect to access these lights when you do so?

    Is it going to be by the id?

    If it is the id MUST be unique, and the order is unnecessary.

    You could just stick them in a dictionary if you wanted.

    In this example I change 'slotID' to 'ID' and I assume it's of type 'string' so you can give it unique names rather than integer values
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections.Generic;
    4.  
    5. public class SomeScript : MonoBehaviour
    6. {
    7.  
    8.     [System.NonSerialized()]
    9.     private Dictionary<string, ArmorLightScript> _table = new Dictionary<string, ArmorLightScript>();
    10.  
    11.     void Start()
    12.     {
    13.         _table.Clear();
    14.         foreach(var light in lights.GetComponentsInChildren<ArmorLightScript>())
    15.         {
    16.             _table[light.ID] = light; //note - if 2 lights have the same ID, the last light found with that ID is stored
    17.         }
    18.     }
    19.  
    20.     public void DoSomethingWithLight(string id)
    21.     {
    22.         ArmorLightScript light;
    23.         if(!_table.TryGetValue(id, out light)) return; //stop now if no light with id is found
    24.    
    25.         //do what you need with the light
    26.     }
    27.  
    28. }
    29.  
     
    Kiwasi likes this.
  3. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    There's absolutely no reason to have to do this from a script. If you want 9 lights to be in 9 specific positions in the array, then make the array public, drop off the initialization in the script, and add all of them using the Inspector directly with dragging and dropping. If you drag them into the array in the order you want, they'll always be in that order, and you can call them using the array index without all of this silliness.

    For future reference, however, pulling items in using GetComponentsInChildren pulls them in the same order that they're in your scene asset list (I think), but if you're relying on this order for some reason then there's a good chance you're doing something wrong. ^_^
     
    Kiwasi likes this.
  4. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    GetComponentsXYZ does not have a guaranteed order, you could run into an issue where it returns light5 before light3 after light7 further down the line. Do not depend on that order of you're going to have a massive headache somewhere in the future.
     
  5. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    Out of curiosity, if it doesn't go by the hierarchy placement, do you think/know if it goes by the instance ID number? The order being unreliable is not in question, but I'm sure there's SOME sort of logic to it.
     
  6. GroZZleR

    GroZZleR

    Joined:
    Feb 1, 2015
    Posts:
    3,201
    I imagine it goes off the order in which they're added to the scene / hierarchy but I couldn't tell you offhand, just that it's not guaranteed to be in a specific order.
     
  7. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    When it's said to not be guaranteed.

    What it means is that Unity may at any time decide to change the way they get the components, which would change the order.

    Currently it appears to be by hierarchy placement. But Unity does not guarantee it is.

    When dealing with ordered collections, you want guaranteed definitions.

    This is more of a documentation/support thing. When programming against an API you program against what they tell you the interface (the functions you call) are said to do. Not what the inner guts appear to do. As they may change the inner guts at any time, while preserving the interface as defined in the documentation.
     
    Kiwasi, DonLoquacious and GroZZleR like this.
  8. Arcatus

    Arcatus

    Joined:
    May 27, 2015
    Posts:
    45
    Yes, I access them by armorLightSc.DoSomething().

    So, indexing by hirachy is out.

    Using public arrays is also not very tempting. Manually dragging and dropping 9 elements might be ok; but what if I have 20.. or 50? That is just inconvinient, manual and quite probably I'll drag the same light in twice or something.

    The dictonary solution seems neat. It's slightly inconvinient that the public vars reset if I apply to the prefab. Would it be a good idea to use transform.name as the ID? The script is vulourable to changes of the name, but perhaps that is OK?
     
  9. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,380
    you could use the transform name, it'll still need to be unique.
     
  10. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Editor scripts are your friend here. Set up via code once and forget.