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.