2
\$\begingroup\$

I am trying to make a JRPG style game using Unity. See this image below to get a sense of the "feel" of the type of game I am making:

http://www.juicygamereviews.com/uploads/3/0/5/0/30501048/9185639_orig.jpg

Currently I'm struggling to find a good way to organize the data in my game.

Referring to the image above, see how each party member has stats, as shown in the UI? I'm sure the monster also has the same kinds of stats, just hidden away. Hence, I want to make a struct called Stats, that both PartyMembers and Monsters contain a reference to.

To summarize what I'm saying so far:

Right now I'm pretty sure I want two classes - one called PartyMember and one called Monster, both of them deriving from a common class - I'll call it TurnTaker - that takes turns during battle. In the TurnTaker class I want a reference to a struct called Stats, which contains HP, MP, Attack, Defense, etc.

The problem is, for player data I want the Stat class to be [Serializable] because I want to save player progress in a binary format, yet for Monsters I wish to make the Stat class inherit from Scriptable Object (SO) for easy development and editing.

Is it possible to make Stats both serializable and derive from SO in Unity? (Note: a struct cannot derive from SO; only a class can. Should I change my stats from a struct to a class? Seems a bit of a waste, just for the inheritance functionality.)

Further, I'm thinking party members have data specific to themselves (equipment, total EXP, character class, etc), as do monsters(drop items, movement type, etc.)

Should I make these two "things," I'll call them PartyMemberSpecificData and MonsterSpecificData

  • separate classes altogether
  • separate interfaces that attach themselves to PartyMember, Monster, or Stat
  • classes that derive from Stats

(I think I want PartyMember to contain a reference to PartyMemberSpecificData and Monster to contain a reference to MonsterSpecificData.)

Any help appreciated!

\$\endgroup\$
1
  • \$\begingroup\$ You shouldn't use an object oriented approach for games. Look into entity component systems. It's thhe main way unity handles entities \$\endgroup\$
    – Bálint
    Aug 4, 2017 at 23:10

2 Answers 2

2
\$\begingroup\$

I'd second Bálint's comment above that inheritance is not necessarily the best pattern to use here. Especially in a component-based engine like Unity, you may find that favouring composition over inheritance gives you more flexibiity.

I might try something like this:

[System.Serializable]
public struct Stats {
   public int Attack;
   public int Defense;
   public int Magic;
   // etc.
}

// Plain old data structure - this just makes it easy to 
// author shared stats objects in the Unity editor.
[CreateAssetMenu(fileName="Stats.Asset", menuName="Character/Stats")]
public BaseStats : ScriptableObject {
   public Stats stats;
}

// Attach this to your characters/monsters and 
// reference their base stats object in the Inspector.
public RuntimeStats : MonoBehaviour {
    public BaseStats baseStats;
    public Stats current;   

    void Awake() {
        current = baseStats.stats;
    }
}

Using this "has-a" relationship, you get:

  • a single common Stats struct that's ready to serialize into a save file if needed

  • a BaseStats object you can store as an asset in your project and share between multiple instances of a character archetype (eg. every goblin can reference the same base goblin stats)

  • a mutable runtime instance of the stats that can be attached to a character instance, can be influenced by leveling / status effects, and is easy to reset to the shared base stats for the archetype when needed. Both party members and monsters can reference this component, they don't each need to implement their own version (unless they need unique stats, but even that can be accommodated with only small variations to the pattern above)

You can carry this "has-a" relationship through the rest of your design too:

  • Rather than have a MonsterData class to handle drops, have a DropPayload component that both monsters and chests can share. Maybe you can also attach this component to a spell effect to make an item-summoning spell!

  • Rather than a PartyMember class handling equipment, have an Equipment component. Then you can freely mix and match, having a monstrous party member who doesn't wear equipment, or town guard "monsters" you can fight, who do wear equipment.

  • Rather than a PartyMember class handling experience and leveling, have an Experience component you can attach to party members. You can then clone the party member and take off the experience component if you need to fight a fixed-level version of a party member as an "evil twin / shadow version" monster at some point. ;)

Thinking about each feature as a self-contained component can give you a lot of freedom to create new gameplay scenarios just by mixing & matching code you already have, in ways that would be much more laborious if everything were bound in strict inheritance hierarchies.

\$\endgroup\$
1
  • \$\begingroup\$ Very interesting, I'll check it out. Thanks for explaining so clearly! \$\endgroup\$ Aug 5, 2017 at 1:43
0
\$\begingroup\$

You can serialize ScriptableObjects as json or binary.

using UnityEngine;

// Custom asset type that prefers binary serialization.
//
// Create a new asset file by going to "Asset/Create/Custom Data".
// If you open this new asset in a text editor, you can see how it
// is not affected by changing the project asset serialization mode.
//
[CreateAssetMenu]
[PreferBinarySerialization]
public class CustomData : ScriptableObject
{
    public float[] lotsOfFloatData = new[] { 1f, 2f, 3f };
    public byte[] lotsOfByteData = new byte[] { 4, 5, 6 };
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .