It always feels awkward dealing with inactive game objects that you can’t access with find. There appears to be many inefficient ways or “tricks” to get around this, but should you just have them active initially?
Maybe it depends what you are used of but IMO all the Find methods should be the last resort to find reference to stuff. I personally don’t use them nearly anywhere but rather create stuff runtime and get the ref there or do the basic Unity style, draggable variables when there are not need for tons of em.
So do you just store your newly created objects in an array of references to assign them at a later time?
I would have the reference to the inactive gameobject already set by public field that is either type of gameobject or the script directly. Then I can keep the unneeded stuff inactive in editor without any helper scripts or any other kind of extra messing around.
If there would be a lot of stuff to reference to then instead of editor public fields I would just create them in Awake or Start from prefabs or gameobject/addcomponent combination and link to variable or add to a list.
What I do in my game is I have a manager for every object I want to keep track of. It’s a simple
private Dictionary<string, List<GameObject> _registredObjects;
Any object that should register with this dictionary will do so in it’s start method.
Then you can just find a specific object easily:
//Return a list of gameObjects in the Building category
List<GameObject> GOs = ObjectsManager.Instance.GetObjectList("building");
for(int i = 0 ; i < GOs.Count ; i++){
//Do whatever you need with the objects here, you can search for a specific one
}
You can do the same with specific scrips, say have a list of HealthScripts or other, that way you don’t have to use GetComponent everytime you want to use something.
Unless you’re dealing with thousands of GameObjects or you’re on mobile the memory footprint should be negligible.
There’s no footprint, unless my brain is running a little slow today… somebody will read this and have some better info, but I’ll kick it off by saying hashtable uses algorithm to convert keys to memory addresses, so the only footprint is all of your dang strings! Plus you have zero autocompletion with strings. Your best bet if you’re using a dictionary would be to use the object’s unique instance id as the key. If you have a fixed number of non dynamically generated objects, you’ll want to roll an Enum so you can use the object’s “name” to reference it, but without creating an enormous, dynamic array of characters that have no compiler assistance.
Strings are for cases where you can’t control the input and you need dynamic storage, user names, passwords, web addresses… there’s better ways of doing it.
That’s the problem though my entire game is dynamic, you start with a terrain and that’s it. The rest is all created during the gameplay. Strings seems to be the obvious way of doing it as it requires no maintenance at all. No need to create enums when making a new object type.
All wrapped in finders methods so regardless of if I pass “build” “building” “BuIlDiNg” “bu” I’ll always get the “building” tag.
I think people are a bit too pedantic when it comes to strings, stop the hate.
Why the unnecessary overhead though? You’re turning an O(1) lookup operation into an O(n) because you have to process the string to find the object, not to mention the memory allocation for said strings when you could instead use a byte. And what if you accidentally type “biulding”? It just ain’t worth. Ain’t worth. Nah, nah, ain’t worth.
You raised the issue of memory, I was just contributing.
You can do whatever you want, it’s your game and only you know the memory ramifications. If you don’t think it’s an issue based on your testing, then who cares? If you’re grinding your test machine to a halt and the only way to save it is by replacing strings with enums, good luck on grandma’s computer in the den…
I don’t think this is the case, what is stored in the dictionary is the hash of the string, not the string itself. Yes upon calling the key you’ll need to run string.GetHashCode() from the string parameter but this is only done once. After that the lookup in the dictionary is still O(1) because you’re retriving a hash, not a string.
Take a look here this guy did 100 000 lookups on a dictionnary which has 128 characters strings as keys and it only took 47 ms.
http://cc.davelozinski.com/c-sharp/fastest-collection-for-string-lookups
Would you get faster times using ints instead? Absolutely!
Will using strings cause any kind of performance issues? Absolutely not, I’ll never have that many categories to begin with, and my strings are about 15 characters long.
Same goes with memory it’s really an int that is stored and not a string.
For the typing yes you make a good point you could make mistakes when passing the parameter.
I’m not trying to headbutt with anyone. I’m not saying using ints isn’t faster or more memory efficient, all I’m saying is using strings isn’t as bad as you make it up to be.
And I appreciate the input. I apologize if I came across as aggressive it was not my intention!
My memory concern was more about the List which in my case can contain up to 2500 object per list rather than the unique key.
I always forget C#'s weird rules/obfuscation for by reference vs value but aren’t you just assigning pointers to those GameObjects in your list? If so each entry would really just be a memory address that gets dereferenced when you access it.
Yes absolutely! But each reference is still 4 bytes on a 32bit system, it can quickly add up. I guess it’s more of a concern if you’re on mobile?
From my experience, the most costly thing on game objects are renderers, rigidbodies and colliders, in that order. So, it’d be best to make a script which disables those based on distance from the player and few other factors (such as if player is outside bounds of the object, gettable with this.gameObject.GetComponent().bounds and if player is colliding with the thing). Of course, popping may occur, but this can be adjusted by increasing distance object will be hid at.
Certainly there’s no real reason to disable whole object.