views:

122

answers:

4

Finding a suitable question title and -tags for this question struck me rather hard.

Basically I've built a game wherein several units/mobs will be present. Now I'm interested in building a system, so each unit can have effects/buffs/debuffs applied to them that will modify the properties of the unit. Examples of such effects could be a frost effect that'd slow the movement speed of the unit, a health boost and so forth. The plan was to have these effects implemented via scripting so it would be possible to create custom user effects.

I'm looking for advice on how I could implement this. For now I've thought about creating a effect class. Then each applied effect would be an instance of the class, and would have a reference to the unit it was applied to. The effect would have at least two methods, an apply and unapply method for respectively applying- and unapplying.

The problem with this, is that it doesn't allow for different ways of cumulative percentages. Like, should two times 10% increase on a value 100 equal 120 or 121.

Not that it really matters, but it's being coded in C#

+3  A: 

Have you considered the Decorator pattern? An example in action can be found in this tutorial.

I've written a small example to illustrate your specific situation. The class UnitWithPowerUp accepts a Unit object (which may or may not already be decorated). When you call Health() on this class, it gets the health of the Unit, and adds 10% to the default 100. If you've decorated it twice, it will return 121. Calling GetDescription() on a single decorated Unit returns "Unit + Power Up". Likewise, a doubly-decorated Unit returns "Unit + Power Up + Power Up".

    public abstract class Unit
    {

      public virtual string GetDescription()
      {
         return "Unit";
      }

      public virtual double Cost()
      {
         return 100;
      }
   }

   public abstract class EffectDecorator : Unit
   {
      public EffectDecorator()
      {
      }
   }



   public class UnitWithPowerUp : EffectDecorator
   {
      Unit unit;

      public UnitWithPowerUp(Unit unit)
      {
         this.unit = unit;
      }

      public override string GetDescription()
      {
         return unit.GetDescription() + " + Power Up";
      }

      public override double Health()
      {
         return unit.Health() * 1.10;
      }
   }

I haven't tested the code or anything, it's just to show the concept. I suggest you get a copy of Head First Design Patterns, if you think this is useful.

Charlie Salts
I'm not sure how that'd help me in any way.
Qua
Dynamically adding new or additional behaviour or attributes to a class is the definition of the Decorator pattern, and is analogous to adding your 'effects' to your 'units'.
Charlie Salts
It's not a good match for changing these properties at run-time though, which is what he'll need.
Kylotan
+4  A: 

You're on the right track with the Effect class. But keep a list of effects on each unit rather than having effects refer to units. When you want to get an attribute value, query the one you need, rather than using apply() and unapply() functions to modify the base values (which can result in the underlying value drifting due to floating point errors and so on).

Your Effect class could have a method Modify() which takes the input value as a floating point value, and returns the modified value. Query a property ends up looking like this pseudocode:

def get_movement_speed():
    value = base_movement_speed() # this is intrinsic to the unit
    for effect in movement_speed_effects_list:
        value = effect.modify(value)
    return value

In the unlikely event that you have so many Effects that this becomes inefficient, cache the values and recalculate them each time you add or remove an effect.

Kylotan
This does make more sense than my answer. +1
Charlie Salts
A: 

If you are planning on scripting to do some of the effects (which can be nice for games that have a whole bunch of effects), you can go ahead and take advantage of C#'s ability to compile during runtime Reference. Essentially, you can code everything you want in C#, save the byte code somewhere (potentially as part of a level file, or expansion pack or whatever), then have the effect execute the appropriate C# code every time it goes off.

Eli
A: 

When doing games where object states needs to change dynamically, take a look at component system/entity system design.

By far the best article on this topic I've seen is

http://www.devmaster.net/articles/oo-game-design/

Mikeon