Historique des modifications - Message

Message #11767

Sujet: Séquenceur d'animation de personnage


TypeDateAuteurContenu
Création du message14-03-2017 21:30:41Magun
Salut
voila un petit code, dit moi ce que tu en pensse ?smile

Code c++ :


#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;
}


tu comprendras que les fonctions:

template <> void AnimationSwitch::enter<ST_ANIM_0>()
template <> void AnimationSwitch::enter<ST_ANIM_1>()
template <> void AnimationSwitch::enter<ST_ANIM_2>()
template <> void AnimationSwitch::enter<ST_ANIM_3>()

permettent de définir les frames des animations
et que les fonctions:

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; };

donne la fsm, donc l'enchainement des évènement.
et donc grâce à irr::scene::IAnimationEndCallBack:

dans l'état 0, quand l'animation est fini, on la rejoue (loop -> idle)
dans les autres états, quand l'animation est fini, on passe à la suivant
dans l'état 3, on retourne à l'état 0 qui reboucle, jusqu'a un event

et donc tu peux faire un ton "graphe" d'animation tranqu'il et juste chager les fonctions d'events

voila, désolé du temp de réponsse, j'avais un éxamain a préparertongue

Retour

OptionsLiens officielsCaractéristiquesStatistiquesCommunauté
Préférences cookies
Corrections
irrlicht
irrklang
irredit
irrxml
Propulsé par Django
xhtml 1.0
css 2.1
884 membres
1441 sujets
11339 messages
Dernier membre inscrit: Saidov17
37 invités en ligne
membre en ligne: -
RSS Feed