I’ve been wondering for a while about how to adress persistance of gameobjecst across scenes without using a singleton (you know, the gobal access is evil thing) and today I came out with a solution for my music player and score manager that may be extended for any use… I believe…
It is actually kind of singleton pattern for Unity but without the global access static field.
Before we start ranting about the use of singletons and globals I would like to explain a little about the motivation of this. This is for an example game I’m preparing for my students on the second year of High School on programming. They already know how to program and we make a lot of emphasis on good programming practices. I know sigleton is a valid option when you are in a hurry (i.e. prototyping) or working on a small project in which you are the only developer. But it’s not when you are working on a team and have dozens of classes and working for a client that will ask for changes frecuently during development.
It’s a little bit convoluted but all you have to do is to inherit it from any game manager, and remember to override the Start and Update functions calling the base function on the first line if you need to use Start or Update on your manager. I include a dummy scoreManager example at the end of the post.
The idea is that if you need to access the manager you can use Find and GetComponent or FindObjectOfType to get a reference to it in the Start function of your monobehviour. And, at the same time, you can drop instance of every manager on every scene so testing levels is easy, but ensuring that those instances are destroyed if there is a previous one, probably containing data from previous levels.
It’s not nice to the garbage collector, as if your are not disciplined enough by deleting the managers from every scene on the final release they will be marked for disposal just after loading the level. But I consider this an acceptable solution with little side effects if you decide to use another dependency injection pattern later.
Another thing I like about this approach is that you can hide it behind an interface or abstract class, which is not possible (or easy) with singletons using a static field.
What do you think about it? Do you find any flaw in this approach to persistance?
using System;
using UnityEngine;
using System.Collections;
public class Persistant : MonoBehaviour {
private float _lifeTime;
public float lifeTime {
get { return _lifeTime; }
}
virtual protected void Awake() {
Type managerType = this.GetType();
_lifeTime = 0f;
Persistant[] persistantObjects = FindObjectsOfType<Persistant>();
// Filter per actual type
ArrayList managers = new ArrayList();
foreach (Persistant curObject in persistantObjects) {
if (curObject.GetType() == managerType) {
managers.Add(curObject);
}
}
if (managers.Count == 1) {
GameObject.DontDestroyOnLoad(gameObject);
} else {
foreach (Persistant curObject in managers) {
if (curObject != this && curObject.lifeTime == this._lifeTime) {
curObject.beDestroyed();
} else if (curObject.lifeTime > this._lifeTime) {
this.beDestroyed();
return;
}
}
}
}
virtual protected void Update() {
_lifeTime += Time.deltaTime;
}
public void beDestroyed() {
GameObject.Destroy(gameObject);
}
}
Dummy Score Manager example:
using UnityEngine;
using System.Collections;
public class ScoreManager : Persistant {
public int playTime; // in seconds
override protected void Start () {
base.Start();
}
override protected void Update () {
base.Start();
playTime = (int) Time.time;
}
}
[EDIT]: I fixed a couple on bugs in the code and changed the name of the class from APersistant to Persistant. It’s not an absttract class.