Search Unity

Question Optimize access to Game Object references?

Discussion in 'Scripting' started by Magnesium, Apr 11, 2021.

  1. Magnesium

    Magnesium

    Joined:
    Sep 14, 2014
    Posts:
    179
    Hello,

    To maximize maintainability, i have "relocalized" as much as possible of my code (inputs, scene management, sounds...) into components added on scene load. However, i need to access those scripts quite frequently (even when storing references) and i've read that FindObjectOfType can be costly.

    What would be the best to ensure that the engine doesn't have to parse every gameObject whenever i need to make a new reference to one of those components?

    Thanks
     
  2. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    If you have a script that many things need a reference to randomly and you don't wanna get a separate reference for each one you can use a "singleton" pattern.

    It's basically just this
    Code (CSharp):
    1. public class MyClass {
    2.  
    3. public static MyClass instance;
    4.  
    5. void Init(){
    6.  
    7. instance = this;
    8. }
    9.  
    10. }
    and then you can access the instance of "MyClass" from anywhere by calling
    Code (CSharp):
    1. MyClass.instance

    it has some caveats with it, so you might wanna look up some tutorial on this pattern to avoid common problems with it.

    if you're doing it on a monobehaviour component the "Init" function should be the Awake function - not the Start function

    It's called "refactoring"(refactor) you code, btw
     
  3. Magnesium

    Magnesium

    Joined:
    Sep 14, 2014
    Posts:
    179
    Hello,

    Thanks, i've tought about it but i'm not a fan of the singleton pattern unless it have no other choice, i was wondering if Unity has a specific solution to this problem.
     
  4. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    The problem with FindObjectOfType is that it needs to search the whole scene

    One thing you can do to optimize this is compartmentalize all the stuff you look for in one parent object and call GetComponentInChildren on him, this will skip searching the rest of the scene.

    One issue you may encounter with this approach is that if you have two component of the same type you'll only get the first one in the hierarchy.
     
  5. Magnesium

    Magnesium

    Joined:
    Sep 14, 2014
    Posts:
    179
    I'm not sure this will help, unless Unity parses the gameObjects in a specific order and it is possible to manipulate this order of gameObjects to make sure it's one of the firsts to be parsed when FindObjectOfType is called. Also, does the engine stop parsing the list once it finds a first object matching the required class? Otherwise this wont help much since instead of searching for a specific component, i will be searching for a component that knows of the other component.

    Does Unity maybe have a centralized system to store and fetch references from? If not, it might be worth coding it myself. I've also seen that there are dependency injection frameworks but it would probably be a bit overkill for now.
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,752
    Well, they have never let me down.

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://pastebin.com/SuvBWCpJ

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://pastebin.com/cv1vtS6G

    These are pure-code solutions, do not put anything into any scene, just access it via .Instance!

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
    Either that or just make it static and / or backed by PlayerPrefs:

    Here's an example of simple persistent loading/saving values using PlayerPrefs:

    https://pastebin.com/icJSq5zC

    Useful for a relatively small number of simple values.
     
  7. Magnesium

    Magnesium

    Joined:
    Sep 14, 2014
    Posts:
    179
    Singletons (actual singletons, not the Unity's don't destroy on load which are simply gameObjects that persist through the game) and static variables will almost surely result in a non maintainable application. After a while it becomes impossible to keep track of everything that runs in the application. Here's an article on the subject: https://cocoacasts.com/are-singletons-bad

    I could, worst case scenario, have a single static class that handles getting references to everything but i would quickly become a giant mess with way too much responsibility. I need to check how to implement some kind of dependency injection.
     
  8. MDADigital

    MDADigital

    Joined:
    Apr 18, 2020
    Posts:
    2,198
    Singletons are a anti pattern, but unless you go with a Unity DI solution they are kind of mandatory
     
  9. Magnesium

    Magnesium

    Joined:
    Sep 14, 2014
    Posts:
    179
    I'll try to find a way to handle it without depending on an external library. I'm more used to frameworks that already handle this like Symfony or Angular.