- Home /
Can I refer to a custom abstract class as a MonoBehaviour property?
Hi, I'm new to Unity and C#; and this is my first question. Here is my problem:
In my MonoBehaviour C# script, I have a reference(public attribute) to an abstract class I created in a second C# script. See the example:
Abstract class:
using UnityEngine;
using System.Collections;
[System.Serializable]
public abstract class CustomBehaviour {
public abstract void Activate(GameObject gameObject);
}
My MonoBehaviour:
using UnityEngine;
using System.Collections;
public class OnCollisionEvent : MonoBehaviour {
public CustomBehaviour behaviour;
public void OnCollisionEnter(Collision collision)
{
if (behaviour != null)
{
behaviour.Activate(this.gameObject);
}
}
}
The problem is, in the Inspector of my GameObject, when I put a script component with OnCollisionEvent, the Inspector does not show the behaviour property to setup.
I understand that this occurs because CustomBehaviour class is abstract and I can't create any instance, and if there's no instances, there's are no attributes.
What I wanted is that I could select my concrete instance of behaviour property(a derived class of CustomBehaviour) in the inspector, like this:
My concrete CustomBehaviour:
using UnityEngine;
using System.Collections;
[System.Serializable]
public class DieBehaviour : CustomBehaviour {
override public void Activate(GameObject gameObject)
{
Object.Destroy (gameObject);
}
}
So that Unity would instantiate a concrete CustomBehaviour of my choise for behaviour attribute of OnCollisionEvent script.
How can I do that? And if not possible, what is the best approach in Unity to have dynamic custom behaviours like this? (Similar to Gof's Strategy Pattern)
I would imagine this could be achieved with an enum which is set from the inspector. A custom strategy would then be instantiated based on that enum value, e.g. in Awake...
Alternatively, you could make your custom behaviors ScriptableObjects, then create an asset for each object and assign those in the inspector.
Neither is a good, robust solution, but I'm hoping someone with more time can come up with an answer.
$$anonymous$$y gut feeling is that you should be able to get what you want if you write a custom property drawer for your abstract type and make it chain through a virtual method to let the derived behaviour instances offer whatever fields they want. For null it would need to allow the user to provide an instance, for example by offering an enum selector to chose a type to construct.
I would seriously consider going down the ScriptableObject route though. If you want multiple objects to share the same behaviour instances - including settings - then this is the way to go, and you'll be able to drag and drop them into the inspector just like any other first class asset.
The problem with ScriptableObjects is that if my OnCollisionEvent have a CustomBehaviour (and assu$$anonymous$$g that CustomBehaviour is a subclass of ScriptableObject), I won't be able to drag DieBehaviour assets to a OnCollisionEvent component in the inspector, only CustomBehaviour assets.
Answer by Bunny83 · Feb 04, 2014 at 03:47 AM
The serialization system can't serialize your custom class in your case. Inheritance for custom-serializable classes doesn't work at all. However, is there a reason you don't want to use MonoBehaviour as baseclass for CustomBehaviour? It would be bound to the instance, can be serialized properly. If you want to have one instance for all objects that share the same CustomBehaviour then i would also suggest ScriptableObject as baseclass.
Since DieBehaviour is derived from CustomBehaviour it can always be assigned to a CustomBehaviour field, that's one of the major points of inheritance.
Just to clarify: custom classes with the serializable attribute aren't really serialized as own instance. Only the fields of the instance get serialized along with the MonoBehaviour which contains the reference to the instance.
In most cases i would suggest MonoBehaviour as baseclass since it's way easier to use than ScriptableObject. You can also use a prefab as instance holder if you only want one instance. The prefab can be assigned to multiple references if you like.
Your answer
Follow this Question
Related Questions
List of Inherited abstract Objects assigned via Inspector 1 Answer
Inspector attribute for showing a field with a custom name? Possible? 1 Answer
[Range] attribute saves to undo-history too often. 1 Answer
Abstract Inspector-Manipulable Objects that aren't GameObjects? 2 Answers
Add AudioSource-Like Range to Script 1 Answer