My empirical tests seem to imply this is not possible. But just in case, I figured I’d ask:
The Unity documentation for MonoBehaviour exposes several “messages”. They call them messages anyway. As fas as I can tell (I’m on C#) they are really neither delegates nor events nor overrides, but rather, arbitrary agreed methods which if you implement in a MonoBehaviour, the runtime knows can be called probably thru reflection.
So for instance, I’m trying to create a wrapper network services class around Unity’s Netowrk
class. And since my class needs to be available between scenes and there is only ever going to be one state, I wanted to go for either just class methods or a singleton.
My first test was with static classes and concrete classes. And my findings where:
-
You cannot create static classes derived from neither
MonoBehaviour
norScriptableObject
. -
You can create concrete classes derived from these, but the messages need to be instance methods; they cannot be class methods. So for instance this wouldn’t work:
public class NetworkServices : MonoBehaviour {
public static void Init() {
Debug.Log(“Init”);
Debug.Log(Network.InitializeServer(2, 2500, !Network.HavePublicAddress()));
}private static void OnServerInitialized() {
Debug.Log(“server initialized”);
}}
But this would:
public class NetworkServices : MonoBehaviour {
public static void Init() {
Debug.Log("Init");
Debug.Log(Network.InitializeServer(2, 2500, !Network.HavePublicAddress()));
}
private void OnServerInitialized() {
Debug.Log("server initialized");
}
}
Which seems to confirm that the ‘message’ methods need to be instance methods. So I need an instance. Ok. Now, if I had a MonoBehaviour
attached to a game object, the above code (second example) would work, because attaching the Script to a GameObject
implies instantiating it. But the truth is that I don’t need to create instances since I need to always access the same one. And neither do I want to go about attaching one of these scripts to some object on every scene to have it instantiate. So I tried the following:
public class NetworkServices : ScriptableObject {
private static NetworkServices _SharedInstance;
public static void Init() {
Debug.Log("Init");
if (_SharedInstance == null) {
Debug.Log("creating instance");
_SharedInstance = CreateInstance<NetworkServices>();
}
Debug.Log(Network.InitializeServer(2, 2500, !Network.HavePublicAddress()));
}
private void OnServerInitialized() {
Debug.Log("server initialized");
}
}
Which on the outside (public API) would look like simply class methods, but in reality is creating an instance (just because the message callback needs to be an instance method). So it’s kind of using a hidden singleton. But this does not work. I used ScriptableObject
because in theory it allows me to create instances not attached to a GameObject
. But OnServerInitialized
is never called. However, here’s a hack that does sort of work:
In theory, you cannot attach a ScriptableObject
to a GameObject
. Also, in theory, OnServerInitialized
is a message of MonoBehaviour
and not of ScriptableObject
; ScriptableObject
inherits from Object
and not from MonoBehaviour
. But if Ido the following:
- change the base class in the above script to
MonoBehaviour
- Add the script to a
GameObject
in the scene. - change the base class back to
ScriptableObject
I end up with a ScriptableObject
attached to a GameObject and the the message gets called.
So from the above it seems that the requirements for the Unity messages to trigger are:
- They need to be instance methods.
- There needs to be an instance attached to a
GameObject
- COROLLARY OF SORTS: Actually the messages are not exclusive to
MonoBehaviour
My 2 questions are:
- Are the above requirements / facts indeed true?
- Is there a way around requirement 2? Basically I want to get the networking messages / callbacks but I don’t want to attach a script to an object on each scene just to access the singleton / class.