ScriptableObject Method Overloading?

Let’s say that I have a database of spells/abilities in my game, and they all share a handful of standard fields (cooldown, cast time, mana cost, etc), but each have very custom behaviour (crowd control, projectile damage, AoE, etc). Ideally, I would like to have these spells show up in the asset list so that I can click on them and edit those common fields via the inspector, and have the custom behaviour defined in script.

I can use ScriptableObject to have the spell show up in the project and be editable and stuff, but I can’t figure out how best to go about defining the custom behaviour. The best solution I can think of is to have, say, a Spell class derived from ScriptableObject which has a public SpellBehaviour field, and that SpellBehaviour would point at the behaviour for the spell.

I feel like I should be able to simply overload the ScriptableObject and some of its methods to define the behaviour… But I don’t think that’s possible! Does this sound like an appropriate way to do what I’m trying to do?

Since we just have another very very old question that got bumped, here’s the answer ^^.

First of all you have to be more careful with the terms. Overloading and overriding are two completely different things. What you want is overriding and polymorphism. There are generally 3 ways how you can define a method that can be overridden:

  • Make a base class that has a virtual method
  • Make an abstract base class that has an abstract method
  • Define an interface and let another class implement that interface.

For ScriptableObjects that should be assignable in the inspector only the first two options apply. Generally you can use interfaces in Unity, but interfaces can’t be serialized by Unity so they can’t be assigned in the inspector.

public class MyBaseClass : ScriptableObject
{
    public string baseString;
    public virtual void Use()
    {
        Debug.Log("MyBaseClass-->Use()");
    }
}

public class SomeDerivedClass1 : MyBaseClass
{
    public override void Use()
    {
        Debug.Log("SomeDerivedClass1-->Use()");
        //base.Use();  // optionally call the base method that we have just overridden
    }
}

Somewhere else you can declare a variable of type MyBaseClass and assign a “SomeDerivedClass1” instance:

public MyBaseClass behaviour; // can be assigned in the inspector
// [ ... ]
behaviour.Use();

Now when you call behaviour.Use(); it will print "SomeDerivedClass1-->Use()" since we assigned a SomeDerivedClass1 instance.

Another way is to make out “MyBaseClass” class abstract like this:

public abstract class MyBaseClass : ScriptableObject
{
    public string baseString;
    public abstract void Use();
}

The derived class wouldn’t need to be changed at all. The differences are:

  • abstract methods do not and can not have a body.
  • a class that has at least one abstract method need to be abstract itself.
  • abstract classes can’t be instantiated.
  • In order to be no longer abstract, a derived class is forced to implement a body for all abstract methods.

So abstract base classes have the advantage that you can’t create an instance of the base class and it ensures that a derived class will implement your method.

So if you want to specify an “interface” that you’re going to use but don’t have any generic code for it, use an abstract method. If you instead want to specify an interface that has some generic code and a derived class might want to override the default behaviour but isn’t forced to, use a virtual method in the base class.