Historique des modifications - Message

Message #11767

Sujet: Séquenceur d'animation de personnage


Type Date Auteur Contenu
Création du message 14-03-2017 21:30:41 Magun
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éparer tongue

Retour

Options Liens officiels Caractéristiques Statistiques Communauté
Préférences cookies
Corrections
irrlicht
irrklang
irredit
irrxml
Propulsé par Django
xhtml 1.0
css 2.1
884 membres
1440 sujets
11337 messages
Dernier membre inscrit: Saidov17
160 invités en ligne
membre en ligne: -
RSS Feed