I ran into a problem in a game that I am doing in C #. This is a simple tile based game, and the problem occurred to me, I am trying to do:
Say we have the main types of tiles, circles and diamonds that are subclasses of Tile. Instead of just matching circles, I tried to extract the “match” behavior in the abstract Tile method: canMatchWith (Tile t). Tiles also have two methods for adding / removing tiles that they can compare with.
So let's say that we have a round tile in the middle of our game, and we have a powerup that says: "The circles on the circle can coincide with the square tiles in this turn." I would go through all the Circle tiles and say circleTile.addCanMatchWith (typeof (Square)). Inside, we have a canMatchWith list.
Then later I want to say: “Circles can no longer coincide with squares” and just say circleTile.removeCanMatchWith (typeOf (Square)).
This is my current solution, and it works fine without any performance flaws that I noticed (this is a tile based game, so these types are evaluated only once per “move”, not frame by frame). However, a voice in my head tells me that this is a bad way to carry out this behavior. Therefore, I have several alternatives:
- Enumerates ... Each Tile can consist of a variable of type Tiletype. This will be initialized in the constructor and set to Type.SQUARE for squares, etc. Then each Tile will have a canMatchWith list, and the functionality is the same as my original implementation. Except in this case, it is a little more complicated. Let's say I have some subclasses of circle, oval and elipse. I want the ovals to fit ONLY squares, but elipses can fit all circles, not squares.
The problem is redundancy, my enum now has OVAL and ELIPSE, and the Elipse class will have (CIRCLE, OVAL, ELIPSE TileTypes) as types that it can compare with. This is completely redundant, I just want to say “Circle”, which I could with the help of types. I believe that Tiles can have TileType baseType and TileType actualType.
- Some form of behavior. Forget the Tile subclasses, just specify the Tiles methods and the instance variable for the List. Then at runtime we can just say someTile.addCanMatch (new CircleMatchBehavior ()). This seems silly, because I will have a bunch of classes just saying that you can fit in a certain form.
In general, what I'm trying to accomplish is that several types of objects can interact with any number of different types. The question is what should I use for Type. Can i use gettype here? Lists? Or is there a better strategy that someone would recommend? I try to be as general as possible, these tiles should not have any hard-coded dependencies on other fragments and should be able to change who they can interact with on the fly. Let's say I'm doing a new subclass of the subclass, the Pentagon ... well, Pentagons can match squares, circles, and Pentagons. Easy with my implementation, but something tells me it's dirty OOP practice.
It seems to me that I should use types / enumerations because I am not trying to say thisTile.addCanMatch (Tile someOtherObject). This is too specific, I want thisTile to be able to map to all fragments that are instances of a particular class.