• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
3
Question by falconfetus8 · Jul 05, 2013 at 01:14 AM · id

Automatically assigning GameObjects a unique and CONSISTENT ID: any ideas?

I'm trying to make a system that automatically remembers data between two scenes so that the scenes appear to be "persistent"; IE: If I open a chest in one scene, hop over to another scene, and then hop back to the original scene, the chest should still be open.

The current system I have in place is working BEAUTIFULLY, but there's a major catch: in order for it to work, I need to assign each persistent object an ID number, and this number has to be the same each time the scene is loaded up. At the moment, I'm just assigning this ID number by hand in the inspector when I place each individual object. However, I would like to have a system that automatically assigns each object a unique ID for me.

So far, I've tried doing something similar to this:

 public class PersistenceRememberer : MonoBehaviour {
     
     public static int nextID = 0;
     
     private int myID;
     
     //Events
     
     void Awake(){
     
         myID = nextID;
         nextID++;
     }
 
     void OnLevelEnd(){
         //Clear the nextID
         nextID = 0;
     
     }
 
 }

However, this has a major flaw in it: each time a new scene is loaded, the objects end up getting different IDs.

So, I decided to come here for ideas. How can I automatically assign an ID to an object in such a way that it will always be the same, even when the player hops back and forth between scenes?

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

8 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by Kiloblargh · Jul 05, 2013 at 01:48 AM

 DontDestroyOnLoad (theThingThatKeepsTrackOfYourIDs);

The persistent gameObject could keep a List.< List. >, with the index of the outer list corresponding to the level, and the index in the inner list would serve as the ID for every tracked gameObject in that level.

You can then have another List.< List. > that is populated at the same time as the first list; so the index numbers of this match to the index numbers of your gameObjects, and you can store whatever data you need to.

This would let you not only remember what chest was locked the last time you were in the level, but remotely unlock any chest on any level from any other level.

-edit- Sorry, I think I misunderstood your problem. How about this: The first time you load a level, if the persistent list doesn't exist yet- do something like this for each tracked object:

float posHash = (1000*transform.position.x) + transform.position.y + (.001*transform.position.z);

Unless two objects are in the exact same spot- which they really shouldn't be- this number will be unique, regardless of the order the objects' individual scripts call "Awake()." Then you can sort them by posHash and use their index in the sorted list as their permanent ID.

Comment
Add comment · Show 5 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image falconfetus8 · Jul 05, 2013 at 08:01 PM 0
Share

The posHash thing is a good idea, but there's an inherent problem with it: what if two objects are in different positions, but end up having the same hash by sheer coincidence? Take, for example, an object located at <1000, 1, .001> and an object located at <1*10^-6, .001, 10000>. They're in different spots, but will have the exact same hash.

avatar image Kiloblargh · Jul 05, 2013 at 08:27 PM 1
Share

Then it can throw an error; and you can move one of them slightly? I did think of that happening as a theoretical problem with my method (which is why I added the different scale factors for each axis) , but is it a practical problem for your case?

You could also calculate the distance between each object and an arbitrary point in 3d space. That seems even less likely to coincidentally give the exact same value (down to floating point precision) for two objects.

avatar image falconfetus8 · Jul 06, 2013 at 07:42 PM 0
Share

I ended up using your idea, and I must say it works great. In the event that I do run into a hash collision, I will just nudge one of them by a little bit by hand. Thanks for the help!

avatar image Em3rgency · Jul 06, 2013 at 07:57 PM 0
Share

Please tick $$anonymous$$iloblargh's answer as correct, or at least close this question :)

avatar image falconfetus8 · Jul 08, 2013 at 02:46 PM 0
Share

I've already given him a "thumbs up". How do I mark his answer as correct?

EDIT: Never$$anonymous$$d. Found the button.

avatar image
12

Answer by Ash-Blue · Oct 23, 2014 at 09:02 AM

This can easily be done through C#'s GUID generator and Unity's editor libraries for a powerful effect.

