views:

389

answers:

5

I'm porting a 2D platformer and I need a good way of getting some extensibility out of my level tiles. I'm not sure if Decorator is correct here, but nothing else comes to mind. Maybe I need something unique.

Anyway, say I have a basic Tile that has things like it's image, and whether the player can pass through it (background or foreground). Now I want to add properties to them like making some tiles act as ladders, or making some hurt or kill the player on contact. Maybe some can disappear. Some properties can be combined.

This sounds like decorator, but I really don't like how that requires my base class to implement dummy versions of everything, like isLadder(), isLethal(), etc. Is there a better way? I'm not going to be the guy who changes my design just so it looks like something out of the GoF book.

Sorry if this has been asked a million times before, I didn't quite find it in the related questions.

+4  A: 

How you design your class methods can make a huge difference in how difficult Decorator is to implement - for instance, instead of isLadder() and isLethal() and so on, why not have methods based on the ways in which the player could interact with a tile (enter(from_dir), exit(to_dir)), etc? A lethal tile could override the enter() method to signal that the player should be killed; a ladder tile could override either enter() or exit() depending on the desired functionality.

Amber
Very interesting - the way I'm going to use it is "if (playerPressedClimbButton " So would that just become "if (playerPressedClimb) { tile->pressClimb() } and the overridden function is pressClimb, and for ladders it returns climbing behavior?
Tesserex
Pretty much - though you could generalize it more, and that button could simply become a "move up" button - perhaps other tiles might have a different action if you tried to "move up" while on them. It's just a flexible way of handling things.
Amber
+1  A: 

Well, if it's about a bunch of is*() functions, you may go for something like isIt(what) function, returning oh no! by default implementation, which will be used as a fallback in derived classes.

Michael Krelin - hacker
+2  A: 

Dav is right. It could be something like this:

class Tile
{
    public bool allowsPassThrough()
    {}

    // couldn't find a better name for this method
    public void passThrough(Player player)
    {}
}

class LethalTile extends Tile
{
    public void passThrough(Player player)
    {
        player.kill();
    }
}
Ionuț G. Stan
doesnät look like `c++` code at all ;-)
Michael Krelin - hacker
@hacker, indeed :) I don't know C++ so I presented some sort of pseudocode.
Ionuț G. Stan
+1  A: 

I would have introduced something like a TileTraits class. Each tile can return its traits via the, well..., "getTraits()" method. TileTraits can be extended to support as many tile features as you want. Something like a:

class TileTraits
{
public: 
   enum TileTrait{ Walkable  = 1, 
                   Climbable = 1 << 1, 
                   Lethal    = 1 << 2 };
private:
   TileTrait m_TraitSet;
};

class BaseTile
{
public:
   virtual TileTraits getTraits() const;
};

class LadderTile : public BaseTile
{
public:
   TileTraits getTraits() const { 
      return TileTraits( TileTraits::Walkable | TileTraits::Climbable); 
    }
};
SadSido
+1  A: 

Maybe you should look at component based objects. Here is an example : http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/

Adis H