Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm about to start a simple browser text RPG, with characters that can (passively) fight other people. This involves a list of about 10 skills like strength, dexterity and so on, with additional proficiencies for different weapons.

Is there a better way to design this character class then just having those skills as class attribute? It seems easy, but I'm reluctant because it's clumsiness.

class Char(self):
    int strength
    int dexterity
    int agility
    ...
    int weaponless
    int dagger
    ...
share|improve this question
1  
You should check this alltogether guide for writing games and how some of the common classes might look like link –  dragons Mar 19 at 8:16
    
@dragons Thanks for the interesting link, but I see no deeper explanation for designing the Charactor class? –  Sven Mar 19 at 8:21
1  
What exactly do you find "clumsy" about this design? –  Thomas Mar 19 at 12:19

6 Answers 6

As long as you keep your system relatively simple, this should work. But when you add things like temporary skill modifiers, you will soon see a lot of duplicate code. You will also run into problems with different weapons using different proficiencies. Because each skill is a different variable, you will have to write different code for each skill-type which basically does the same (or use some ugly reflection hacks - under the condition your programming language supports them).

For that reason I would recommend you to store both skills and proficiencies in an associative data-structure which maps skill-constants to values. How to do that elegantly differs from programming language to programming language. When your language supports it, the constants should be in an enum.

To give you an example how this would work in practice, your code for calculating attack damage would then look something like that:

int damage = attacker.getSkill(STRENGTH) + 
             attacker.getProficiency(weapon.getProficiencyRequired()) -
             defender.getSkill(TOUGHNESS);
share|improve this answer
    
Creating a method like getSkill() goes against the fundamental principle of object-orientated programming. –  Jephir Mar 27 at 2:59

Why not use associated arrays?, this gives the benefit of being easily extended (using PHP for example)

$Stats["Strength"] = "8";
$Stats["Dexterity"] = "8";

for things such as weapons, you would probably want to create some base classes

Weapon -> MeleeWeapon, RangedWeapon

and then create your weapons from there.

The end result I would aim for is a class looking like this

class Character
{
    public $Stats;
    public $RightHand;
    public $LeftHand;
    public $Armor;
    public $Name;
    public $MaxHealth;
    public $CurrentHealth;

    public function __construct()
    {
        //Basic
        $this->Name = "Fred";
        $this->MaxHealth = "10";
        $this->CurrentHealth = "10";

        //Stats
        $this->Stats["Strength"] = 8;
        $this->Stats["Dexterity"] = 8;
        $this->Stats["Intellect"] = 8;
        $this->Stats["Constitution"] = 8;

        //Items
        $this->RightHand = NULL;
        $this->LeftHand  = NULL;
        $this->Armor = NULL;

    }
}

You could store everything in an array if you really wanted too.

share|improve this answer
    
That is pretty much what @Philipp said? –  Zehelvion Mar 19 at 16:22
1  
@Philipp suggested the use of enums, arrays are another option. –  Grimston Mar 19 at 16:26
    
It actually says: "...associative data-structure which maps skill-constants to values", the constants in the dictionary could be strings. –  Zehelvion Mar 19 at 17:50

I'll try to answer this question the most OOP way (or at least what I think it would be). It may be completely overkill, depending on the evolutions you see about the stats.