Following scripts will automatically generate a unique ID for you, all you have to do is attach the script component. And then KABOOM, you never have to worry about it again (as long as you don't delete the script component). You'll notice in the screenshot the unique ID is visible, but it cannot be edited for safety and stupidity reasons. If you really want to edit it, you can change it to an editable field through EditorGUI.

alt text

UniqueIdDrawer.cs

 using UnityEditor;
 using UnityEngine;
 using System;
 
 // Place this file inside Assets/Editor
 [CustomPropertyDrawer (typeof(UniqueIdentifierAttribute))]
 public class UniqueIdentifierDrawer : PropertyDrawer {
     public override void OnGUI (Rect position, SerializedProperty prop, GUIContent label) {
         // Generate a unique ID, defaults to an empty string if nothing has been serialized yet
         if (prop.stringValue == "") {
             Guid guid = Guid.NewGuid();
             prop.stringValue = guid.ToString();
         }
 
         // Place a label so it can't be edited by accident
         Rect textFieldPosition = position;
         textFieldPosition.height = 16;
         DrawLabelField (textFieldPosition, prop, label);
     }
     
     void DrawLabelField (Rect position, SerializedProperty prop, GUIContent label) {
         EditorGUI.LabelField(position, label, new GUIContent (prop.stringValue));
     } 
 }

UniqueId.cs

 using UnityEngine;
 using System.Collections;
 
 // Placeholder for UniqueIdDrawer script
 public class UniqueIdentifierAttribute : PropertyAttribute {}
 
 public class UniqueId : MonoBehaviour {
     [UniqueIdentifier]
     public string uniqueId;
 }
 



screen shot 2014-10-23 at 2.02.06 am.png (11.3 kB)
Comment
Add comment · Show 6 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Augenpulver · Aug 01, 2016 at 07:55 AM 0
Share

You could simply use the folowing for the same effect or not?

 public readonly string uniqueId;
avatar image Bunny83 Augenpulver · Aug 01, 2016 at 08:29 AM 2
Share

readonly most likely gives you problems with Unity's serialization system. A readonly field can only be initialized either directly in the field initializer or inside the constructor. Both run before any serialization / deseriaization takes place. So you can't test if you already have a GUID assigned in the constructor since the deserialization hasn't took place yet.

If you worry about people can accidentally tweak it, just make the field prvate and use the SerializeField attribute to make it still serializable. That way the user can't access the ID from outside the class. If you still need "read access" just implement a readonly property.

Also value can't be changed in the inspector since Ash uses a LabelField to display the GUID. The only way to "edit" it would be to switch the Inspector into debug mode. However that's exactly the point of the debug mode. It allows you to change any serialized data of a component which of course can break the component's functionality, but that's the user's risk.

avatar image Ash-Blue · Aug 13, 2016 at 04:13 AM 0
Share

I discovered an edge case with this solution. If you put it on a prefab you will probably run into duplicate IDs. I've been trying to figure out a golden solution to prevent this. But am still working on trying to figure something out.

avatar image jammyt Ash-Blue · Sep 21, 2016 at 03:56 PM 0
Share

I'm having the same issue as Ash-Blue, in that if you apply the game object to a prefab, then you get the ID stored in the prefab and thus duplicate IDs when you drag the prefab into a scene.

Did you get a solution for this?

I've tried to clear the ID in the prefab using the AssetProcessor but then when I hit 'Apply' on a gameobject in the scene to apply to it to prefab, it clears the data and reassigns the ID value but I want it to be consistant.

avatar image Ash-Blue jammyt · Oct 02, 2016 at 11:59 PM 0
Share

Ultimately I had to write a special editor window that scans all my scenes and lets me choose which duplicate IDs to scramble. I don't think there is a way around this sadly :(

Image of what I wrote linked from Dropbox since image upload appears to be broken on Unity Answers

https://www.dropbox.com/s/l1dnd1ze33s2dea/Screenshot%202016-08-13%2023.24.21.png?dl=0

avatar image dishmop Ash-Blue · Apr 03, 2017 at 12:27 PM 0
Share

In case you're still interested I've posted a solution that gets around the prefabs problem as well as some other edge cases that I had (see end of this thread) - hope this helps (though its interesting how many edge cases there are for such an apparently simple requirement).

avatar image
0

Answer by mrpmorris · Aug 01, 2016 at 08:49 AM

Is there a problem with saving the game state?

https://unity3d.com/learn/tutorials/topics/scripting/persistence-saving-and-loading-data

Otherwise, if you want a unique ID then create a string that is a concatenation of the following

  1. Scene name

  2. World location that the object has when the scene is loaded

  3. World rotation the object has when the scene is loaded

If you use a Tuple as the key for a static hashtable you can have your MonoBehavior set ThatTable[thatkey] = this.gameObject on Awake

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image icywater45 · Sep 05, 2016 at 03:58 AM 0
Share

THAN$$anonymous$$ YOU SO $$anonymous$$UCH!

I have been searching for an answer like this for the past few days and I did not realize how simple it was. I have been making a building grid but had no way of identifying each individual space, but the method of using it's coordinates in its name works perfect!

avatar image
2

Answer by AntFitch · Oct 27, 2016 at 12:12 AM

  1. You can generate a permanent ID when you attach this GameObjectGUID.cs script to your game object.

  2. When you duplicate a game object that already contains the GameObjectGUID.cs script, a new ID is generated for the duplicated object.

GameObjectGUID.cs

 // GameObjectGUID.cs (drag this onto your game object)
 using UnityEngine;
 
 public class GameObjectGUID : MonoBehaviour {
 
     public int gameObjectID = 0;
 }

GameObjectGUIDInspector.cs

 // GameObjectGUIDInspector.cs
 using UnityEngine;
 using UnityEditor;
 using System;
 
 [CustomEditor(typeof(GameObjectGUID))]
 public class GameObjectGUIDInspector : Editor
 {
     private GameObjectGUID id;
 
     // assign GameObjectGUID instance to this inspector
     void OnEnable()
     {
         id = (GameObjectGUID)target;
 
         // generate new guid when you create a new game object
         if (id.gameObjectID == 0) id.gameObjectID = new System.Random().Next(1000000, 9999999);
 
         // generate new guid if guid already exists
         else
         {
             GameObjectGUID[] objects = Array.ConvertAll(GameObject.FindObjectsOfType(typeof(GameObjectGUID)), x => x as GameObjectGUID);
             int idCount = 0;
             for (int i = 0; i < objects.Length; i++)
             {
                 if (id.gameObjectID == objects[i].gameObjectID)
                     idCount++;
             }
             if (idCount > 1) id.gameObjectID = new System.Random().Next(1000000, 9999999);
         }
     }
 }

This needs optimized, but it is possible to get a unique game object ID when you attach a script to a game object and when you duplicate the game object that contains the ID script.

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by PeterMorris · Oct 27, 2016 at 08:02 AM

I'd use a GUID. Random integers aren't guaranteed to be unique

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
  • 1
  • 2
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

27 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Instantiate ID 2 Answers

Photon Problem 0 Answers

how to create ID to script ?? 0 Answers

store contact with last before destruction 3 Answers

Google Play test in-app purchase non-blank order ID. 0 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges