Deserialization for instantiation of derived classes with different behaviour...

Hello again!

This time I come with a tricky question for which I have not been able to find a solution in this forum, let’s see if someone can enlighten me.

In the little game I’m developing, I have multiple skills, let’s say 100 hundred for example. In order not to create 100 specific skills that inherit from a Skill base class, my idea is to use composition. My plan is to use ScriptableObjects or JSON files that store the data per skill, load them when I need them and create a Skill instance with the values loaded from a SkillFactory. So far so good, unless someone tells me otherwise (I’ll be happy to hear about any other possibilities).

The problem comes when some of these skills offer different behaviors:

  • Some will damage the target (may include debuffs).
  • Some will heal the target (may include buffs)
  • Some will create new entities
  • Some may buff/debuff
  • Etc…

So my initial idea was to create some derived classes that inherit from Skill: DamageSkill, HealSkill, SpawnSkill and so on…

What I don’t quite know is how to create the correct specific instance of the derived class. First, I tried using JSON files, but as far as I know there is no easy way to use JsonUtility that allows serialization / deserialization of derived classes. Secondly, I tried using ScriptableObjects but I end up having a similar problem because in order to know the instance I need to create, I need the type which unfortunately is inside the SkillData stored in memory, so I can’t know it before loading the data.

Should I pull the Skill type from the SkillData class, so I know in advance what I’m going to load from memory? It seems to me the only possibility, but I think I’m missing something?

I hope I have made myself clear, so that you can help me on this, because I have been dealing with this issue for several days and I can’t find a way to solve this situation.

Thanks a million in advance

Just use scriptable objects as the factory for these skills themselves, or as a wrapper around one. No need for JSON files or to load things on the fly; that’s just needlessly complicating the process. Just reference the scriptable objects and pull the skills out of them on an as-need basis.

You can achieve polymorphic serialisation in Unity with the [SerializeReference] and some custom inspector work.

Could be as simple as this:

[CreateAssetMenu]
public sealed class SkillFactoryObject : ScriptableObject
{
    [SerializeReference]
    private ISkillFactory _skillFactory = null;
   
    public ISkill GetSkillInstance() => _skillFactory?.GetSkillInstance();
}

public interface ISkillFactory
{
    ISkill GetSkillInstance();
}
1 Like

But when you call the method → public ISkill GetSkillInstance() => _skillFactory?.GetSkillInstance();
I understand you need to send a string or something similar as an argument to instantiate the correct skill within the specific SkillFactory, right?

Or am I missing anything?

Thanks for your help! :slight_smile:

You just need references to a skill factory scriptable object and get the skill instance.

If it wasn’t clear, you would make plain C# types implementing ISkillFactory and select them via a custom inspector you would make for the SkillFactoryObject.

1 Like

It is possible that I am missing something, but I do not see where I can define each unique Skill parameters. Should these parameters be part of the SkillFactoryObject? Which means I would have around 100 SkillFactoryObjects with customized parameters and via customized Editor I can select which ISkillFactory instantiates them? And where is the behaviour per Skill group coded? Inside each ISkill variant?

Somehow I think your solution is what I’m looking for, but I’m not able to figure out how it works. sorry if I’m being a bit annoying and thanks again for your help!

The ISkillFactory would have your values that you edit, which it then passes into the skill that it constructs. The ISkill interface would be the base interface for the skill themselves, which outlines the most core functionality.

An in use example would be something like this:

[System.Serializable]
public sealed class SkillFireball : ISkill
{
    [SerializeField]
    private float _damage = 100f;

    public string SkillName => "Fireball";

    public float Damage => _damage;

    public SkillFireball(SkillFactoryFireball factory)
    {
        _damage = factory.Damage;
    }

    public sealed class SkillFactoryFireball : ISkillFactory
    {
        [SerializeField]
        private float _damage = 100f;

        public float Damage => _damage;

        public ISkill GetSkillInstance()
        {
            return new SkillFireball(this);
        }
    }
}

And then in use would look like:

(This is using Odin Inspector)

2 Likes

OK, now I got it! Thank you very much for your help :slight_smile:

1 Like