Good way to reference scripts performance friendly (without singleton)

Hello there!

In the RPG courses Sam advices to not use the singleton pattern because it’s not a really good solution.

So my question then is, how can you reference other scripts or objects without using functions like “FindObjectsOfType” or “findobjectwithtag”, since these are costly and usually not recommended to use for production?

Thanks!

Each problem has a few decent solutions. This is one of those questions that has a lot of options, but none of them are really great for every situation.

The most performat way is to use the inspector and manually drag it in to reference the object in question.

The next way, really is FindObjectOfType, but only if you’re doing it a handful of times max. It can get really costly (performance wise) if you’re doing it on every update, or a very frequent collision.

Other ways can include keeping track of created objects, either from the factory itself or some sort of central registry of the object type. Neither of these solutions are ideal but they’re easy enough to solve.

There’s other ways too.

1 Like

You’re quite right, FindObjectOfType<T>() and GameObject.FindWithTag() are both relatively expensive operations (although FindWithTag is much faster than FindObjectOfType). This makes it very important to limit their use, and as Michael said, you really really don’t want to use these in an Update loop.

In most cases, there isn’t ever a need to. Take the player, for example. There should be one and only one player in the scene (in our setup). That player should exist at the beginning of the scene, since it’s in the scene file. This means that in 99.99% of cases, if you’re looking for a reference to the player, one need only cache the reference in Awake()

GameObject player;

void Awake()
{
    player = GameObject.FindWithTag("Player");
}

So all of your UI, all of your enemies, etc, can get their reference to Player when the game starts and since we’re Fading in with a coroutine in the fader, nobody will ever notice.

The SavingSystem and Fader are a bit trickier, since they don’t exist in the scene file, but are instantiated in during the first run of a scene containing the PersistentObjectSpawner. There’s no (safe) way to guarantee that the PersistentObjectSpawner’s Awake() will run before everybody elses, so putting a reference to the Fader in the Awake() method of the Portal is not truly safe. That being said, since it’s a one-off, there’s nothing wrong with grabbing that reference to Fader and SavingWrapper in the Portal’s method to move to the next scene because it won’t be noticed. It’s not in an Update, but a response to a very specific event.

Now here’s something I did that ground my game to an absolute halt (in this case, “my game” is a procedurally generated game with random enemies that respawn somewhere between 1 and 5 minutes after they die, where the enemies have “teams”, so that Guards attack Bandits, everybody attacks monsters, and not everybody attacks the player)… So I thought I’d be clever (I really should have known better) and write a Linq query for the AI to find the nearest enemy to attack:

var entityToAttack = FindObjectsOfType<Entity>()
                               .Where(h=>h.GetComponent<Health>().isAlive)
                               .Where(f=>f.GetComponent.Faction.IsHostile(faction))
                               .OrderBy(d=>Vector3.Distance(transform.position, d.transform.Position))
                               .FirstOrDefault();

Needless to say, this crushed my fps if there were more than about 5 enemies in the scene.

1 Like

Oh man, the garbage collector would be having a heart attack running that in an Update method.

I hear you on that one. There’s always tradeoffs. What I find worst is the trade off between hard coding caching for one use applications vs making reusable code. Perhaps I’m just not that good a coder yet ;(

1 Like

Judging from the answers I’ve seen you give on these topics, I’d say you’re doing quite well. :slight_smile: The truth of the matter is that when it comes to coding, we’re all learning, even after 40 years of coding in my case.

Thanks for the pep talk. I haven’t done any coding this year and I’m feeling it slip away. Work has distracted me from the important stuff… but alas.

But the good news. I signed up for a year long advanced programming class, so come July, I’m officially a full time student. I’m sure that’ll get me back in the thick of it.

That’s where I am right now with my Bass and Guitar… I played for almost 40 years, but haven’t played live since the Paindemic began… I have a feeling I’ve forgotten more riffs than some players ever play in the first place.

Enjoy that advanced class!

1 Like