You could imagine a SkillSet (or Stats) class (I'm using C-like syntax for this answer):

class SkillSet {

    // Consider better data encapsulation
    int strength;
    int dexterity;
    int agility;

    public static SkillSet add(SkillSet stats) {
        strength += stats.strength;
        dexterity += stats.dexterity;
        agility += stats.agility;
    }

    public static SkillSet apply(SkillModifier modifier) {
        strength *= modifier.getStrengthModifier();
        dexterity *= modifier.getDexterityModifier();
        agility *= modifier.getAgilityModifier();

    }

}

Then the hero would have an intrinsicStats field of the SkillSet type. A weapon could have a modifier skillSet as well.

public abstract class Hero implements SkillSet {

    SkillSet intrinsicStats;
    Weapon weapon;

    public SkillSet getFinalStats() {
        SkillSet finalStats;
        finalStats = intrinsicStats;
        finalStats.add(weapon.getStats());
        foreach(SkillModifier modifier : getEquipmentModifiers()) {
            finalStats.apply(modifier);
        }
        return finalStats;
    }

    protected abstract List<SkillModifier> getEquipmentModifiers();

}

This is of course an example to give you idea. You may also consider using the Decorator design pattern, so that the modifiers on the stats work as "filters" that are applied one after the other…

share|improve this answer
    
How is this C-like? –  bogglez Mar 19 at 19:07
    
@bogglez: I likewise tend to use "C'ish" to refer to pseudocode that loosely resembles a curly-brace language, even if classes are involved. You do have a point, though: this looks like way more specific syntax -- it's a minor change or two away from being compilable Java. –  cHao Mar 19 at 21:44
    
I don't think I'm being overly strict here. This is not just a difference in syntax, but a difference in semantics. In C there is no such thing as a class, templates, protected-qualifiers, methods, virtual functions, etc. I'm just not fond of this casual abuse of terms. –  bogglez Mar 20 at 7:58
    
As the others said, curly-brace syntax comes from C. The syntax of Java (or C# for that matter) is highly inspired by this style. –  Arlaud Pierre Mar 20 at 8:32

The most OOP way of doing things would probably be doing something with inheritance. Your base class (or super class depending on language) would be person, then maybe villains and heroes inherit from the base class. Then your strength based heroes and flight based heroes would branch off as their mode of transport is different, for instance. This has the added bonus that your computer players can have the same base class as the human players and it will hopefully simplify your life.

The other thing regarding attributes, and this is less OOP specific would be to represent your character attributes as a list so you don't have to have them all defined explicitly in your code. So maybe you would have a list for weapons and a list for physical attributes. Make some sort of base class for these attributes so they can interact, so each one is defined in terms of damage, energy cost, etc. so when two individuals come together it is relatively clear how the interaction will take place. You would iterate through the list of each character's list of attributes and calculate the damage one does to the other with a degree of probability in each interaction.

Using a list will help you to avoid rewriting a lot of code as in order to add a character with an attribute you hadn't thought of yet, you just have to make sure it has an interaction that works with your existing system.

share|improve this answer
4  
I think the point is to decouple the stats from the hero's class. Inheritance is not necessarily the best OOP solution (in my answer I used composition instead). –  Arlaud Pierre Mar 19 at 14:35
1  
I second the previous comment. What happens if a character C has properties from character A and B (which both have the same base class)? You either duplicate code or face some problems concerning multiple inheritance. I would favor composition over inheritance in this case. –  ComFreek Mar 19 at 16:10
1  
Fair enough. I was just giving the OP some options. It doesn't look like there is much set in stone at this stage and I don't know their experience level. It would probably be a bit much to expect a beginner to pull off full blown polymorphism, but inheritance is simple enough for a beginner to grasp. I was trying to help address the issue of the code feeling 'clumsy' which I can only assume refers to having fields hard coded that may or may not come into use. Using a list for these types of undefined values imho is a good option. –  GenericJam Mar 19 at 16:27
    
-1: "The most OOP way of doing things would probably be doing something with inheritance." Inheritance is very not particularly object-oriented. –  Sean Middleditch Mar 20 at 17:01

I'd recommend a stat type manager, populated from a datafile (e.g. I use XML) and Stat objects, with a type and a value stored in the character insatnce as a hashtable, with the stat type unique ID as the key.

Edit: Psudo code

Class StatType
{
    int ID;
    string Name;

    public StatType(int _id, string _name)
    {
        ID = _id;
        Name = _name;
    }
}


Class StatTypeManager
{
    private static Hashtable statTypes;

    public static void Init()
    {
        statTypes = new Hashtable();

        StatType type;

        type = new StatType(0, "Strength");
        statTypes.add(type.ID, type);

        type = new StatType(1, "Dexterity");
        statTypes.add(type.ID, type);

        //etc

        //Recommended: Load your stat types from an external resource file, e.g. xml
    }

    public static StatType getType(int _id)
    {
        return (StatType)statTypes[_id];
    }
}

class Stat
{
    StatType Type;
    int Value;

    public Stat(StatType _type, int _value)
    {
        Type = _type;
        Value = _value;
    }
}

Class Char
{
    Hashtable Stats;

    public Char(Stats _stats)
    {
        Stats = _stats;
    }

    public int GetStatValue(int _id)
    {
        return ((Stat)Stats[_id]).Value;
    }
}
share|improve this answer
    
I think StatType class in unnecessary, just use the name of the StatType as a key. As #Grimston did. The same with Stats. –  giannis christofakis Mar 26 at 12:43
    
I prefer to use a class in instances like this so you can freely modify the name (while the id remains constant). Overkill in this instance? Perhaps, but since this technique may be used for something similar elsewhere in a program I'd do it like this for consistancy. –  DFreeman Mar 26 at 12:54

Ι'll try to give you an example on how you can design your arsenal.

class Player {
    private int health = 100;
    private Weapon weapon = new Weaponless();

    public void setWeapon(Weapon weapon) {
        this.weapon = weapon;
    }

    public void attack(Player enemy) {
        enemy.setHealth(enemy.getHealth() - this.weapon.getDamage());
    }

    public int getHealth() {
        return health;
    }

    private void setHealth(int health) {
        /* Check for die */
        this.health = health;
    }
}

public interface Weapon {
    public int getDamage();
}

class Weaponless implements Weapon {
    private int damage = 0;
    @Override
    public int getDamage() {
        return this.damage;
    }
}

class Knife implements Weapon {
    private int damage = 10;
    @Override
    public int getDamage() {
        return this.damage;
    }
}

public class Game {
    public static void main(String[] args) {
        Player yannis = new Player();
        Player sven = new Player();
        yannis.setWeapon(new Knife());
        yannis.attack(sven);      
    }
}

Hope it helps!

Addendum

My design choice is to decouple entities, I think it's called strategy pattern not sure.

Using that pattern you can easily change weapons which can be applied to other aspects of your character such as armory defense. You can also enhance it using the Decorator pattern if you would like to have a combination of equipments.

share|improve this answer
1  
This answer would be more helpful when you would explain your reasoning behind your design choices. –  Philipp Mar 20 at 17:15
    
@Philipp Is this any better? –  giannis christofakis Mar 20 at 18:23

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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