3
\$\begingroup\$

So I have a Class called Character which represents all the player, his companions, and all enemies. This class does a lot of things including performing actions upon other characters, and upon the environment, and so on.

I'm about to start work on a battle system for this RPG, and there will be the player controlled (and enemy controlled) units which will have a location on the screen, and a delay since their last action, and a ton of other properties and methods that apply entirely to the battle. But, this thing will also be associated in a one-to-one relationship with a Character which exists separate from a battle. It will need to access that characters stats for it's battle actions as well as some of it's methods.

So the root of my question is, is it better to create a new "Unit" class, which references the character it's associated with, or should I just expand upon the existing Character class with functions and properties that relate only to a battle? If it matters I'm writing this in C#.

\$\endgroup\$
  • \$\begingroup\$ Subclassing is specialisation. If your BattleCharacter really is completely a sub-type of Character, then subclass. Can you imagine a situation where a battling Unit might represent something other than a Character? (Maybe you might later want a CatapultUnit in the future which isn't a Character.) \$\endgroup\$ – Anko May 1 '14 at 14:20
  • \$\begingroup\$ Yeah, Character probably should be named something closer to "Entity". It's a thing with stats, skills, and it belongs to a Party. So even a non-living object with stats and skills would be a Character, only with different skills. I think I'm going to go ahead with "Unit" then. A follow up question would then be: What would be the best way to instantatiate this more specialized "Unit" class from an existing "Character" Object? Can I simply do something like: Unit mainUnit = (Unit)existingCharacter? If Unit inherits from Character? That really would be ideal I think. \$\endgroup\$ – Mason11987 Jun 3 '14 at 13:19
  • \$\begingroup\$ If Unit inherits from Character and existingCharacter is a Character, then Unit mainUnit = (Unit)existingCharacter would fail, because Unit is a subclass of Character and some Characters might not be Units. Did you mean the other way around (Character subclasses Unit)? \$\endgroup\$ – Anko Jun 3 '14 at 14:19
  • \$\begingroup\$ Okay, what I had in my head isn't right then. If I'm going to go this route I'd need to have my battle view utilizing a Unit object. But if all I had was a Character object, and Unit inherited from Character what would be the best way of setting up a Unit object which will have access to the data in an existing Character object? \$\endgroup\$ – Mason11987 Jun 3 '14 at 14:22
  • \$\begingroup\$ How about an interface? You could have Characters (and anything else even totally unrelated that can participate in a battle) implement IBattler; then they'll all be fine to store in an IBattler-type variable. \$\endgroup\$ – Anko Jun 3 '14 at 14:28
2
\$\begingroup\$

There are two principles behind my suggestion, SoC and SRP. That is, Separation of Concerns and the Single Responsibility Principle.

The main thing to note in your case is that your character, so far, is totally unrelated to combat. Generally speaking, if something isn't going to be used somewhere, it shouldn't even exist there. Creating things like your combat Unit as wrappers has another related benefit: it is a perfect example of Composition, which is (in the universe of OOP) generally considered a Good Thing.

So, happily split things where you can, and where things aren't needed, don't put them. The result will be a non-coupled design which will be easy to extend and maintain. This is a core principle of OOP, no matter the application.

Good luck!

\$\endgroup\$
1
\$\begingroup\$

First, a comment: it doesn't sound like you're using an entity/component model. I highly suggest that, because it will help you with your design, and it will also address this problem.

The "core" problem is not "the current representation of the player (on the map) now needs to go into battle." The problem is sprites, etc. are all specific to your current "view" (let's say the map view, as opposed to the battle view).

What I suggest is this: distil your Player class down to the core, permanent attributes that are there regardless of which view you're looking at. This will likely include:

  • Player name
  • Current/total health
  • Inventory
  • Skills
  • etc.

Once you have this done, it's just a matter of passing this data from view to view. When you pass it to the world map, it'll create the right sprite and render the player location, and allow you to move him.

When you pass it to the battle view, it'll recreate the right sprites, display health, turns, etc.

So the answer is not "new class" or "subclass," the answer is "extract your data from your current view and pass that around instead."

\$\endgroup\$
  • \$\begingroup\$ I actually do have it extracted, and the Map view actually just deals with whatever is given to it by the Character class. The problem is the Character class would need a large array of methods and properties as it relates to battling, in order for the Battle view to know what to draw or what options to give. But those methods and properties aren't meaningful outside of a battle. \$\endgroup\$ – Mason11987 Jun 3 '14 at 13:15
  • \$\begingroup\$ @Mason11987 so you should have a BattlePlayer class and a MapPlayer class. Keep the concerns separate (single responsibility per class), and pass around the shared data. \$\endgroup\$ – ashes999 Jun 3 '14 at 17:00
0
\$\begingroup\$

The main purpose of inheritance is to exploit the use of polymorphism. You may put the sub-classes in a collection data structure which type is the super-class of those sub-classes and then iterate over them, calling the same method with different implementations.

For example, when you create the class Vehicle. Suppose that when your game character calls forth a meteor down from the sky and then every vehicle in the surrounding AoE explodes. Based on this logic, you may create the method explode() in the Vehicle class. But, it would make no sense if a Bicycle explodes from a meteor crash, it has no fuel, why would it explode?.

The solution is to create the Explosive interface with the method explode() in it. Cars, buses, trains etc. implements the interface whilst Bicycle does not. So, the Collection type should be Explosive, iterate over it and call the explode method.

For your case, are you going to put the characters in the same group and call the same method in the future? If not, just create a new super-class.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.