#include <iostream>
#include <irrlicht/irrlicht.h>
#include <stdio.h>
//! ==========================================================
// petite definition recursive d'une list en template'
template <int HEAD, class TAIL>
struct IntList
{
enum { head = HEAD };
typedef TAIL tail;
};
struct IntListEnd {};
// iteration sur la list "template" pour trouve un etat
template <class STATELIST>
struct SwitchTemplate {
template <class CONTEXT>
static typename CONTEXT::ReturnType work(int state, CONTEXT & context)
{
return ((STATELIST::head == state) ?
context.template operator()<STATELIST::head>() :
SwitchTemplate<typename STATELIST::tail>::work(state, context));
}
};
// fin de l'iteration recursive -> retourne l'état courant
template <>
struct SwitchTemplate<IntListEnd>
{
template <class CONTEXT>
static typename CONTEXT::ReturnType work(int state, CONTEXT & context)
{
return typename CONTEXT::ReturnType();
}
};
//! ==========================================================
template <class CONTEXT, class STATELIST = typename CONTEXT::StateList>
struct StateMachine
{
CONTEXT & context;
int state;
template <class RET, class DATA> struct CallEvent {
typedef RET ReturnType;
CONTEXT & context;
DATA & data;
template <int STATE> RET operator()(){
return context.template event<STATE>(data);
}
};
template <class RET, class DATA> struct CallEventConst {
typedef RET ReturnType;
CONTEXT & context;
const DATA & data;
template <int STATE> RET operator()(){
return context.template event<STATE>(data);
}
};
template <class RET> struct CallEventNoData {
typedef RET ReturnType;
CONTEXT & context;
template <int STATE> RET operator()(){
return context.template event<STATE>();
}
};
struct CallEnter {
typedef void ReturnType;
CONTEXT & context;
template <int STATE> ReturnType operator()(){
return context.template enter<STATE>();
}
};
StateMachine(CONTEXT & c) : context(c), state(STATELIST::head) {
CallEnter cee = {context};
SwitchTemplate<STATELIST>::work(state, cee);
}
void changeState(const int newstate){
state = newstate;
CallEnter cee = {context};
SwitchTemplate<STATELIST>::work(state, cee);
}
void work(){
CallEventNoData<int> ce = {context};
int newstate = SwitchTemplate<STATELIST>::work(state, ce);
if(newstate != state)
changeState(newstate);
}
template <class EVENT>
void work(const EVENT & ev){
CallEventConst<int, EVENT> ce = {context, ev};
int newstate = SwitchTemplate<STATELIST>::work(state, ce);
changeState(newstate);
}
template <class EVENT>
void work(EVENT & ev){
CallEvent<int, EVENT> ce = {context, ev};
int newstate = SwitchTemplate<STATELIST>::work(state, ce);
changeState(newstate);
}
};
#define LIST1(a) IntList<a,IntListEnd>
#define LIST2(a,b) IntList<a,LIST1(b) >
#define LIST3(a,b,c) IntList<a,LIST2(b,c) >
#define LIST4(a,b,c,d) IntList<a,LIST3(b,c,d) >
#define LIST5(a,b,c,d,e) IntList<a,LIST4(b,c,d,e) >
#define LIST6(a,b,c,d,e,f) IntList<a,LIST5(b,c,d,e,f) >
#define LIST7(a,b,c,d,e,f,g) IntList<a,LIST6(b,c,d,e,f,g) >
#define LIST8(a,b,c,d,e,f,g,h) IntList<a,LIST7(b,c,d,e,f,g,h) >
//! ==========================================================
using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
irr::scene::IAnimatedMesh* ePlayer;
IAnimatedMeshSceneNode* NodePlayer;
//! ==========================================================
enum States
{
ST_ANIM_0,
ST_ANIM_1,
ST_ANIM_2,
ST_ANIM_3
};
struct Event { int state; };
struct AnimationSwitch
{
typedef LIST4(ST_ANIM_0, ST_ANIM_1, ST_ANIM_2, ST_ANIM_3) StateList;
/// default template version for the event function
template <int> int event() { cout << "undefined event handler" << endl; return 0; }
template <int> int event(Event &ev) { return ev.state; }
template <int> void enter() { cout << "undefined enter" << endl; }
template <int i> void exit() { cout << "undefined leave " << i << endl; }
};
template <> int AnimationSwitch::event<ST_ANIM_0>() { cout << "event 0" << endl; return ST_ANIM_0; };
template <> int AnimationSwitch::event<ST_ANIM_1>() { cout << "event 1" << endl; return ST_ANIM_2; };
template <> int AnimationSwitch::event<ST_ANIM_2>() { cout << "event 2" << endl; return ST_ANIM_3; };
template <> int AnimationSwitch::event<ST_ANIM_3>() { cout << "event 3" << endl; return ST_ANIM_0; };
template <> void AnimationSwitch::enter<ST_ANIM_0>()
{
cout << "play idle animation" << endl;
NodePlayer->setMD2Animation(scene::EMAT_STAND);
}
template <> void AnimationSwitch::enter<ST_ANIM_1>()
{
cout << "play walk animation" << endl;
NodePlayer->setMD2Animation(scene::EMAT_RUN);
}
template <> void AnimationSwitch::enter<ST_ANIM_2>()
{
cout << "play jump animation" << endl;
NodePlayer->setMD2Animation(scene::EMAT_JUMP);
}
template <> void AnimationSwitch::enter<ST_ANIM_3>()
{
cout << "play attack animation" << endl;
NodePlayer->setMD2Animation(scene::EMAT_ATTACK);
}
struct AnimationStateMachine : public StateMachine<AnimationSwitch>, public irr::scene::IAnimationEndCallBack
{
AnimationStateMachine(AnimationSwitch &c) : StateMachine<AnimationSwitch>(c) { }
// quand l'animation ce fini, on passe a la suivantun peut long
virtual void OnAnimationEnd (IAnimatedMeshSceneNode *node) { work(); }
};
//! ==========================================================
class MyEventReceiver : public IEventReceiver
{
public:
MyEventReceiver(AnimationStateMachine &fsm) : sm(fsm) {}
bool OnEvent(const SEvent& event)
{
if(event.EventType == irr::EET_KEY_INPUT_EVENT && !event.KeyInput.PressedDown)
{
switch (event.KeyInput.Key)
{
case irr::KEY_KEY_Z:un peut long
// on force l'état 1
Event eOn = {ST_ANIM_1};
sm.work(eOn);
return true;
}
}
return false;
}
private:
AnimationStateMachine &sm;
};
int main(int argc, char** argv)
{
/// Initialisation
IrrlichtDevice *device = createDevice(video::EDT_SOFTWARE, dimension2d<u32>(1024,768), 32, false, false, false,0);
if (!device) return 1;
IVideoDriver* driver = device->getVideoDriver();
ISceneManager* smgr = device->getSceneManager();
IGUIEnvironment* guienv = device->getGUIEnvironment();
/// Charge le node du player
ePlayer = (irr::scene::IAnimatedMesh*)smgr->getMesh("sydney.md2");
NodePlayer = smgr->addAnimatedMeshSceneNode(ePlayer);
NodePlayer->setMaterialTexture(0, driver->getTexture("sydney.bmp"));
NodePlayer->setMaterialFlag(irr::video::EMF_GOURAUD_SHADING, true);
NodePlayer->setMaterialType(irr::video::EMT_REFLECTION_2_LAYER);
// Init player size
NodePlayer->setScale(vector3df(0.5,0.5,0.5));
NodePlayer->setLoopMode(false);
smgr->addCameraSceneNode(0, vector3df(0,30,-40), vector3df(0,5,0));
AnimationSwitch c;
AnimationStateMachine sm(c);
MyEventReceiver receiver(sm);
NodePlayer->setAnimationEndCallback(&sm);
device->setEventReceiver(&receiver);
while(device->run())
{
driver->beginScene(true, true, SColor(255,100,101,140));
smgr->drawAll();
guienv->drawAll();
driver->endScene();
}
device->drop();
return 0;
}