0
\$\begingroup\$

I want to create a utility class that will, among other things, return a cached reference to the main camera. Is the below code correct? My concern is that I'm doing it wrong and that FindGameObjectWithTag is being called each and every time the getter is referenced.

using UnityEngine;

public static class Utils
{
    public static Camera MainCamera { get; } = Camera.main;

}
\$\endgroup\$

2 Answers 2

1
\$\begingroup\$

You would need to use an example below to call FindGameObjectWithTag each time:

    public static Camera MainCamera => Camera.main;

In your example Camera is assigned once.

Although, there is problem with static: their initialization is not the same as normal, with Unity it's hard to find deterministic way to check when Camera is actually assigned. It could be Edit mode, or the moment camera is not created yet. If camera is destroyed or scene is changed (and you're not using DontDestroyOnLoad), you'll get exceptions on calling missing MainCamera.

Consider assignment directly from camera controller:

public class CameraController : Monobehaviour {

    private void Awake() {
        Utils.MainCamera = GetComponent<Camera>();
    }
}

Obviously, MainCamera will need public set; for that.

This way you can guarantee that camera is assigned exactly at the moment it's initialized during runtime. Any new CameraController will overwrite previous one (if old one is destroyed, for example).

It is questionable to introduce such things when you already have Camera.main, although static reference would work slightly faster. This trick helps to create references to any object without global access as well.

I would also note that creation of global references and utility classes is considered not the best practice. It is pretty amazing how easy and clean you could set up references with singletons and statics, but it creates tight dependencies which hard to edit, hard to remove and hard to test. And arguably harder to understand. Choose wisely!

\$\endgroup\$
0
0
\$\begingroup\$

The property here doesn't provide any form of caching. It will call the Camera.main property getter each time you call it. So it doesn't give you anything over calling Camera.main directly.

If you want a caching version of this utility class:

public static class Utils
{
    private static Camera _mainCamera;
    public static Camera MainCamera { 
        get {
             if (!_mainCamera) { 
                  _mainCamera = Camera.main;
             }
             return _mainCamera;
        } 
    } 
}

This will of course stop working if you change which camera is the main camera at runtime. When you do that, then you might want to add another method to class Utils which sets the private variable _mainCamera back to null, so the next call to Utils.MainCamera will retrieve the new main camera.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks. Do you think I can get away with writing the whole property as public static Camera MainCamera => _mainCamera ?? (_mainCamera = Camera.main); \$\endgroup\$
    – Sean Carey
    Mar 25, 2020 at 21:02
  • \$\begingroup\$ @SeanCarey Sure, if you like to play code golf you can also write it that way. \$\endgroup\$
    – Philipp
    Mar 25, 2020 at 22:00
  • 1
    \$\begingroup\$ @SeanCarey also note that UnityEngine.Object uses custom equality operator so if you want to avoid errors (camera gameobject is destroyed but _mainCamera reference is not yet null) you should use explicit null comparison instead of ?? operator: _mainCamera != null ? _mainCamera : (_mainCamera = Camera.main). Link to source \$\endgroup\$
    – Xamtos
    Mar 26, 2020 at 8:14
  • 1
    \$\begingroup\$ @Philipp using { get; } = Camera.main three times faster in the profiler than calling Camera.main directly. Are you sure there is no caching involved? After all, is is equal private static Camera _mainCamera = Camera.main; public static Camera MainCamera => _mainCamera , isn't it? \$\endgroup\$
    – Xamtos
    Mar 26, 2020 at 8:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .