I took this idea and modified it a wee bit. My idea was to have behavious as things attributed to game objects (but they don't have to be) which act on attributes and modify them, importand variables such as controllers are kept as part of the object for memory management purposes plus it allows things to be accessed directly if needs be. This is what I did for player movement (I'm not a great programmer, sorry if the code is a bit shoddy):
//####################
class AttributeType{
public:
AttributeType(){}
};
template <class T>
class Attribute : public AttributeType{
private:
T data;
public:
Attribute(T _data) {
data = _data;
}
T GetValue() {
return data;
}
void SetValue(T value) {
data = value;
}
};
class UTNBehaviour {
public:
map<string,AttributeType*>* attributes;
void SetAttributeList(map<string,AttributeType*> * att) {
attributes = att;
}
template <typename T>
T GetAttributeValue(map<string,AttributeType*>* att, string name) {
return reinterpret_cast<Attribute<T>*>((*att)[name])->GetValue();
}
template <typename T>
void SetAttributeValue(map<string,AttributeType*>* att, string name, T value) {
return reinterpret_cast<Attribute<T>*>((*att)[name])->SetValue(value);
}
virtual void operator()()=0;
virtual void operator()(map<string,AttributeType*>* att)=0;
};
float mx = 0;
float my = 0;
class PlayerMovement : public UTNBehaviour{
public:
virtual void operator()() {
(*this)(attributes);
}
virtual void operator()(map<string,AttributeType*>* att) {
TVec3 * rotation = GetAttributeValue<TVec3*>(att,"orientation");
rotation->X = rotation->X + my*0.1;
rotation->Y = rotation->Y - mx*0.1;
UpdateController(*GetAttributeValue<TEntity*>(att,"controller"),rotation->Y,(KeyDown(KEY_W)-KeyDown(KEY_S))*5,(KeyDown(KEY_D)-KeyDown(KEY_A))*5,0,10);
}
};
//####################
class UTNGameObject{
private:
static list<UTNGameObject *> liveObjects;
public:
UTNGameObject();
map<string,AttributeType*> attributes;
map<string,UTNBehaviour*> behaviours;
void AddAttribute(string name, AttributeType* att) {
attributes[name] = att;
}
void AddBehaviour(string name, UTNBehaviour* bhv) {
behaviours[name] = bhv;
}
template <typename T>
T GetAttributeValue(string name) {
return reinterpret_cast<Attribute<T>*>(attributes[name])->GetValue();
}
template <typename T>
void SetAttributeValue(string name, T value) {
reinterpret_cast<Attribute<T>*>(attributes[name])->SetValue(value);
}
map<string,AttributeType*> * GetAttributeList() {
return &attributes;
}
virtual ~UTNGameObject();
virtual void Update();
};
//##########
enum PLAYERTYPE {LOCAL_PLAYER,FOREIGN_PLAYER,NPC};
class UTNCharacter : public UTNGameObject{
public:
void Update();
TController controller;
TVec3 orientation;
PLAYERTYPE playertype;
};
//##########
list<UTNGameObject *> UTNGameObject::liveObjects;
UTNGameObject::UTNGameObject(){
liveObjects.push_back(this);
}
UTNGameObject::~UTNGameObject(){
}
void UTNGameObject::Update(){
}
//##########
void UTNCharacter::Update() {
}
//##########
And then the creation of a player object:
void CreateGame() {
SetWorld(world.GetWorld(MAINWORLD));
Collisions(1,2,true);
SetWorldGravity(Vec3(0,-20,0));
TEntity scene = LoadScene("abstract::scene.sbx");
EntityType(scene,1);
//world.AddObject(&scene);
UTNCharacter *newplayer = new UTNCharacter;
newplayer->playertype=LOCAL_PLAYER;
newplayer->controller = CreateController(1.8f,0.4f,0.3f,40.0f);
newplayer->AddAttribute("controller",new Attribute<TEntity*>(&newplayer->controller));
SetBodyMass(*newplayer->GetAttributeValue<TEntity*>("controller"),60.0);
EntityType(*newplayer->GetAttributeValue<TEntity*>("controller"),2);
PositionEntity(*newplayer->GetAttributeValue<TEntity*>("controller"),Vec3(0.0,5.0,0.0));
newplayer->orientation=Vec3(0);
newplayer->AddAttribute("orientation",new Attribute<TVec3*>(&newplayer->orientation));
UTNBehaviour * bhv = new PlayerMovement;
bhv->SetAttributeList(newplayer->GetAttributeList());
newplayer->AddBehaviour("playercontrols",bhv);
world.player = &newplayer->controller;
world.playerrotation = &newplayer->orientation;
world.AddObject(newplayer);
appstate = GAME_RUNNING;
}
And the world update loop (UTNWorld is my framework substitute which can be rendered by a renderer object)
void UTNWorld::Update() {
SetWorld(GetWorld(MAINWORLD));
for(list<UTNGameObject *>::iterator ita=worldObjects.begin(); ita!=worldObjects.end(); ) {
UTNGameObject *ptr=(*ita);
++ita;
ptr->Update(); //Fairly redundant if you use behaviours
for(map<string,UTNBehaviour*>::iterator itb=ptr->behaviours.begin(); itb!=ptr->behaviours.end(); ) {
UTNBehaviour * ptrb = (*itb).second;
//(*ptrb)(&(ptr->attributes));
(*ptrb)();
++itb;
}
}
PositionEntity(cam,EntityPosition(*player)+Vec3(0,1.8,0));
RotateEntity(cam,*playerrotation);
SetWorld(GetWorld(MAINWORLD));
UpdateWorld(AppSpeed());
}
Sorry if it's a bit confusing and a bit long, it's from a WIP and I din't want to spend too much time editing it.
So is this a good way of working (I can see myself easily being able to build up an array of usefull behaviours and objects this way)? As I said before, I'm a pretty poor programer in that I don't have very much real world experience so this whole thing might be disasterous.