Help Understanding Inheritance and its Uses

I am working on creating an RPG game that will work in similar fashion to games like the old-school Final Fantasy and Golden Sun games where I will have a main character that the player controls, but they will have party members along with him/her when going into battle.

I’ve been trying to figure out how to create a party system to where the game recognizes each character as a specific class while also being able to add them to the party or dismiss them and replace them with others like FF9 or Golden Sun to be specific as the type of class system I want to use in my game.

I came across a forum post, an old one but still was helpful, that talked about using Inheritance with the classes to make a base class then have each class or type of fighter (warrior, mage, etc.) be the sub class that inherits off of the main base class script. I’ve looked it up and still researching on how to use inheritance, but I wanted to see if my base understanding of the inheritance system is correct.

So, the way I see it is that the base class would work almost like the Wretch from Elden Ring. Even stats across the board, nothing special. Then each of the other classes (Samurai, Bandit, Warrior, etc.), are all the sub classes that would inherit the base class and then modify their stats based on each of their unique scripts and modify the stats accordingly, lowering the unused stats and raising those that the class is proficient with. I obviously realize that this probably isn’t how Elden Ring works considering each class is a different level and all, it was just the easiest thing I could thing of as an example mainly looking at the stats and variations.

Is this a correct understanding of how inheritance works or have I missed the mark somewhere in how Inheritance works?

Stats are just data, so there’s really no reason to make all of the subclasses. If the only difference between Bandit/samurai/warrior etc. are the stats then you only need one class. Just set the stats to different amounts. You could make each kind of character a different prefab or use Scriptable object to store the different default stats.

I think I get what you are saying. The classes will have other differences aside from stats such as types of armor and weapons they use.

Apologies I should have been more specific with what I was asking. I’m eventually looking to write script that can be used to add characters as party members but only if they are a combat type character and not a NPC. I tried using tags to identify the two different types of characters but my dialogue still activates the same choice of having them join the party whether I had them labeled as NPC in the tags or not. Each time I tried looking up how to do this in different ways I kept seeing the same article about using inheritance coding so I figured I would try that out and see if it is my solution.

Going off of what you said though kdgalla, would it be a better option to make each character its own script attached to it instead of trying to do the inheritance process? I might not be understanding how to use inheritance which was also my main question if I understood how it functioned in general.

None of this really needs to be inheritance based. They’re all just points of data that will likely be the same across all characters.

Remember Unity is component based. Take advantage of that.

Inheritance is a technique for sharing code.

For instance, if you have some function that is generally useful

public int CalculateSplines(int x, int y, float prickles) {
 // ...
}

Then you might share it using inheritance

public class Character {
  // define the code as a method
  public int CalculateSplines(int x, int y, float prickles) {
   // ...
  }
}

public class Warrior : Character {
  public void Dribble() {
    // we can call CalculateSplines likes it's a method of Warrior, because we inherited it from Character
    var splines = CalculateSplines(1, 2, 34.5);
    // ...
  }
}

Alternatively, you might just make a function (a method that’s not really attached to a class)

public static class Dribblat {
  // define the code as a function
  public static int CalculateSplines(int x, int y, float prickles) {
   // ...
  }
}

public class Warrior {
  public void Dribble() {
    // we can call CalculateSplines by accessing the static function of the Dribblat class
    var splines = Dribblat.CalculateSplines(1, 2, 34.5);
    // ...
  }
}

Or, you can use composition

public class Dribbler {
  public int CalculateSplines(int x, int y, float prickles) {
   // ...
  }
}

public class Warrior {
  Dribbler dribbler { get; }
  public Warrior(Dribbler d) {
    dribbler = d;
  }

  public void Dribble() {
    // we can call CalculateSplines by accessing our dribbler that was given to us as a dependency
    var splines = dribbler.CalculateSplines(1, 2, 34.5);
    // ...
  }
}

Each approach has pros and cons, though you will find inheritance is generally less flexible.

p.s. Please don’t attempt to interpret the method and type names. They are just nonsense.

2 Likes

I’ll use a Unity example for why you might want to use Inheritance.

Both a MeshRenderer and a SkinnedMeshRenderer inhert from an a Renderer Class.

This is useful because let’s say you have a script that changes the materials on a model. If you didn’t have inheritance you would need to write code to handle the MeshRenderer or a SkinnedMeshRenderer.

However because they both inherit from Renderer, to get the materials from either you can just say GetComponent().materials.

1 Like

Before C# and C++ even existed, we used to do stuff in C. In C you have structs which are data containers. So when you would have a profession such as fighter or mage, then you would make a common struct and then extend it with fighter or mage related stuff. Then the functions would use a pointer to that struct and eventually check the struct size or a specific field to determine which profession we are talking about. So for example if you had a function to print the profession title, the convention was to pass a pointer to that struct as first parameter.

typedef struct  {
    int type;
    char *title;
} Profession;

typedef struct {
    Profession profession;
    int numSpells;
} Mage;

typedef struct {
    Profession profession;
    int hpBonus;
} Fighter;

void printTitle(Profession *profession)
{
}

Classes make this stuff automated. With them you don’t need to pass the struct as parameter. Instead you have:

class Profession()
{
    string title;
    void printTitle()
    {
    }
}

class Fighter : Profession
{
    int hpBonus;
}

class Mage: Profession
{
    int numSpells;
}

and then:

Profession profession;
profession.printTitle();

And for checking whether you have a mage or fighter you do this:

if (profession is Mage) {
}
else if (pression is Fighter)
{
}

These days, classes do a lot more than this but that’s the basic of how they work.