2

I have in mind an idea for my first java project (OO focused). This project is some kind of a very basic roleplaying game (NO GUI, it's very basic), so I have some OOD questions.

A player (no player class is intended, at least for now) can choose a character class (you know, fighter, wizard etc... in the future he might be able to choose a few characters so he can have a party). After the character has been created he can fight against other foes (controlled by the program).

  • Each charcter has some info like: a character class (like fighter), Level, Armor Class, Abilities (Strength, Dexterity, Wisdom etc.).
  • Each Class has an inventory.
  • Each character has some methods like:

  • Attack (use a weapon, if he's a spell caster then casting spells also can use Attack).

  • Defend (like defensive spells or use abilities like parry. note: changes armor class.
  • Some character classes (like wizards) can Cast Spells. Most spells will are offensive or defensive, so they can use Attack or Defend method. let's say that castFireball can call Attack(20) for example. Some spells can do other things like castHeal which heals the character and changes the current hit points.

  • Buy (optional for future). same implementation for all characters of course.

  • Add/Remove from inventory.

Suggested implementation: I thought about creating an abstract class (with info like Level, Armor class, Abilities (like strength, dexterity, wisdom etc.). and some methods like attack and defend. Other specific classes will extend Character so it looks like:

                           Character (abstract)
                                 Character Class (like fighter)
                                 Level
                                 Hit Points
                                 Current Hit Points
                                 Armor Class
                                    .
                                    .
                                    .
                                 Inventory (List)

                                 Strength
                                 Dexterity
                                 Wisdom


  Fighter       Wizard         Rouge        Cleric   (All extends Character)

Questions:

  1. Using abstract class here is considered as a good design in this case? would you suggest using an interface and change the design ?
  2. Should I make a another class for Abilities like strength, wisdom etc. or it's ok that it's a part of Character ?
  3. Should I make another class for inventory? I think it might be better, right?
  4. Storing data for all weapons, armors, and shield (maybe other stuff in the future) by using enums is a good solution?
  5. Spells - I'm not sure what is a good way to implement them. I can create a spells class, with static methods for each spell (like castFireball, castHeal methods). Casting spells is relevant only to spell casters characters of course (and each character has a known spells list, so he can cast only spells he knows). Is it a good way to implement that? I can also use a txt file and get the relevant data from the file, but I'm not fond of this idea.

Keep in mind that it should be basic, but it should be planned for future changes and additions. It would look like:

How would you like to attack?

  1. Dagger (primary weapon)
  2. Sword
  3. Cast Spell

3

Which spell would you like to cast?

  1. Fireball
  2. Heal
  3. Ice Storm

1

You hit the enemy with a fireball, and dealt 20 damage.

It's very vague, but you get the idea..

Thanks a lot !!

5 Answers 5

1

I would advise against making Character an abstract base-class of (for instance) Fighter. Being a fighter is only an attribute of the character. I simply tells you that he can wield a sword and wear plate-mail, for instance. In some games, it is assumed that a Warrior character will always be a warrior. Then, when requirements change, so that a character can change class to, say, Mage, there is a whole data migration problem rather than simply a change of attributes. K

Keep your inheritance tree as shallow as you can. Use aggregation and composition instead of inheritance when you can.

Sign up to request clarification or add additional context in comments.

11 Comments

I think so plalx. In fact, I would go further and ask why a character can only be of one class. In some games, there are simply skills, and in such a game I can imagine checking this.skills.armorwearingskill >= armor.skillrequredToWear or some such. I think that provides more flexibility for when requirements change. And it can still fit in with a character class governing such aspects as you mentioned, through a character class being associated with a set of constraints on other attributes. Ability to handle changing requirements is the value here. If they won't change, inheritance is fine.
I see your point here. you're right that a character class is just an attribute. If a character can be more than one class then using aggregation and composition is a better design than inheritance. If a character can be only one character class then I abstract class works fine. Thanks for the tip :)
@Niminim Just ask yourself... is a character a class or a character has a class? Seeing composition where you first saw inheritance will often lead to much better designs.
I just thought about something - Let's say that I don't use Character as an abstract class, what about spell-casters. All characters can attack with weapons, buy things, and do other stuff, but only spell-casters can cast spells, so they have unique info like spells per day, total known spells etc, and another unique method - castSpells. Would it be a good idea to create a SpellCaster class, which will be a subclass of character ?
What's to prevent a warrior from training in spell-casting? If you are wedded to character classes, then by all means create subclasses of Character, but understand the limitations you are placing on future directions.
|
1

Generally, class B should be a subclass of A only if there is an is-a relationship between them - that is, if it would make sense to say that any instance of B also is an instance of A. By applying this, you can e.g. see that the character classes are the only viable candidates for subclasses of Character: A Warrior is a Character, but it is not the case that a Weapon is a Character. Instead, there is a has-a relationship between the other classes and Character: a Character has a Weapon. In that situation, you should use composition: the Character class could have a field of the type Weapon (or, more likely, a field of the type List<Weapon>, so that you can have multiple weapons).

But even if you can make a class hierarchy, it's not certain that you should. If the differences between the character classes can wholly be implemented as differences in stats (which are presumably just fields in the class) or some simple ability differences, you might only need the Character class. On the other hand, if the behavioral differences are huge and you'd end up with a bunch of if statements to select the appropriate behavior for various character classes in different situations, it might be wise to introduce subclasses. However, as @plalx and @B. Dalton point out, it is often possible to use composition instead, extracting the behavioral differences to an abstract CharacterAbilities class and its subclasses.

3 Comments

Sure at first it seems that a warrior is a character, but it's all a matter of perspective. Is a character a class or a character has a class? You can often turn things around to end up with composition instead and that leads to much more supple designs.
@plalx: Fair enough; see my new paragraph.
Thanks for the Advice, Aasmund !
0
  1. Using an abstract class here works very well since all other character classes will be extended from this class and the class itself is never instantiated.

  2. This is a matter of preference, if your abilities are more complex than integers you may consider making them a class, however if all you are doing is adding temporary buffs/debuffs I recommend having two integers for each ability: one for the current ability value and another for your base value without the buffs/debuffs.

  3. Having inventory as a class is a good idea. Some people may be tempted to create an array of inventory items and manipulate it as the game requires. I think creating a separate class keeps everything nicely encapsulated, even if you are just manipulating an array.

  4. Enumerations are useful in creating a weapon but I would also recommend a separate class for this as well. If you use enumerations for all items you may end up having to use a lot of math, specifically division and modular to get item types. Creating an item class and extending it to different item types allows all items to be contained in a common array using the parent class type while giving them different stats/abilities/uses.

  5. Spells can follow similar to the way I described items above (in fact a spell could be an item if you wanted to hold them in your inventory). Make sure to have some enumerations to describe the spell and its function and then a method to interpret these when it is cast.

3 Comments

1+2+3. Thanks! 4. I thought about creating enums for weapon, sields, armors, and "other stuff" separately, though creating another class also sounds good
5. If I get it right then you suggest that the enum will include the info and the method, and another method will call that method, right?
If you keep all your items as enumerations without classes you will need to run them through a translator whenever you want to print out their name, damage, or defense. This will end up being a very long switch statement but is definitely a way to solve it. I think storing this information in a class would be easier. For 5 I mean that all spells should have a common method that is called when cast, the enumerations tell what happens in this method. That way an object can cast a spell without really caring what spell it is and let the spell do the rest.
0

Classes should have a single responsibility (or more specific a single reason to change)

1) Abstract class looks the way to go, as you can have common behaviour contained in the class, reducing duplication. An interface only defines the 'contract'

2) See opening statement, sounds like another responsibility.

3) See 2

4) Depends on content, classes may be better

5) Maybe a different abstract class inheriting fro character to determine spell properties. Avoid static methods. Also worth looking at a design pattern for spells. Could have an interface with a method 'castSpell' and each spell implements its own functionality.

Plenty of different options - Best to have a go and see what works. If you get stuck, post the code.

Comments

0

As for weapons, shields and spells, I would model them into two interfaces:

  • PassiveItem - things that modify character's abilities without them needing to perform any actions (e.g. shield increases their defense)
    • This would have some kind of applyEffect() method that modifies the abilities (possibly create a copy of base abilities, then run all passive items' applyEffect() on those to get final abilities with items)
  • ActiveItem - weapons, items and spells that require character's action to have any effect
    • This would have method performAction(Character self, Character target) that would modify the tow combating characters in some way, e.g. HealSpell implementation would increase character's hitpoints stat, Dagger would perform an attack on the target.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.