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

Finding GameObject using ID

Discussion in 'Scripting' started by chrisk, May 9, 2009.

  1. chrisk

    chrisk

    Joined:
    Jan 23, 2009
    Posts:
    704
    There is GetInstanceID on GameObject but I do not know how to find an GameObject using this ID.
    What is this ID used for?

    Simlarily, API support for finding GameObject, Component or Child Object doesn't seem to be intuitive.

    What if there are two GameObject with the same name?
    Right now it seems to return the first one it finds.
    ID would be useful in this case but there is no finding object using ID.
    Finding Components is also similar, unorthogonal. Some takes component name as argument and some only take Component Types.
    Finding child Object is also unintuitive. You have to use Transform to find child GameObject such as this,
    Code (csharp):
    1.  
    2. Transform rightArm = playerGO.transform.Find("RightArm")
    3. if(rightArm != null)
    4.   return rightArm.gameObject;
    5. else
    6.   return null;
    7.  
    Instead of just playerGO.Find("RightArm");

    I think you should be able to make child object to any object regarless of transform exsit or not. It logically makes sense to have children for grouping purpose.

    Right now, to make a child object, you will have to do though Transform again, like,
    weaponGO.transform.parent = rightArmGO.transform;
    I expected an API like, rightArmGO.AddChild(weaponGO), but it threw me off for a while why AddChild didn't exist.

    I'm still learning and my experience is fresh compared to experience users. I hope UT dev takes this into consideration.

    Yeah, please tell me how to find an Object using this unique ID.

    Thanks.
     
  2. Mem Dixy

    Mem Dixy

    Joined:
    Feb 26, 2008
    Posts:
    51
    I don't entirely get what you are trying to do so this may not be very useful to you.

    You may not have to add .transform because the variable is already a transform. So you may be able to shorten your code to this:
    Code (csharp):
    1. Transform player;
    2. Transform weapon;
    3. Transform rightArm = player.Find("RightArm");
    4. if (rightArm != null) {
    5.     weapon.parent = rightArm;
    6. }
    7.  
    GetComponetInChildren only returns the first component it finds. To find all of the components use GetComponetsInChildren.

    Is there a reason why you need to find a unique object? Is it because you want an arm to only get one gun? If so you may be able to use this:
    Code (csharp):
    1. if (rightArm.childCount==0) {
    2.     weapon.parent = rightArm;
    3. }
     
  3. chrisk

    chrisk

    Joined:
    Jan 23, 2009
    Posts:
    704
    Well, my question is actually finding an unique object, not components. There may be several objects with the same name, in that case, name alone is not good enough. I believe ID would be useful but I can't find ways to find object using ID.

    Finding Components has similar problem. What if there are two components with the same name?

    Also, children hierarchy depending on Transform is little weird. Children should be independent of Transform. It's more of GameObject Property. Don't you think? Thus, Transform.Find() should move up to GameObject.Find().
     
  4. Mem Dixy

    Mem Dixy

    Joined:
    Feb 26, 2008
    Posts:
    51
    I remember someone else had this problem and someone replied saying it could not be done. There may be a way to do this anyways so long as you don't load a new level and come back to it (because the InstanceIDs would be different). You could try something like this (oh and you can find an object using GameObject.Find instead of Transform.Find).
    Code (csharp):
    1. private void Start () {
    2.     gameObject.name = gameObject.GetInstanceID().ToString();
    3. }
    4. // To find the object use this.
    5. GameObject item = GameObject.Find(gameObject.GetInstanceID().ToString());
    6. // Or do this.
    7. public GameObject other;
    8. private void Start () {
    9.     gameObject.name = other.GetInstanceID().ToString();
    10.     string save = gameObject.name;
    11. }
    12. // To find the object use this.
    13. GameObject item = GameObject.Find(save);
    What this does is sets the objects name to it's InstanceID and then you find it by looking up it's name. This may not solve your problem because the InstanceIDs are different every time so you will have to find the object, get it's InstanceID, then find it again (which is kind of pointless but perhaps you can find a use for this).
     
  5. ElmarKleijn

    ElmarKleijn

    Joined:
    May 11, 2009
    Posts:
    87
    Possibly you could attach the objects to a parent, and traverse all children of this parent to find the given ID by looping through all the transforms?

    Not sure how well this would work out though.
     
  6. NCarter

    NCarter

    Joined:
    Sep 3, 2005
    Posts:
    686
    You can't rely on the instance ID to have any particular value or for that value to remain the same from one run of the game to the next, so it's useless for searching in any case. The only use I've found for it is as a debugging aid. When you have multiple instances of the same script that all print debug messages at the same time, it can be helpful if they append their instance ID to their messages so you can tell one from another.

    If you want to uniquely identify things without relying on names, the best thing to do is make a direct link to the object with a reference variable. For example, in Javascript, write this at the top of your file, outside of functions:

    Code (csharp):
    1. var anotherObject : Transform;
    You can then drag something into the slot that appears for that variable in the inspector, and the rest of the script will be able to access it through the variable. This is outlined in the first section of this page. It's particularly useful to do this within a hierarchy that will be made into a prefab as the references will be automatically restored when the prefab is instantiated.

    It's worth noting that references to objects are themselves a unique means of identifying a particular object. If 'someVariable' is a reference to a Transform, and 'someOtherVariable' is another reference to the same Transform, 'if(someVariable == someOtherVariable)' will return true. If someOtherVariable refers to a different Transform, it'll return false even if both objects have the same name.

    You probably won't be able to hook everything up via public variables in the editor. For example, your enemy characters will probably be created at runtime instead of being placed beforehand in the editor, so you'll have to obtain references to them in some way. Using a Find function is one way of doing this, but you might also get references to them from events such as collisions:

    Code (csharp):
    1. var something : Collider;
    2.  
    3. function OnTriggerEnter(other : Collider)
    4. {
    5.     if(other == something)
    6.     {
    7.         Debug.Log("We hit the trigger stored in the 'something' variable.");
    8.     }
    9. }
    Also, you get a reference to the new object when you use the Instantiate function, as described on this page.
     
  7. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
    When you obtain the ID from an object, you already have a direct link to that object, so I can only assume you want to print this ID once and then use the value to find the object in later runs.

    Unfortunately, while the ID is guaranteed to be unique, it's unlikely to be guaranteed to be the same between two separate runs (this is impossible to implement due to the fact that the user can freely generate objects at runtime).

    To find specific objects in the scene, give them a unique tag and search for them using:
    Code (csharp):
    1. GameObject.FindWithTag(tag : String)
    Edit:
    someone beat me to it :p
     
  8. chrisk

    chrisk

    Joined:
    Jan 23, 2009
    Posts:
    704
    [Mem Dixy wrote]You could try something like this (oh and you can find an object using GameObject.Find instead of Transform.Find)[/Mem Dixy wrote]

    GameObject.Find and Transform.Find is not the same. GameObject.Find will find the object from the scene whereas Transform.Find will find from its children. Thus GameObject.Find cannot identify the unique object if there are more than one object with the same name.

    Also, I do not understand why searching an object with unique ID is not exposed. It's probably easily solved by having a hash table. It does not have to be persistent between the run. How do you identify the unique object in network environment where distributed object needs be identified. I'm sure they have internal method of identifying the object using unique ID. Why don't they expose it as an API??
    Isn't it pretty common to use?
    I hate to muck around with the tag and you will have to generate a unique ID yourself.
     
  9. chrisk

    chrisk

    Joined:
    Jan 23, 2009
    Posts:
    704
    GameObject.Find and Transform.Find is not the same. GameObject.Find will find the object from the scene whereas Transform.Find will find from its children. Thus GameObject.Find cannot identify the unique object if there are more than one object with the same name.

    Also, I do not understand why searching an object with unique ID is not exposed. It's probably easily solved by having a hash table. It does not have to be persistent between the run. Without it, how do you identify the unique object in network environment where distributed object needs be identified? I'm sure there is an internal method of identifying the object using unique ID. Why don't they expose it as an API??
    Isn't it pretty common to use?
    I hate to muck around with the tag and you will have to generate a unique ID yourself.
     
  10. GargerathSunman

    GargerathSunman

    Joined:
    May 1, 2008
    Posts:
    1,571
    You could just give all the objects you want differentiated a script with a single integer variable and two functions (set, get). Then you just make sure that each instantiated object has its number set to one higher than the previous, and you've got a unique ID you can call from every object.
     
  11. chrisk

    chrisk

    Joined:
    Jan 23, 2009
    Posts:
    704
    Sure, it's not hard to generate monotonic indices, I mean, using tag seems like a kludge and not the right way to use inplace of unique ID.

    I guess I'm trying to understand the reason why the API isn't exposed.
    I'm still new to UT and I was pleasantly surprised that UT is very powerful/complete, yet there is some minor missing features, such as unorthogonal APIs(finding childrent GameObject and unique object using ID), or unable to preview animation from asset to name a few that also surprise me.
    UT has been around few years and it's hard not to overlook such a minor features in my opinon. ^^
     
  12. wjmurdick

    wjmurdick

    Joined:
    Apr 10, 2009
    Posts:
    43
    Seems like you almost have to write your own manager that instantiates objects, keeps track of them, allows you to search its list for them by ID, and frees them up when you are done.
     
  13. Mem Dixy

    Mem Dixy

    Joined:
    Feb 26, 2008
    Posts:
    51
  14. Psyco92

    Psyco92

    Joined:
    Nov 15, 2013
    Posts:
    22
    I am wondering the same thing although over a network.
    To clarify : Is there a way to reference a specific game object in a scene, that is identical in all instances of that scene?

    My current solution was to use a string consisting of the wanted objects path.
    This works because I wrote a script that hunts for and renames game objects in a scene with duplicate names.
    This is highly impractical and and hurts work time when waiting for complex hierarchies to be dealt with.

    Surely there is a better way?!

    Here's the code I use to rename all scene objects quickly (with "undo").
    Just copy into an empty script and drop onto any object in your scene. Click append.
    Unappend will remove chars from the end of object names. This will only work properly if used immediately after Append.

    Code (CSharp):
    1.  public bool append = false;
    2.     public bool unappend = false;
    3.  
    4.     void OnDrawGizmos () {
    5.         if (append == true)
    6.         {
    7.             Append();
    8.             append = false;
    9.         }
    10.         if (unappend == true)
    11.         {
    12.             Unappend();
    13.             unappend = false;
    14.         }
    15.     }
    16.  
    17.     void Append()
    18.     {
    19.         Transform[] gos = GameObject.FindObjectsOfType<Transform>();
    20.         for (int apnd = 0; apnd < gos.Length; apnd++)
    21.         {
    22.             gos[apnd].name += "" + apnd;
    23.         }
    24.     }
    25.  
    26.     void Unappend()
    27.     {
    28.         Transform[] gos = GameObject.FindObjectsOfType<Transform>();
    29.         for (int apnd = 0; apnd < gos.Length; apnd++)
    30.         {
    31.             gos[apnd].name = gos[apnd].name.Substring(0, gos[apnd].name.Length - apnd.ToString().Length);
    32.         }
    33.     }
     
    Last edited: Mar 9, 2016
  15. arturmandas

    arturmandas

    Joined:
    Sep 29, 2012
    Posts:
    240
    There is an obvious use for this method and it is categorizing by a common trait, shared via a control object, presumably a (logical) parent. Think of a master NPC not being able to hit his minions on collision.