#168820 - Drovor - Wed May 27, 2009 9:40 pm
I am working on a simulation project on the DS and essentially have a 2D array of tiles, each tile is a struct of values. The generic tile has a TYPE field and can be various TYPEs (like barrier, empty, food, egg, ... all of which are declared in an enum). Actions can be performed on the struct which modify its properties, like if the TYPE == food, the food can be picked up and the TYPE is changed to empty. (This design may be questionable, but it is working for me surprisingly well and the question is about use of macro's not design!)
These are the relevant values of my tile:
At first I was using simple comparison macro's to test the TYPEs:
This was very convenient because I was able to expand it without touching any other part of the program when I wanted to make more types of food:
Well this practice seems to be a slippery slope, because I'm adding more and more of these. All are simply manipulating the struct, but they are getting more complicated than simple comparisons.
For example, I needed a reference to who is standing on the tile in the tile (there are thousands of characters, so a lookup from my list of characters isn't feasable if I need to know something like who is standing next to someone else). Because of that I needed to keep the struct updated when a character moves from one tile to the next and I get something like this:
Again I can easily update the macro if I wanted to make it so 3 characters can occupy one tile, but then it gets even bigger.
Finally the question:
For those of you who may be more familiar with with using macros, I am wondering what your opinions on them are? I suppose at some point you should just make functions to do this sort of manipulation and I probably crossed that line long ago, where do you consider that line?
These are the relevant values of my tile:
Code: |
struct Tile
{ short TYPE; Creature* occupant_one; Creature* occupant_two; }; |
At first I was using simple comparison macro's to test the TYPEs:
Code: |
#define FOOD(X) FOODi(X->TYPE) // Tile* X
#define FOODi(X) ((X == FOOD)) |
This was very convenient because I was able to expand it without touching any other part of the program when I wanted to make more types of food:
Code: |
#define FOOD(X) FOODi(X->TYPE)
#define FOODi(X) ((X == FOOD) || (X == FOOD2)) |
Well this practice seems to be a slippery slope, because I'm adding more and more of these. All are simply manipulating the struct, but they are getting more complicated than simple comparisons.
For example, I needed a reference to who is standing on the tile in the tile (there are thousands of characters, so a lookup from my list of characters isn't feasable if I need to know something like who is standing next to someone else). Because of that I needed to keep the struct updated when a character moves from one tile to the next and I get something like this:
Code: |
#define AVAILABLE_SPOT(X) ((X->occupant_one == '\0') || (X->occupant_two == '\0'))
#define SET_SPOT(X, Y) {if(AVAILABLE_SPOT_ONE(X)) SET_SPOT_ONE(X, Y); else if (AVAILABLE_SPOT_TWO(X)) SET_SPOT_TWO(X, Y);} #define REMOVE_SPOT(X, Y) {if(SPOT_ONE_IS(X, Y)) SET_SPOT_ONE(X, '\0'); else if (SPOT_TWO_IS(X, Y)) SET_SPOT_TWO(X, '\0');} #define AVAILABLE_SPOT_ONE(X) (X->occupant_one == '\0') #define AVAILABLE_SPOT_TWO(X) (X->occupant_two == '\0') #define SET_SPOT_ONE(X, Y) (X->occupant_one = Y) #define SET_SPOT_TWO(X, Y) (X->occupant_two = Y) #define SPOT_ONE_IS(X, Y) (X->occupant_one == Y) #define SPOT_TWO_IS(X, Y) (X->occupant_two == Y) |
Again I can easily update the macro if I wanted to make it so 3 characters can occupy one tile, but then it gets even bigger.
Finally the question:
For those of you who may be more familiar with with using macros, I am wondering what your opinions on them are? I suppose at some point you should just make functions to do this sort of manipulation and I probably crossed that line long ago, where do you consider that line?