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 :)