Hey folks,
after being recommended the ‘Overthrowing the MonoBehaviour tyranny’ talk, I now try to use as many plain C# objects as possible to manage complexity.
However, I am now encountering an issue related to the lifecycle of objects.
This is my current InCameraDetector, which is supposed to be a Singleton:
public class InCameraDetector {
private static InCameraDetector _instance;
private Camera _camera;
private InCameraDetector(Camera camera) {
this._camera = camera;
}
public static InCameraDetector Instance(Camera camera)
{
return _instance ??= new InCameraDetector(camera);
}
// Methods...
}
This works fine, so that only a single instance of the InCameraDetector is being managed.
There is one problem though, if I go back to the main menu and change the Scene, the Camera gets destroyed while the InCameraDetector doesn’t. This causes an Exception and the InCameraDetector to break.
I was wondering if there is a solid way, to avoid this issue and maybe bind the Singleton to the Scene or something else entirely.
If you want to bind a C# class to the life time of a scene, it needs to be referenced by a monobehaviour.
Ultimately, in this instance, a monobehaviour will still need to manage the C# object. This is Unity after all, and monobehaviours are still needed to make things happen in scene most of the time.
You have given little context about your project and needs, which could have given a more correct architectural answer. Anyway, there are 2 ways I see:
Re-registering needed MonoBehaviours when entering the same scene.
MonoBehaviour is the fundamental class in Unity. Why give it up? If you want to save MonoBehaviour between scenes, then use DontDestroyOnLoad as mentioned above. I created a tutorial about correct using of it:
Well, the project itself is an AR application and the only Camera we really use, is the one provided by the XROrigin.
About giving up on MonoBehaviours:
I pretty much agree with the speaker in the mentioned talk. MonoBehaviour is quite useful, but is overkill in many situations. The InCameraDetector doesn’t really need to know about all the Lifecycle hooks provided by Unity and should be able to work seperately from Unity itself, as it just checks whether some Object is visible in the Camera.
A static instance will live the lifetime of the domain. This means static stuff can live through play mode sessions if you have play mode settings turning domain reloads off when entering play mode.
So yes you would need to manage its lifetime.
So question is, what advantage are you getting here over a monobehaviour? Plain C# objects have their use case (particularly serializable one). But this seems like a case where you should just use a monobehaviour.
You could also pass a destroy cancellation token to InCameraDetector via it’s constructor, if you have some MonoBehaviour attached to the same game object with the camera.
But I personally do agree with the sentiment, that it usually makes life just much easier and more pleasant, if you don’t try to fight Unity, and just use MonoBehavious when it’s convenient to do so
It looks like you’re always passing in the camera every time you access the instance, and that the instance doesn’t have any fields or other data it holds onto other than the camera.
soooo could this maybe just be a static method that takes a camera? Why do you need the InCameraDetector object?
I mean Plane Tracking, Image Tracking. etc. So, what is it?
P.S. FYI, this is not related to your issue, but useful to operate with AR Foundation when having multiple scene. By Adding SceneUtility and SceneUtilitySetup to your project, you can get rid of the error when switching scenes: “MissingReferenceException: The object of type ‘Camera’ has been destroyed but you are still trying to access it.”