views:

146

answers:

4

Hi folks,

I'm making a very simple 2D RPG in Java. My goal is to do this in as simple code as possible. Stripped down to basics, my class structure at the moment is like this:

  • Physical objects have an x and y dimension.
    • Roaming objects are physical objects that can move().
      • Humanoid objects are roaming objects that have inventories of GameItems.
        • The Player is a singleton humanoid object that can hire up to 4 NPC Humanoids to join his or her party, and do other actions, such as fight non-humanoid objects.
        • NPC Humanoids can be hired by the Player object to join his or her party, and once hired can fight for the Player.

So far I have given the Player class a "party" ArrayList of NPC Humanoids, and the NPC Humanoids class a "hired" Boolean.

However, my fight method is clunky, using an if to check the party size before implementing combat, e.g.

public class Player extends Humanoids {
   private ArrayList<Humanoids> party;
   // GETTERS AND SETTERS for party here
   //...

   public void fightEnemy(Enemy eneObj) {
      if (this.getParty().size() == 0)
        // Do combat without party issues
      else if (this.getParty().size() == 1)
        // Do combat with party of 1
      else if (this.getParty().size() == 2)
        // Do combat with party of 2
      // etc. 

My question is, thinking in object oriented design, am I on the right track to do this in as simple code as possible? Is there a better way?

+2  A: 

Well, forgetting the overall design, from a basic programming point of view, instead of having that if structure, you should have a method that takes the party size as an argument. That way, you can just pass in this.getParty().size() and get rid of the ifs.

i.e.

  combatManager.fight(this.getParty().size(), eneObj);

Where combatManager is an object (or class, if you want a static version) that knows how to make things fight.

As I said though, this is not a solution for your design, simply a nicer way to avoid the ifs.

The Player class should not be responsible for making things fight, so perhaps you could change your fightEnemy method to engageEnemy or something, and simply have it go to the combatManager with the correct parameters.

Chris Cooper
@Chris Cooper: Java classes needs an uppercase so it's not clear if you suggest a helper class (with a static *fight()* method) or an instance of a class. In any case, you're just shifting the issue to the *fight* method: the class won't know how to magically make "things fight". Especially if the OP's method is already called *fightEnnemy* it's not 100% clear that another method *fight* would be really helpful.
Webinator
@WizardOfOdds: I agree with what you said. I made it uppercase, but in the original post, I don't think it really matters what it is. I was not suggesting how he lay out his architecture, simply how he handle that specific problem. And I agree that another fight method may not help, but in reality, the Player class should not be responsible for know how to make things fight.
Chris Cooper
@ Chris and Wizard, thanks for the discussion. It's clear that I have to go back to the drawing board to make this RPG smoother from the beginning.
Arvanem
A: 

Perhaps this would be a nice opportunity to use the Strategy Design Pattern. This way you can change the fighting strategy which will be used when party members are added or removed, rather than every fight.

tjohns20
Thanks for the helpful link that sets out that Pattern clearly. I've struggled to understand the Strategy Design Pattern before.
Arvanem
+6  A: 

"My question is, thinking in object oriented design, am I on the right track to do this in as simple code as possible?"

No, and your description uses the essential verbs that describe how your design is built on too much inheritance.

Physical Objects have an x and y dimension (position).
[A Roaming Object is a Physical object that has a changeable position]
Humanoid objects are roaming objects that have inventories.
The Player is a singleton humanoid object that can have a party
[A party has a player and] has up to 4 NPC Humanoids

Composition, although too rarely stressed in object-oriented design has a role to play in code. This is why the has-a / is-a distinction is so often used in analysis.

By declaring a player as a singleton, you've added type complexity and possibly limited your design. What if you'd like to have two players at some future point? How about more? This is not an unreasonable extension but would require that you break the singleton anti-pattern used. If you only want one player, only instantiate one; coding the singleness assumption into the class is unnecessarily limiting. Remember that the coder has to affirmatively call a constructor and need not worry about Players spontaneously appearing.

An object has a position, great: give it one through composition. A position can be changed, so define position::move(). A Player may have a human controller which distinguishes it from an NPC, but - by definition - a non-player character indeed is a character, one which has control that doesn't come from a player. Might you want to give an NPC player control? Many games do, but if you have already encoded the player-character dependency inside a class, an NPC will always be an NPC.

Also, how certain are you that 4 (or 5) is a good number for a party? The Zero, One, Infinity principle says that if you will allow more than one, allow an arbitrary number. If you don't hard code "five-ness" into your design, you limit flexibility.

I generally recommend that designers consider inheritance a method of last resort because of a history of overzealous use. A design can be OOP with no inheritance at all. Polymorphism is cool, but so are encapsulation and abstraction, perhaps even more so.

msw
+1 plus one for being well-versed in all things OOP
puddingfox
Thanks for your comments. This is why I come to Stack Overflow. It's about getting coding right from the beginning rather than coming back to a mess, which in my case, involves too much inheritance.
Arvanem
A: 

The player is part of the party. The NPCs are part of the party too. Why would the player handle NPC combat? I think you should add that logic into the NPC class (extends Humanoid) and let add some AI so that NPCs will act with the player and other NPCs when they are grouped together.

Tom
@Tom: thank you for your response. FYI, I have made an overarching Characters class implement a Hireable interface, which has a method hire(Characters hiree). When called, hire adds a hiree to the party of the object calling hire. ATM, I am initialising the Player to have a party of 1 by calling hire(player). It is a clunky solution again. Do you have any suggestions?
Arvanem
@Tom, don't worry about answering. It's difficult to grasp what I am doing, you need to see code. If I can't work it out, I'll post it later as a question on StackOverflow.
Arvanem