
Question? is that possible to create an architecture, interface based, which allows you programming a game flow independent of his content?
answer: yes!
Note that Minigame_Pinball and Minigame_Pinball_Score are just interface implementations that don't know nothing about the game flow, they are using IGameObj to connect to the flow and returning a condition from FLOW_CONDITIONS, they register themselves and they are allocated only when I need them :) (it's easy to pre-allocate if you want to)
Now, you can copy the code, create your own game class, derive that from IGameCreateObj and implementing your own IGameObj and have fun!!!!
//class MyOwn : public IGameCreateObj<MyOwn> #include "stdafx.h" #include <iostream> #include <vector> #include <typeinfo> #include <time.h> using namespace std; enum FLOW_CONDITIONS { LOOP = 0, NEXT_FLOW, BACK, NEXT }; class IGameObj { public: virtual void Init() = 0; virtual FLOW_CONDITIONS Loop() = 0; virtual void Uninit() = 0; virtual IGameObj *CreateANew() = 0; virtual ~IGameObj(){}; }; template<class X> class IGameCreateObj : public IGameObj { public: //make singleton static X* GetInstance() { static X x; return &x; } //able to get a copy IGameObj *CreateANew() { return new X(); }; virtual ~IGameCreateObj(){}; }; class Minigame_Pinball : public IGameCreateObj<Minigame_Pinball> { private: double timeOut; public: void Init() { timeOut = clock(); }; FLOW_CONDITIONS Loop() { timeOut += clock()-timeOut; if (timeOut > 3000) return NEXT; cout << "Minigame_Pinball " << timeOut << endl; return LOOP; }; void Uninit() {}; }; class Minigame_Pinball_Score : public IGameCreateObj<Minigame_Pinball_Score> { public: void Init() {}; FLOW_CONDITIONS Loop() { return LOOP;}; void Uninit() {}; }; struct FlowCondition { IGameObj *obj1; FLOW_CONDITIONS fc; IGameObj *obj2; }; class IGameFlow { public: virtual bool Loop() = 0; }; class GameFlow : public IGameFlow { private: vector<const FlowCondition* const> _list; IGameObj *_currentObj; IGameObj *AllocType( IGameObj *obj_info ) { IGameObj *mg = NULL; mg = obj_info->CreateANew(); return mg; } FlowCondition *SearchCondition( FLOW_CONDITIONS fc ) { vector<const FlowCondition* const>::iterator it; for( it = _list.begin(); it != _list.end(); ++it ) if ((*it)->fc == fc) return (FlowCondition *)*it; return NULL; }; public: GameFlow() : _currentObj(NULL) {}; void RegisterCondition(IGameObj *obj1, const FLOW_CONDITIONS fc, IGameObj *obj2 ) { FlowCondition *p = new FlowCondition(); p->fc = fc; p->obj1 = obj1; p->obj2 = obj2; _list.push_back( p ); if (_currentObj == NULL) { _currentObj = AllocType(obj1); _currentObj->Init(); } return; } virtual ~GameFlow() { vector<const FlowCondition* const>::iterator it; for( it = _list.begin(); it != _list.end(); ++it ) delete *it; delete _currentObj; } bool Loop() { FLOW_CONDITIONS fc = _currentObj->Loop(); if (fc==NEXT_FLOW) return false; FlowCondition *tmp = SearchCondition( fc ); if (tmp != NULL) { _currentObj->Uninit(); delete _currentObj; _currentObj = AllocType(tmp->obj2); _currentObj->Init(); } return true; } }; class GameFlowManager { private: vector<const IGameFlow* const> _list; IGameFlow* _gFlowCurrent; public: GameFlowManager() : _gFlowCurrent(NULL) {}; void RegisterFlow(IGameFlow *gflow) { if (_gFlowCurrent==NULL) _gFlowCurrent = gflow; _list.push_back( gflow ); return; } void Loop() { while(_gFlowCurrent->Loop()) { } } }; int _tmain(int argc, _TCHAR* argv[]) { GameFlow minigameFlow; minigameFlow.RegisterCondition( Minigame_Pinball::GetInstance(), NEXT, Minigame_Pinball_Score::GetInstance()); minigameFlow.RegisterCondition( Minigame_Pinball_Score::GetInstance(), BACK, Minigame_Pinball::GetInstance()); minigameFlow.RegisterCondition( Minigame_Pinball_Score::GetInstance(), NEXT_FLOW, NULL ); GameFlowManager game; game.RegisterFlow( (IGameFlow*)&minigameFlow ); game.Loop(); return 0; }
Nowadays, I'm working as director of pre-production so "officially" I do not write code, anyway, I hope it can help someone :)