Design Dilemma(C++)

Started by
4 comments, last by Telastyn 19 years, 6 months ago
I'm working on designing AI for a game and I have run into a snag. I'll try to explain it best I can. I have a Bot class that holds all the information about a bot, his goals, current path, his state machine,... this is all fine. The problem is that the game has multiple classes, so the bot could be for example a machine gunner, a medic, sniper... Here's my current inheritance tree(pretty simple) Client->Bot Normally I would just inherit the playerclasses off of the Bot class, something like this. Client->Bot->Medic Client->Bot->Sniper The problem with this, is that the bot should be able to change class during runtime, like any fps game out there, and using inheritance, this would require the Bot to be deleted and re-created as the new class. Obviously I want to avoid this. A bot shouldn't leave and rejoin the game just to change class. Anyone have any design ideas for this problem? I have one of my own but I'm not sure if it's the best approach. I sat down and listed out what each class has differently from each other and the only things different really are the transition table for the state machine, and some other properties like possibly bounding box. The state machine being the main difference in the classes, since they should all behave differently. Normally the Medic, Sniper.. subclass would set up the transition table, but since I want to avoid having to delete and re-create the object to change classes during runtime, I was thinking about implementing the Medic, Sniper as static classes that are there for no other reason than to initialize the Bot class with the proper states and variables for the playerclass. Something like this.

void Bot::ChangeClass(PlayerClass _newclass)
{
switch(_newclass)
{
case CLASS_MEDIC:
Medic::InitializeBot(this);
break;
case CLASS_SNIPER:
Sniper::InitializeBot(this);
break;
...
};
}

With this idea, the class change would be fairly easy. The static functions would be called and passed the bot pointer, and the class can call functions to clear the transition table, register new states, clear and reset the bots weapons... I feel that this is a decent alternative to deleting and re-creating the bot to change classes. Another option would be for the Bot to have a pointer to an IPlayerClass so that the playerclass would just need to be deleted and re-created on class changes instead of the whole bot, but this seemed messier to me. Any ideas are appreciated.
Advertisement
Funtion overloading for each type of bot maybe?
Instead of lots of switch statements testing "if I were a", I would try to design a single bot that would make use of whatever capabilities are available to him. For instance, a medic is just a normal guy that has a healing ability. A sniper is just a normal guy who has a sniper rife (the appropriate behaviour for a sniper rifle would be hiding). They would probably all behave the same way if given a hand gun or grenades.

To me it's the items, not the bot class, that determines how it is to behave. You may want to check out the visitor pattern for a way of making use of this.
I beleive what you are looking for is called the Strategy design pattern (google it).

Basically, you want to encapsulate all the "thinking" parts into an object seperate from the bot itself. That way, when you change duties or "strategies", you drop the object from the bot and load in a fresh one. Something to the effect of:

class Bot: public whatever {public:   void Think() { brain->Think( params ); }   void ChangeJobs( params ) {      switch(params) {         case offensive:            delete brain;            brain = new OffensiveStrategy( this );         case defensive:            delete brain;            brain = new DefensiveStrategy( this );         }      }private:   Strategy* brain;   }
As an aside, I believe your inheritence tree nomenclature is back to front from the standard : client -> bot means that client is inherited from bot; I think you want client <- bot.
Assuming -all- you want to do is prevent deletion when changing classes, why not create a bot constructor which takes another bot as its parameter? You can then keep the state without totally recreating a new bot. You also might need to overload your destructor if yours is "noisy" [ie posting "so-and-so has left the game", which is un-needed when you're deleting an old bot since you copied it to the new class] And the destructor will likely need to be virtual.

Then you get something like this:

Medic::Medic      (bot *target):bot(target){// Medic specific stuffdelete target(quiet);}



This topic is closed to new replies.

Advertisement