Subclassing in C#?

I know this is more of a C# question than a Unity question, but I figure it's relevant all the same, and may help others as well in their endeavors. I have a couple questions all related to subclassing. (Whoa, first time I've typed in a title and UnityAnswers didn't have a single related suggestion for me!)

  1. How do I do it? I've actually done a lot of searching about this on Google but I haven't found any simple, easily-understandable answer. MSDN articles are way too complex when it comes to explaining things like this.

  2. Am I correct in assuming that subclassing would be useful for, say, having one script called "Health" and having every separate AI script subclass from it, thus allowing me to more or less "blindly" apply health changes to any enemy regardless of his type?

  3. If I subclass in Unity, can I just apply the last script in the hierarchy to my game object? I assume I would need to apply all the scripts manually, but I'm just making sure.

Thanks.

You subclass each time you write a C# script in Unity.

public class MyScript : MonoBehaviour // Subclassing MonoBehaviour
{
}

Yes, you could make a subclass called Health, although it's not very "component-based".

public class Health : MonoBehaviour
{
    public int health;
}

public class Enemy : Health
{
    // will inherit "health"
}

public class Player : Health
{
    // will inherit "health"
}

You don't often say "Enemy is a Health" but rather that "Enemy has Health", and it's a good rule of thumb for deciding when to use subclassing or slap on another component on them. Although we could just change our perspective and think of all the properties a "Character" has. You can only inherit from one base class (that base class can in turn inherit from something else). This next approach isn't much better, but it's a better name at least.

public class Character : MonoBehaviour
{
    public int health; // has health
    // Whatever else you can think of.
}

public class Enemy : Character // Enemy is a Character
{
    // will inherit "health", Enemy has health
}

public class Player : Character 
{
    // will inherit "health", Player has health
}

"Enemy is a Character", and "Characters have health".

So yeah, you can just replace the : MonoBehaviour for : MyOtherBaseClass, as long that base class evenutually inherit from MonoBehaviour. This applies when you want your classes to have the property of being placed on game objects.

A tip: For many things you want to share/mix properties of several concepts. Perhaps you want to have a Health script that your Enemy and Player want to use. You could add a health script to the same game object that has the enemy or player script. This is about separation of concerns, and your player/enemy would access the health script rather than have it built in, however how you prefer to write your code is entirely up to you. If you prefer to have health and other properties baked into a base class, go for it.

So, just to give you a little bit of options for your subclassing endevour, you should know about overriding methods.

public class Character : MonoBehaviour
{
    public void Speak()
    {
        print("I spoke!");
    }
}

public class Player : Character
{
    // Can also Speak
}

It would be nifty if Player could change how it speaks. We can change this with virtual methods. We change our Speak in Character to be virtual, and override Speak in Player.

public class Character : MonoBehaviour
{
    public virtual void Speak() // Added the 'virtual' keyword
    {
        print("I spoke!");
    }
}

public class Player : Character
{
    public override void Speak() // Added the 'override' keyword
    {
        print("Player spoke!");
    }
}

In this setup, if you had a reference to a Character type, that actually held a Player object, and called Speak(), it would execute Players version of Speak instead of the Characters version. It's a very silly method I wrote here, but the idea is that you can choose to do other things differently. Like, "UpdateMovement" might be done differently for an AI player than a Human Player. The human player would accept Input to make movement, and the AI player might make use of an A* Algorithm to traverse the level.

I hope it helped somewhat.

A short summary:

  • Subclassing give you all the properties and methods (all members) of the base class.
  • You can change the behaviour of methods by using the virtual and override keywords.
  • You can substitute any sort of Character where there's a Character reference needed.
  • Base classes are chosen with the : operator after the class name.
  • Unity scripts must subclass MonoBehaviour at some point in their inheritance.
  • Try to think of names for subclasses in a "is a" manner. What sounds correct?
    • "Player is a Health"
    • "Player is a Character"
    • "Player has a Health"
    • "Player has a Character"
  • The "is a" suggest to favor inheritance over compostion.
  • The "has a" suggest to favor composition over inheritance.
    • Done with member variables or another shared component on the same G.O.