Hello,
I’m new to Unity3D. I’m used to Object Oriented Programming. Going from Java → Unity3D and C#, I was looking for a good way to structure my classes, including game object properties and inheritance from super classes shared by different prefabs that each have their own subclass scripts. Below is one way to do it. If my reasoning and solution below feels obvious and trivial, feel free to disregard. This was a way for me to learn and find out a solution as many other answers were not as detailed and they lacked examples.
Let’s say I want to have some prefab game objects:
- a Vampire game object
- a Skeleton game object
They have their own special properties, implemented in corresponding scripts
- Vampire script (class)
- Skeleton script (class)
typically added to their prefabs.
… but I want them to share properties and behaviour from an abstract super class “Creature”.
The class hierarchy could be much more sophisticated (e.g. Creature has other subclasses, like Human, Animal, etc), but to keep this example simple, this is one way to do it:
The super class “Creature” inherits the MonoBehaviour:
public class Creature : MonoBehaviour
{
int hp;
string name;
//This works as a base constructor, to be called in the subclass's Awake() or Start()
public void Init(string name, int hp)
{
this.hp = hp;
this.name = name;
}
public virtual void ShowStats()
{
print("Hello, I'm "+name+", and my HP= "+hp);
}
}
The Vampire and Skeleton classes inherit from Creature… and they can add extra behaviour, e.g. in overriding methods:
public class Vampire : Creature {
// Use this for initialization
void Start()
{
base.Init("Vampire", 2);
}
public override void ShowStats()
{
base.ShowStats();
print("... and I'm a blood sucker too!");
}
}
public class Skeleton : Creature {
// Use this for initialization
void Start()
{
base.Init("Skeleton", 1);
}
}
The sub classes - NOT Creature - will be attached to the Vampire and Skeleton prefabs.
The game logic can then find all game objects tagged with “Creature” and iteratate through them, like this:
public class GameLogic : MonoBehaviour {
// Update is called once per frame
void Update ()
{
if (Input.GetKey(KeyCode.Space))
{
foreach ( GameObject creature in GameObject.FindGameObjectsWithTag("Creature"))
{
creature.GetComponent<Creature>().ShowStats();
//We can then invoke creature specific behaviour, e.g.
if (creature.name.Equals("Vampire"))
{
//Do some cool vampire-specific stuff, e.g life draining...
}
}
}
}
}
This gives us…
- Hello, I’m Skeleton, and my HP= 1
- Hello, I’m Vampire, and my HP= 2 … and I’m a blood sucker too!
Advantages:
- Only one actual GameObject is needed to contain both subclass and superclass(es).
- Only one script (the subclass) needs to be attached to the prefab. Super class script(s) are included through inheritance.
Drawback with my outlined solution without a constructor:
I did not use a constructor as the Unity framework recommends using Awake() or Start() instead of normal class constructurs. Therefore, superclass initializer parameters is not enforced by compile errors, so it is possible to “forget” to pass initializer parameters to the superclass. There are surely ways to solve it. One way could be to create an abstract method in the superclass to, sort of, remind the implementor which parameters to initialize. But maybe there are better and more correct ways.
Another disadvantage:
If we want a clean logical model of our game objects, without connections to the actual “view”. Consider the Model-View-Controller design pattern where Unity GameObjects are intimately associated with the View.
While programming AI, we might want to handle a pure logical model of the game world to evaluate possible game world changes and future moves and positions of game creatures WITHOUT showing it in the view! In this case, we don’t want all that extra stuff inherited from the Unity framework in our objects, because sometimes, we won’t always create those GameObjects. We only want temporary “abstract” models for the AI algorithm to evaluate.
For this case, it may be better to have a pure logical class hierarchy of the game world and creatures in it, without inheritance from Unity MonoBehaviour. In that case, the Creature class shall NOT inherit from Unity MonoBehaviour. Instead the default script in each creature prefab should CONTAIN a pure logical Creature object (instantiated as the proper subclass.) In this case, we use OO “composition” instead of OO “inheritance”.
Please let me know if I got this all wrong and if it would be natural to do something entirely different, but it seems to work for me.
Best Regard
/Christian, Craze Music / Craze Creature Studios
www.craze.se