Regarding a previous question about this approach, about an alternative to the GetInstance method, the proposed alternative was FindObjectOfType. However it was my understanding that these sort of methods should be avoided since they lead to a lot more processing than necessary. I guess I’m having trouble unlearning some things. I was always trying to keep the code as performant as possible. But it seems the approach being taught here is sacrificing that for readability. Is that generally a good trade off?
If you are using FindObjectOfType
every tick go for a singleton.
If you are not using it in every tick then use FindObjectOfType
and cache the value so you don’t have to use the method again.
In all my years coding games I noticed that singletons are not really that useful. Half the time you can access the scripts in other ways, and the other half is just way too inefficient. I only have found a single scenario where singletons are the best choice, when you want a music player on while loading a new scene, that’s about it.
- You want data to go across scenes? Use a
ScriptableObject
, you can even use the object as your save file using json. - You want a class to be in every scene? Use a sealed class.
- There’s a racing problem and a singleton might fix it? Use lazy values instead.
Seriously, there’s a better tool than singletons for almost every problem I have encountered in all my years making games.
So, to answer your question, Is a good trade off? No, I don’t think it is, but there’s always a solution that gives you both; good performance, and readability.
Thank you. I’ve generally avoided using methods like FindObjectsOfType because I picked up somewhere along the way that they were bad and lazy. So I’ve just got lots of references set in the inspector for when classes refer to each other. Is it better in general to not set these sorts of things in the inspector?
I think that’s a matter of preference.
I generally don’t use the exposed variable approach because it gets really annoying, more when dealing with prefabs.
It takes a second to fill the reference in the inspector, but as games get more complicated that little task can become really time consuming or just annoying. Imagine you have 100 enemies and all of them need a reference to the player, no issue, you select all of them and set the reference all at the same time, but what if you have 10 types of enemies, each one with their unique script, you’ll have to set the reference 10 times, on top of that, you’ll have to do it in every new scene you create (unless you duplicate the scene), and it gets worse, you won’t be able to spawn new enemies because they need the reference.
This doesn’t mean it’s a bad idea, as I said, it depends, let me show you a system I coded to create full level sequences by dragging objects into a script.
In this particular case, I did it that way because all levels are different, it’s quite convenient to have that sort of “drag and drop” system when the object changes every new scene.
My rules would be the following;
I don’t use exposed references when:
- The reference can’t be saved in a prefab.
- I need to instantiate the object during runtime.
- When working in a team. I don’t want the game designer getting confused as hell with all the references so I rather set them in code for the designer to have fun making the game without worries.
But that’s just me, if you are comfortable using exposed references then go for it.
Oh! I also wanted to show you this class that is part of the game I showed in the video above:
This class holds all the information the sequences need to be able to run. The class gets created by the script that runs the game sequence and then passes it to all the ScriptableObjects
, so lines like FindObjectOfType
only run once during the whole game.
My point being, there are many ways to do things, find what suits you, your project, and your team, the best.
Like Singletons, FindObjectOfType is a tool. They’re not always bad, but can easily be abused.
A good alternative to FindObjectOfType which is faster is GameObject.FindWithTag. The trick to this is to put your one instance of the class on a GameObject with a unique tag. Then rather than using FindObjectOfType, you’ll call GameObject.FindWithTag(string myTag).GetComponent() instead.
This is marginally faster because while both FindWithTag and FindObjectOfType must crawl through the entire heirarchy until it finds a hit, FindWithTag only needs to compare the tag of the GameObject, while FindObjectOfType has to run GetComponent on EACH of the objects that it tests. This cost savings is not insignificant.
That being said, neither method should be used in every Update() loop. As Yee said, if you’re doing that every update, just use a Singleton.
Thank you! It’s most helpful to see this approach in code. I think I definitely need to reassess how I’m approaching references like this. Having a singleton class with a ton of references that I need to set and then reference the singleton seems like an unnecessarily roundabout way of doing things compared to this approach. I’m just glad I’m not deeper into development when I realised I need to change this
Thanks again!
That’s useful to know that FindWithTag is faster. I’ve mostly avoided using tags. I was always concerned that looking things up with strings is prone to connections being lost, or if I want to change a tag then I have to go find everywhere in code that I referenced the tag. But it’s all one kind of tradeoff or another I suppose. Thank you.