Rick Posted September 24, 2010 Share Posted September 24, 2010 Just something I'm working on to try and make UI driven game logic. Very similar to the component stuff I was doing. Almost for my own documentation #include <map> #include <string> using namespace std; 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 GameObject { private: map<string, AttributeType*> _attributes; public: void AddAttribute(string name, AttributeType* att) { _attributes[name] = att; } 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); } }; // the base class for all behaviors class Behavior { private: map<string, AttributeType*> _parameters; public: void ClearParameters() { _parameters.clear(); } template<typename T> void PushParameter(string name, T data) { _parameters[name] = new Attribute<T>(data); } template<typename T> T GetParameter(string name) { return reinterpret_cast<Attribute<T>*>(_parameters[name])->GetValue(); } virtual void operator()()=0; }; // this specific behavior reduces health of a game object class DoDamage : public Behavior { public: virtual void operator()() { // get the parameters (the names would be linked via xml/editor) GameObject* obj = GetParameter<GameObject*>("game.object"); int dmgAmount = GetParameter<int>("damage.amount"); // do the logic int health = obj->GetAttributeValue<int>("health"); health -= dmgAmount; obj->SetAttributeValue<int>("health", health); } }; // input parameter: modelFilename <string> the name of the model to load // output parameter: model <TEntity> stores the actual model class LoadModel : public Behavior { public: virtual void operator()() { } }; class TEntity { }; int main() { // everything is a GameObject object GameObject human; // all logic is a Behavior. we would create 1 type of each behavior and that would be used // everywhere it's needed Behavior* damage = new DoDamage(); // we can create/set custom data for any game object // this can be explained in xml human.AddAttribute("health", new Attribute<int>(100)); human.AddAttribute("name", new Attribute<string>("Rick")); human.AddAttribute("attack.power", new Attribute<float>(50.5f)); human.AddAttribute("model", new Attribute<string>("abstract::model.gmf")); // we can get these attributes float ap = human.GetAttributeValue<float>("attack.power"); int health = human.GetAttributeValue<int>("health"); // add parameters and call the DoDamage behavior damage->ClearParameters(); damage->PushParameter<GameObject*>("game.object", &human); damage->PushParameter<int>("damage.amount", 5); (*damage)(); health = human.GetAttributeValue<int>("health"); return 0; } Quote Link to comment Share on other sites More sharing options...
ZioRed Posted September 25, 2010 Share Posted September 25, 2010 I would allow to pass a Parameter[] to the constructor of each Behavior so you don't need to ClearParameters() And maybe a Call method instead of constructor is preferable as class design since may happen you need to create a Behavior from scratch (or it may be called in unwanted times causing unwanted behaviours, think to Reflection in example). My 2 cents Quote ?? FRANCESCO CROCETTI ?? http://skaredcreations.com Link to comment Share on other sites More sharing options...
Rick Posted September 25, 2010 Author Share Posted September 25, 2010 The way this is setup, each behavior is only created once for the entire game and all game objects that are connected to that behavior use just the one instance. So when it's a certain game objects turn to use a certain behavior, the previous parameters are cleared and that game objects parameters are filled in. That would be why I don't use the constructor. But I like the idea of using an array of parameters. I'll just make that passed to the function call operator. In this design you can think of behaviors are just a normal function. Like if this was normal C you'd just have normal functions that work on all the different game objects in your game. The reason I didn't make it a normal function is with polymorphism you can store all the different behaviors in a container and assign them a name. Create 1 of each at the beginning of the game dynamically from dll's (in C# anyway), so people can add their own behaviors dynamically. Then when the actual flow of game logic is read from xml files you can refer to behaviors via their string name. I've been playing around with Kismat a little and it seems the theme is that Events fire and run Actions that work on Game Objects. One of the cool things I like about Kismat is that these events have parameters that get filled in by the even caller and one can save off those parameters to variables to be used later in the flowgraph. That's pretty handy. Quote Link to comment Share on other sites More sharing options...
Canardia Posted September 25, 2010 Share Posted September 25, 2010 I would rather send messages to each game object. Quote ■ Ryzen 9 ■ RX 6800M ■ 16GB ■ XF8 ■ Windows 11 ■ ■ Ultra ■ LE 2.5 ■ 3DWS 5.6 ■ Reaper ■ C/C++ ■ C# ■ Fortran 2008 ■ Story ■ ■ Homepage: https://canardia.com ■ Link to comment Share on other sites More sharing options...
Ending Credits Posted October 30, 2010 Share Posted October 30, 2010 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. Quote AMD Phenom 9850 (X4 2.5GHz) | 1066MHz CL5 GEIL Black Dragon (800MHz) | Powercolor ATI 4870 1GB | DFI 790FXB-M2RSH | 24" 1920x1200 | Windows Vista 64-bit Ultimate Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.