0

I am making a game in which the player character can gain traits that change how their character behaves in my world model or add functionality to it. For example, the character might gain the "feather" trait that changes how fall damage is calculated or the "strong" trait that means the player can now pick up items that were previously just part of the scenery.

I have been hard coding traits in their relevant classes and switching a boolean to change behavior when they come into play, but it is getting rather unmanageable as my trait list grows. There must be a more scalable and decoupled way of doing this.

(The perfect scenario I want is a way that I can just program the class variations and get them switched at runtime in some way while keeping the context and references of the previous object, but any other way to suitably fulfill the requirements bellow is a good answer.)

How would you implement such a feature where methods change and new functionality is gained and removed at runtime?(Please provide an hypothetical example on the given scenario) If you are not inclined to do my work for me, which programming patterns would you use to achieve this kind of behavior?

P.S.:Please feel free to suggest a better title. I suck at those. I will edit this out once a better one has been found.

Althis
  • 181
  • 6

1 Answers1

1

You could try to implement the Decorator Pattern, which is usually used to add and remove behaviors to an object dynamically, without changing the reference of the original object. The Wikipedia page gives you good explanations and examples. Anyway I'll try to show you a simple Java (hope you'll understand it, you didn't specified the language) example maybe closer to your case. Suppose you have a character class like this:

public class Character {

    public int calculateFallDamage() {
         return 10;
    }

    public void pickUpItem() {
    // initially this method could be empty
    // nothing happens when you try to pick up items
    }
}

Now we create a subclass of Character that adds the "feather" trait. This subclass must contain a field of the class that it extends in order to change its behaviors:

public class FeatherDecorator extends Character {

    private Character decoratedCharacter;

    public FeatherDecorator(Character character) {
        this.decoratedCharacter = character;
    }

    @Override
    public int calculateFallDamage() {
        int fallDamage = decoratedCharacter.calculateFallDamage();  // call the function of the decorated class
        return fallDamage - 5;  // change the result 
    }
}

If you want to add the "feather" trait you have create a new object like this:

Character character = new Character();
int fallDamage = character.calculateFallDamage(); // returns 10
character = new FeatherDecorator(character);
int newFallDamage = character.calculateFallDamage(); // returns 5

Doing in this way you can keep the original reference to the Object but at the same time you can change his behavior. If you are interested to remove a decoration you could add a method like this:

public class Character() {
    ...
    public Character getDecoratedComponent() {
    // exception becaus it's not decorated
    }
    ...
}

public class FeatherDecorator extends Character {

    private Character decoratedCharacter;
    ...
    @Override
    public Character getDecoratedComponent() {
        return decoratedCharacter;
    }
    ...
}

Now it's very easy to obtain the original object without decorations:

Character character = new FeatherDecorator(new Character());
character = character.getDecoratedComponent(); // returns the object without the feater decorator

I hope I have helped you, the Decorator Pattern is a very powerful pattern which gives some flexibility to the objects' behavior. Please let me know if you need more explanations.

sinecode
  • 743
  • 1
  • 7
  • 17
  • This is exactly what I want with two caveats, maybe you can also help me with those. My first problem with this is that as far as I understand I can add an arbitrary number of traits. For example, I can add the feather trait and then add the strong trait, and it would work. But if I want to remove a trait I can only remove the last added. Like in a stack. The second problem I see if that this assumes a single reference to the character object exists. Is there a way to update all references at once? – Althis Mar 19 '17 at 17:25
  • If you want to remove a specific decoration you can look at [this question](http://stackoverflow.com/questions/12239784/how-to-remove-decorated-object-from-decorator-pattern-in-java#12240581). I'm sorry but I didn't understand that you could have many different references to the same object, this fact maybe could cause problems with the decorator pattern. In this case, as _jaco0646_ said in the comment, maybe the [State Pattern](https://sourcemaking.com/design_patterns/state) could be better. – sinecode Mar 19 '17 at 20:26