I'm currently attempting to use a Singleton as a global data structure for Task organization in a game I'm making in Unity.
My Singleton class code is as follows:
public class TaskManager : MonoBehaviour
{
private List<Task> Tasks;
private static TaskManager instance;
private TaskManager()
{
Tasks = new List<Task>();
}
public static TaskManager Instance
{
get
{
if(instance == null)
{
instance = new TaskManager();
}
return instance;
}
}
}
I used this example as a basis for my class:
https://msdn.microsoft.com/en-us/library/ff650316.aspx
However, the problem is, when I try to access the TaskManager in different scripts, the values don't get saved.
For example, in one script I do:
TaskManager tm = TaskManager.Instance;
Task newTask = new Task();
tm.PushTask(newTask);
print(tm.GetTaskList().Count);
Through this I can see that the TaskManager has a count of 1, showing the new task.
But then my other script attempts to read from the TaskManager:
TaskManager tm = TaskManager.Instance;
List<Task> l = tm.GetTaskList();
print(l.Count);
When I do this, the Count is returned as 0, showing that the above task from the world has not been saved to the TaskManager.
I'm pretty sure the error is resulting from me misunderstanding how to use Singletons. Do I need to implement a set property for TaskManager Instance? Or is there another mistake I'm making?
Thanks!
Edit:
The PushTask() code is as follows:
public void PushTask(Task t)
{
Tasks.Add(t);
}
Personally, I don't think that solution that you chose is a perfect one. For some time, I tried using "abstract" classes that didn't inherit from MonoBehaviours, to decouple logic from Unity mechanics — but found that this makes code bloated and unnecessary complicated. In fact, every class that doesn't only contain data but has some logic of its own ends up being a MonoBehaviour sooner or later, in my experience.
So, instead of removing inheritance from MonoBehaviour, I'd solve it by implementing the usual MonoBehaviour singleton pattern:
using UnityEngine;
public abstract class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
public static T Instance { get; private set; }
protected virtual void Awake()
{
if (Instance == null)
{
Instance = (T) this;
}
else
{
Debug.LogError("Got a second instance of the class " + this.GetType());
}
}
}
And then just inheriting your class from it.
Related
I'm trying to create my first bigger project in Unity and I am struggling to understand how abstract implementations away from the monobehaviour classes attached to gameobjects.
I am very familiar with dependency injection (using ASP.NET) but it seems DI is not a great idea to include in Unity projects according to a number of different articles. These articles say Unity has to handle Inversion of Control already, which is the Service Locator principal. I cannot find any built in implementation aside from methods like GameObject#Find or GameObject#GetComponent, etc.
An example would be a class handling interaction with files:
public interface IFileHandler { }
public class FileHandler : IFileHandler { }
public class FileHandling : MonoBehaviour
{
private IFileHandler fileHandler;
private void Awake()
{
this.fileHandler = new FileHandler();
}
}
Now the constructor of FileHandler changes. I would have to change it in every class.
How can I decouple the FileHandler from FileHandling?
Thanks in advance
I recall that in Asp.net there's Program.cs with main method that boots everything up. In unity you could have GameObject with similar Program.cs script that has been assigned a very low Script Execution Order. The script simply initialises your game systems if they have not been initialised yet.
During initialization you can create system instances and store to a static class like toolbox from where you can later reference them from anywhere. If your system needs to listen to unity events like update you can create a new GameObject with the script and set DontDestroyOnLoad enabled and store it to the Toolbox as well.
Toolbox is basically singleton for storing your other "singletons" so they don't have to be singletons. If you use interfaces you can easily swap out the implementation for the SaveSystem for example.
// Enum to allow multiple instances if needed
enum GameSystems { SaveSystem, GameManager }
public class GameTB {
//usage GameTB.toolBox.SetTool(GameSystems.SaveSystem, new SaveSystem());
public static ToolBox<GameSystems> toolBox = new ToolBox<GameSystems>();
//usage GameTB.SaveSystem.SaveGame();
public static ISaveSystem SaveSystem
{
get
{
return toolBox.GetTool<ISaveSystem>(GameSystems.SaveSystem);
}
}
public static IGameManager GameManager
{
get
{
return toolBox.GetTool<IGameManager>(GameSystems.GameManager);
}
}
}
public class ToolBox<T>
{
private Dictionary<T, object> Tools { get; } = new Dictionary<T, object>();
public K GetTool<K>(T key)
{
if (Tools.ContainsKey(key))
return (K)Tools[key];
else
return default(K);
}
public void SetTool(T key, object tool)
{
if (!Tools.ContainsKey(key))
Tools[key] = tool;
else
Tools.Add(key, tool);
}
public bool ContainsTool(T key)
{
if (Tools.ContainsKey(key) && Tools[key] != null)
return true;
else
return false;
}
public void ClearTools()
{
Tools.Clear();
}
}
So I'm experimenting with DI and am trying to create a GameObject Generator.
That GameObject Generator generates GameObjects inside the scene based on some internal logic.
There is variation to what kinds of GameObjects are generated and the logic can vary.
I thought that I could create a Interface and be able to create a class per "unique logic" (i.e. for every generator behaviour i create a class and can switch between generating a lot of small objects and a couple of big objects without having to use if statements, but instead the power of polymorphism).
So I've got something like
GameObjectGenerator : Monobehaviour
IGeneratorType
SmallGenerator : Monobehaviour, IGeneratorType
BigGenerator : Monobehaviour, IGeneratorType
from a logical standpoint this seems to be making sense.
The issue arrises, when transitioning from those generators.
I want to have some sort of condition, where i call a method "TransitionGenerator" from IGeneratorType
that returns a new IGeneratorType. Logically this is working aswell.
However, i want to keep track of my generated Objects (in a list for instance), because they need to be Destroyed later.
When transitioning, the List of generated Objects need to be passed to the new IGeneratorType.
This is where I find myself struggling.
The classes that implement from IGeneratorType need to extend Monobehaviour aswell because i need to make calls to Instantiate and Destroy.
But because they extend from Monobehaviour, I can't seem to create a constructor.
After a bit of research i found a lot of people pointing to either Awake/Start or to creating a Init method.
The problem is, with Awake/Start i cant pass anything and with Init, i would need to put that into the interface aswell, which doesnt make a lot of to me sense from a design standpoint.
Example code:
public class GameObjectGenerator : Monobehaviour{
private IGeneratorType generator;
public void Start(){
generator = new SmallGenerator();
}
public void Update(){
generator.Generate();
if(somecondition){
generator = generator.Transition();
}
}
}
public interface IGeneratorType{
void Generate();
IGeneratorType Transition();
}
public class SmallGenerator : Monobehaviour, IGeneratorType{
private List<GameObject> generatedObjects;
public SmallGenerator(/*List<GameObject> previousObjects*/){
//generatedObjects = previousObjects;
}
public void Generate(){
//...
if(somespecificcond){
generatedObjects.Add(Instantiate(...));
}
if(somecondition){
Destroy(generatedObjects[0])
}
}
public IGeneratorType Transition(){
return new BigGenerator(/*generatedObjects*/);
}
}
public class BigGenerator : Monobehaviour, IGeneratorType{
private List<GameObject> generatedObjects;
public BigGenerator(/*List<GameObject> previousObjects*/){
//generatedObjects = previousObjects;
}
public void Generate(){
//...
if(somespecificothercond){
generatedObjects.Add(Instantiate(...));
}
if(somecondition){
Destroy(generatedObjects[0])
}
}
public IGeneratorType Transition(){
return new SmallGenerator(/*generatedObjects*/);
}
}
I just found the simplest workaround to this specific case:
public class BigGenerator : IGeneratorType{
private List<GameObject> generatedObjects;
public BigGenerator(/*List<GameObject> previousObjects*/){
//generatedObjects = previousObjects;
}
public void Generate(){
//...
if(somespecificothercond){
generatedObjects.Add(Object.Instantiate(...));
}
if(somecondition){
Object.Destroy(generatedObjects[0])
}
}
public IGeneratorType Transition(){
return new SmallGenerator(/*generatedObjects*/);
}
}
This works because Instantiate and Destroy are static methods from "Object", of which "GameObject" inherits.
However this doesn't solve the problem in case one really HAS TO inherit from monobehaviour
in Unity I make use of interfaces. I set a logic for components which are totally different to each other.
Examples:
A car, a dog and a aircraft would implement IMovable. I can call Move() from each component but these components execute different code.
Same for ISavable, each component, that has to save data to the database could save the stuff when looping through all savables.
The problem:
Some people in forums say that interfaces are bad for Unity.
When destroying a gameobject and call its interface method this still gets executed.
No error would come up because Destroy() does not destroy objects. Unity as a C++ driven Engine would setup a C# wrapper for the objects. These objects just get a flag destroyed which is a bool.
Destroyed gameobjects will not get destroyed immediately, they will be destroyed later on at the end of the frame.
Until this end of the frame is not reached the method can still get called from the destroyed object.
The best way would be using abstract classes only and never use interfaces because of the bad behaviour coming up when destroying objects.
I tested this with a small example, I created the following scripts:
public interface IIntfacable
{
void DoSomething();
void DestroyComponent();
}
public class bar : MonoBehaviour
{
private IIntfacable i;
private void Start()
{
i = FindObjectOfType<foo>().GetComponent<IIntfacable>();
}
private void Update()
{
i.DoSomething();
i.DestroyComponent();
i.DoSomething();
}
}
public class foo : MonoBehaviour, IIntfacable
{
public void DoSomething()
{
Debug.Log("=> DoSomething");
}
public void DestroyComponent()
{
Debug.Log("=> DestroyComponent");
Destroy(gameObject);
}
}
When executing this code I get the following result
Workaround:
I could create an abstract base class and choose between
public abstract void Foo();
and
public virtual void Bar()
{
return;
}
but this might lead to overengineering. Because all Scripts would need this base class whether they need this method or not.
Conclusion:
Should I prevent using interfaces?
I am confident in saying there is no harm in using interfaces.
The underlying fear is about keeping track of unmanaged references, a problem which will still be there weather you are using interfaces, abstract classes or whatever. You simply have to make sure that your game code will not try to access any objects which have been Destroy()ed.
Basically, I just construct a collection of objects that I know are not destroyed in my scene, and remove them after destruction.
With risk of answering an xy-problem, If you are scared to miss out on your reference count anyway or there is something in particular which wont allow creating such a list, there is not really any magic wand here, but there are a few precedent patterns in the .net framework with the IDisposable interface/pattern that may lead the way.
Many implementations of these patterns checks a flag in a few public-facing methods of the object. IDisposable.Dispose() would set the flag to true and throw an ObjectDisposedException on some public method if this is set to true, analog to MissingReferenceException in this case. Some patterns will then expose the flag IsDisposed, so that other objects that use the implementation can check instead of doing a try-catch on any access to the object. Your analog could be IsDestroyed, and you should set it in the override of OnDestroy.
You could change your method update like this (well it's not really a use case, why would you try to use it after destroying it, but to show my point):
private void Update()
{
i.DoSomething();
i.DestroyComponent();
if (!i.IsDestroyed) {
// This will not be called
i.DoSomething();
}
}
and implementation could be
public interface IIntfacable : IDestroyable
{
void DoSomething();
}
public interface IDestroyable
{
void DestroyComponent();
bool IsDestroyed { get; }
}
public class foo : MonoBehaviour, IIntfacable
{
bool IsDestroyed { get; private set; }
public void DoSomething()
{
Debug.Log("=> DoSomething");
}
public void DestroyComponent()
{
Debug.Log("=> DestroyComponent");
Destroy(gameObject);
}
public override OnDestroy() {
base.OnDestroy();
IsDestroyed = true;
}
}
In my project, I have a class structure as shown in the image.
The green classes are old codes, that runs very well. The classes in red boxes are newly added codes. There're no compiler errors, however when click play in Unity and runs into the new code, the three classes can't be initialized correctly.
And unity console gives warning that says "The class named 'DataMgrBase`2' is generic. Generic MonoBehaviours are not supported! UnityEngine.GameObject:AddComponent()" at this line: "instance = obj.AddComponent ();"
How can I solve this problem?
Following are some code for your reference, thanks!
Implementation of singleton base class:
using UnityEngine;
using System.Collections;
public class UnitySingletonPersistent<T> : MonoBehaviour where T : Component
{
private static T instance;
public static T Instance {
get {
if (instance == null) {
instance = FindObjectOfType<T> ();
if (instance == null) {
GameObject obj = new GameObject ();
obj.name = typeof(T).Name;
obj.hideFlags = HideFlags.DontSave;
instance = obj.AddComponent<T> ();
}
}
return instance;
}
}
public virtual void Awake ()
{
DontDestroyOnLoad (this.gameObject);
if (instance == null) {
instance = this as T;
} else {
Destroy (gameObject);
}
}
}
Implementation of DataMgrBase:
public class DataMgrBase<TKey, TValue>: UnitySingletonPersistent<DataMgrBase<TKey, TValue>> {
protected Dictionary<TKey, TValue> dataDict;
public override void Awake()
{
base.Awake();
dataDict = new Dictionary<TKey, TValue>();
}
public TValue GetDataForKey(TKey key)
{
TValue data;
if (dataDict.TryGetValue(key, out data))
{
return data;
}
else
{
data = LoadDataForKey(key);
if (data != null)
{
dataDict.Add(key, data);
}
return data;
}
}
virtual protected TValue LoadDataForKey(TKey key)
{
if (dataDict.ContainsKey(key))
{
return GetDataForKey(key);
}
else
{
return default(TValue);
}
}
}
I've solved it by myself as following:
Change of the base class to get a new generic type(of the class that will derive from it, and pass this type to singleton base class)
public class DataMgrBase<TKey, TValue, TClass>: UnitySingletonPersistent<TClass> where TClass: Component
For all the other three classes that want to derive from it, change them as following form:
public class MobSettingDataMgr : DataMgrBase<int, MobSettingData, MobSettingDataMgr>
You want something like:
public abstract class UnitySingletonPersistent<T> : MonoBehaviour where T:UnitySingletonPersistent<T>
{
...
}
Then in your concrete class:
public class DataMgrBase<TKey, TValue> : UnitySingletonPersistent<DataMgrBase<TKey, TValue> >
{
...
}
This is somehow answer that is not solving your problem, but will explain the problem.
MonoBehaviour cannot be generic for at least two reason:
1. Imagine you want to add generic component in Inspector from Unity3D editor. Now engine needs to know exactly all types in this component, not only casue it is going to be compiled in this moment, but also cause you could have public fields with undeclered types. Try to assign your UnitySingletonPersistent directly in Inspector, and you will see it is imposible.
2. Using AddComponent<T> where T is generic looks like could work, but also in this engine you can make so called prefabs out of instantiated GameObjects, and if this GameObject contains generic component Unity3D engine would need to support some kind of baking types, and in practice this would lead to generating scripts, each with diffrent types, and making big mess inside project. I hope you follow me.
But why it works for the components you marked with green color? Simply cause Unity3D engine knows all types when adding this component to GameObject.
To support all this Unity Technologies would need to make core changes in Unity3D engine, how it works now. It would make Unity3D completly diffrent engine as it is now.
So to solve your problem, there is only one way: no adding in runtime generic components, and getting rid of DataMgrBase class. So you will need to implement DataMgrBase logic in each component.
I ran into a problem today and a friend recommended I use a global static instance or more elegantly a singleton pattern. I spent a few hours reading about singletons but a few things still escape me.
Background:
What Im trying to accomplish is creating an instance of an API and use this one instance in all my classes (as opposed to making a new connection, etc).
There seems to be about 100 ways of creating a singleton but with some help from yoda I found some thread safe examples. ..so given the following code:
public sealed class Singleton
{
public static Singleton Instance { get; private set; }
private Singleton()
{
APIClass api = new APIClass(); //Can this be done?
}
static Singleton() { Instance = new Singleton(); }
}
How/Where would you instantiate the this new class and how should it be called from a separate class?
EDIT:
I realize the Singleton class can be called with something like
Singleton obj1 = Singleton.Instance();
but would I be able to access the methods within the APIs Class (ie. obj1.Start)? (not that I need to, just asking)
EDIT #2: I might have been a bit premature in checking the answer but I do have one small thing that is still causing me problems. The API is launching just fine, unfortunately Im able to launch two instances?
New Code
public sealed class SingletonAPI
{
public static SingletonAPI Instance { get; private set; }
private SingletonAPI() {}
static SingletonAPI() { Instance = new SingletonAPI(); }
// API method:
public void Start() { API myAPI = new API();}
}
but if I try to do something like this...
SingletonAPI api = SingletonAPI.Instance;
api.Start();
SingletonAPI api2 = SingletonAPI.Instance; // This was just for testing.
api2.Start();
I get an error saying that I cannot start more than one instance.
Why not just add a public APIClass property to your singleton?
public sealed class Singleton
{
public static Singleton Instance { get; private set; }
private APIClass _APIClass;
private Singleton()
{
_APIClass = new APIClass();
}
public APIClass API { get { return _APIClass; } }
static Singleton() { Instance = new Singleton(); }
}
Then your calling site looks like:
Singleton.Instance.API.DoSomething();
Or if you are the author of the API class, you could make it a singleton itself, instead of wrapping it in a singleton:
public sealed class SingletonAPI
{
public static SingletonAPI Instance { get; private set; }
private SingletonAPI() {}
static SingletonAPI() { Instance = new SingletonAPI(); }
// API method:
public void DoSomething() { Console.WriteLine("hi"); }
}
API call:
SingletonAPI.Instance.DoSomething();
Here is the official Microsoft approach.
The beauty of the singleton is that you can use and access it anywhere in your code without having to create an instance of the class. In fact that is it's raison d'etre, a single instance of a class eg
Singleton.Instance.MyValue and Singleton.Instance.DoSomething();
You wouldn't instantiate the class - the pattern you're using basically instantiates itself the first time it's used. The advantage to the method you're using is that it's thread safe (will only instantiate once, no matter how many threads try to access it), lazy (it won't instantiate until you try to access the Singleton class), and simple in implementation.
All you need to do to use this is to do:
Singleton.Instance.MyMethodOnSingleton();
Or, alternatively:
Singleton myInstance = Singleton.Instance; // Will always be the same instance...
myInstance.DoSomething();