*** Disclaimer Start ***
Objects don’t really communicate using primitive values, they communicate using references. The serialized data stored in save files is for reliably loading information into the various databases/systems in your game, but once it’s loaded, and the systems establish references to each object instance, you won’t be using the IDs much anymore (at least, in most common game dev scenarios that I’ve come across). I feel this is an important point to make because the format of the ID is probably one of the least important things to worry about, and while there are pros and cons depending on the format you use, in the end you can really just do whatever you want (like using HSV colors for IDs) and get a game working just fine.
*** Disclaimer End ***
Integers are absolutely fine for object IDs in most scenarios, but they have two drawbacks and one benefit over some other common solutions which may or may not apply to a given problem. Let’s talk about the three common approaches as I see them, and the pros and cons of each.
- Integers/Shorts. Integers are 32-bit and shorts are 16-bit, which is ~4 billion / ~64 thousand numbers, respectively. At this range, even if you use Random to randomly generate the value, you’re not guaranteed to get a unique ID. 4 billion sounds like a lot, but with a thousand or more objects, a collision is not beyond the realm of possibility, so you must have some system in place for checking to make sure ID values don’t overlap and create bugs down the line. Since you’re going to be checking anyways, some might say using short is better though, since 64 thousand is already enough never have to worry about running out of room in most scenarios, assuming you don’t mind checking against the whole lookup table for duplicates each time you hit GenerateID. There are even scenarios where byte could be better (256 values) if you don’t need more values than that, like say, as the value type for many enums (this has other problems though, as it isn’t as well-supported as I think it should be).
The main benefit is that the smaller the type used, theoretically the faster lookups should be. You’re not getting the guaranteed uniqueness of Guids or the human-readability of strings, but you get performance benefits instead. That said, IDs are overwhelmingly used in serialization, but not really used much in your core code. Once an object obtains a reference to whatever the ID is for, they tend to cache that reference and use it directly, unless there’s some reason they can’t. That being the case, the only real performance benefit you tend to get is in the initial access to obtain the reference (usually immediately after booting the game, starting a new scene, and/or deserializing save data, when performance matters the least), and in the memory allocation size of thousands and thousands of otherwise absolutely tiny objects, if memory is a huge concern. This isn’t really enough to be considered “critical” in any way, at least to me, so going with integers/shorts/bytes for the performance benefits is pretty well into premature optimization territory unless you have a really good reason to do so IMO.
- Guids are the industry standard for guaranteed unique IDs (5,316,911,983,139,663,491,615,228,241,121,400,000 combinations). They aren’t serialized by default by Unity, which means using them in a game is a little tricky and usually one has to resort to treating them like strings for good chunks of their lifetime, or write a property drawer for a wrapper (as I did), but this isn’t really a very big deal as long as anything that really cares knows that it can convert them to strings. Just generating the Guid and treating it as a string all of the time is perfectly viable too- though it’s slower than doing the lookups with Guids directly, and string-to-Guid conversions (and vice-versa) everywhere no doubt generates garbage.
The benefit to using Guids is that you can guarantee uniqueness across different development stations without having to cross-check them with eachother. In other words, Developer A can be working on making objects for a system, Developer B can be working on making other objects for the same system, and they can combine their work later without needing to worry about collisions. This is quite valuable in some scenarios, such as when you only want one member of the team actually using Unity, while the others simply use tools you’ve made for generating data to import (this is commonly the case with me). You can have the IDs / data generated outside of Unity without needing any real integrations until the last step of feeding that data in, because collisions simply aren’t going to happen.
The drawbacks are performance cost and the fact that the numbers are even less human-readable than ints/shorts. All systems that generate and use Guids, both in and outside of Unity, will need to be automated or only use the ID under-the-hood while dropdown selections just give the “name” of the object being selected instead. This isn’t that difficult to do, but it’s another step. People shouldn’t be expected to copy and paste Guids around in the inspectors/between spreadsheets, ever, or you’re just asking for problems.
- Just using strings. Strings are the slowest option, and they aren’t guaranteed unique in their simplest form, but they have one interesting benefit. That is, you can make a hierarchical structure using just the object ID, and have a single database with categorical divisions without needing to make the categories distinct objects themselves. The usual rule of thumb with this is to use Reverse Domain Name Notation, which is to say, starting with the broadest categorical level, and narrowing it down to the smallest and then object name itself. “Items.Armor.Chest.Gold-Breastplate”, as an example. or “UI.StartScene.NewGameButtonText”- the possibilities are pretty much endless. You can even write a property drawer for this so that you can use drop-downs for already-created sections, like “Items”, “Armor”, “Chest” in the first example, then only have to write the object name itself to avoid the possibility of misspelling or misremembering any particular section and creating bugs.
Of course, strings are also viable as short IDs with just the name, so long as you can check for uniqueness (which you need to be doing for anything other than Guids anyways), and while this is easily the least performant solution, lookups really shouldn’t be happening so often that it matters, or I’d argue you have bigger problems.
That’s just me though, YMMV obviously.