Well rather than having equipment/environment change the interface of the character, I would try to have the character interface generic, and have it interact with the environment underneath. For example:
1 2 3 4 5 6 7 8 9 10 11 12
|
landFighter.runto(x,y,z);
swampFighter.runto(x,y,z); // same interface
LandFighter::runto( /*xyz*/ )
{
if(mud_on_path) CantMove();
}
SwampFighter::runto( /*xyz*/ )
{
if(mud_on_path) CheckThicknessAndStuff();
}
| |
Changing the way your program interfaces with the character for each set of circumstances is troublesome because
1) it requires you to hardcode each circumstance into the character
2) it requires if/else chains to determine which interface to use. if(fighter.equipment == thisitem) DoThis(); else if(blah) DoThat(); Blech.
My suggestion would be to make each different kind of circumstance a class (each circumstance class derived from a common abstract base class), and give the characters pointers to those circumstances. It's kind of hard to explain -- I hope I'm making sense -- it all makes sense in my head I swear! XD
Anyway the trick is to get the interface to be a basic as possible, and put the specifics in derived classes. That way as the specifics change, you can just change (or add) one circumstance's handler, rather than having to go into each and every character's class and add a new else if to the chain.
As for inheritance -- It basically comes down to a "is a" relationship. A
fighter
"is a"
character
... a
landfighter
"is a"
fighter
, etc. However this "is a" relationship has a condition that for a fighter to
really be a character, it needs to do everything that a character can do. IE: the outward interface has to be the same. If you really can't make it the same, you either should redesign the interface, or reconsider whether or not it really has a "is a" relationship. A swampfighter might not be a fighter, for example, if he can't do things that fighters can normally do -- but he might be a character! It's more about how the class behaves.
As for program flow, it's up in the air how you want to approach it because it can vary depending on all the details. But my first instinct would be to have.... how to word this.... like.... if logic A is dependent on logic B, then have logic A's code call logic B's. Don't do if(logicB) DoLogicA1(); else DoLogicA2();
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
// bad
void MoveCharacters()
{
if(acharacter->InASwamp())
acharacter->MoveThroughSwamp(a,b,swamp->GetThickness());
else
acharacter->MoveOnLand(a,b);
}
// better
void MoveCharacters()
{
acharacter->Move(a,b);
}
void Character::Move(int a,int b)
{
if(InASwamp())
MoveThroughSwamp(a,b,swamp->GetThickness());
else
MoveOnLand(a,b);
}
| |
This way the dependency stays where it matters, and the overall game flow can be clueless about it. If each character checks their own depencies, they can respond to them in their own way. If a swampfighter can move through the swap and on land, for example, it might not even have to do that InASwamp() check.
Anyway I don't know if I'm making much sense. Design is tricky though. I've found that's it's actually the hardest part of programming -- but once you have a good design, the programming part is
soooooo easy.