Historique des modifications - Message

Message #11776

Sujet: Séquenceur d'animation de personnage


Type Date Auteur Contenu
Création du message 19-03-2017 18:18:07 jonath313
Merci pour tes réponses bien concises Magun.
Du coups je n'ai pas copié tas façon de faire, elle est très bien mais j'ai du mal à la maîtriser, néanmoins çà me permet de voir et de comprendre d'autres manières de traiter la problématique.
J'ai alors continué d'améliorer mon code et çà donne quelque chose comme çà :

Code c++ :

 
#ifndef PERSO_CONFIG_H
#define PERSO_CONFIG_H

#define IIDLE_WAIT_ANIM_FRAME   184
#define START_IDLE_ANIM_FRAME   184
#define ENDED_IDLE_ANIM_FRAME   205
#define START_WALK_ANIM_FRAME   1
#define ENDED_WALK_ANIM_FRAME   12
#define START_JUMP_ANIM_FRAME   94
#define ENDED_JUMP_ANIM_FRAME   102
#define START_ATTACK_ANIM_FRAME 32
#define ENDED_ATTACK_ANIM_FRAME 44
#define START_BACKJP_ANIM_FRAME 146
#define ENDED_BACKJP_ANIM_FRAME 158
#define START_TAKE_ANIM_FRAME 32
#define ENDED_TAKE_ANIM_FRAME 38
#define START_GIVE_ANIM_FRAME 38
#define ENDED_GIVE_ANIM_FRAME 44

#define IDLE_ANIM_SPEED         4
#define WALK_ANIM_SPEED         10
#define JUMP_ANIM_SPEED         10
#define ATCK_ANIM_SPEED         10
#define BCKJ_ANIM_SPEED         10
#define TAKE_ANIM_SPEED         20
#define GIVE_ANIM_SPEED         20

#define ANIM_OFFSET             2

#define RESET 0
#define  SET  1

#define KEY_JUMP    KEY_KEY_E
#define KEY_WALK    KEY_KEY_Z
#define KEY_ATTK    KEY_KEY_A
#define KEY_TAKE    KEY_KEY_T
#define KEY_GIVE    KEY_KEY_G

#endif /* PERSO_CONFIG_H */


Code c++ :

 
#include <iostream>
#include <irr/irrlicht.h>
#include <stdio.h>
#include <time.h>

#include "perso_config.h"

using namespace std;
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;

enum  {                       /* On définit les états de la machine à état d'animation */
                    ST_IDLE_0,
                    ST_WALK_1,
                    ST_JUMP_2,
                    ST_ATTAK_3,
                    ST_TAKE_4,
                    ST_GIVE_5};

static uint8_t 	next_state  = ST_IDLE_0, state = ST_IDLE_0;	             /* Initialize next & current states ........................... */

void fsm_state(uint16_t old_anim_end, uint16_t new_anim_start, uint16_t new_anim_end, uint16_t new_anim_speed);
void fsm_goNextState(uint8_t newState);
void fsm_perso_manage_anim(void);

irr::scene::IAnimatedMesh*  ePlayer;
IAnimatedMeshSceneNode*     NodePlayer;                                                 /* Le node du player .......................................... */

irr::scene::IAnimatedMesh*  eBox;
IAnimatedMeshSceneNode*     NodeBox;

irr::scene::IAnimatedMesh*  eTerrain;
IAnimatedMeshSceneNode*     NodeTerrain;

int     frameEnCour     = 0;
bool    anim_working    = false;

int     KEY_SAVED_STATE[KEY_KEY_CODES_COUNT ] =  {0};

static void keypad_KEY_SAVED_STATE_control(uint8_t AskingState, irr::EKEY_CODE key)
{
    int KEY_CURRENT_STATE = KEY_SAVED_STATE[key];

	switch(AskingState)
	{
		case RESET:
			if(KEY_CURRENT_STATE == SET)
			{
				KEY_SAVED_STATE[key] = RESET;
			}
			break;
		case SET:
			if(KEY_CURRENT_STATE == RESET)
			{
				KEY_SAVED_STATE[key] = SET;
			}
			break;
		default:
				break;
	}
}

static void key_event_test(const SEvent& event)
{
    if(event.KeyInput.PressedDown)  // si la touche est appuyée
    {
        keypad_KEY_SAVED_STATE_control(SET, event.KeyInput.Key);
    }else{                          // si la touche est relachée
        keypad_KEY_SAVED_STATE_control(RESET, event.KeyInput.Key);
    }
}

class MyEventReceiver : public IEventReceiver
{
public:

    MyEventReceiver(){}

    bool OnEvent(const SEvent& event)
    {
        // si l'événement et une touche du clavier
        if (event.EventType == irr::EET_KEY_INPUT_EVENT)
        {
            key_event_test(event);
        }
        return false;
    }
private:
};


void animation_bind_idle(EKEY_CODE key)
{
    if((KEY_SAVED_STATE[key] == 0) && anim_working == false)
    {
        NodePlayer->setAnimationSpeed(IDLE_ANIM_SPEED);
        NodePlayer->setFrameLoop(START_IDLE_ANIM_FRAME,ENDED_IDLE_ANIM_FRAME);
        NodePlayer->setLoopMode(true);
        fsm_goNextState(ST_IDLE_0);
    }
}

void animation_bind_single(uint16_t new_anim_start, uint16_t new_anim_end, uint16_t new_anim_speed, EKEY_CODE key, uint8_t newState)
{
    if(KEY_SAVED_STATE[key] == 1 )
    {
        anim_working = true;
        NodePlayer->setAnimationSpeed(new_anim_speed);
        NodePlayer->setFrameLoop(new_anim_start,new_anim_end);
        fsm_goNextState(newState);
    }
}

void animation_bind_ended(uint16_t new_anim_end)
{
  if((NodePlayer->getFrameNr())> (new_anim_end - ANIM_OFFSET))
  {
      anim_working = false;
      NodePlayer->setLoopMode(false);
  }
}

void animation_bind_looped(uint16_t new_anim_start, uint16_t new_anim_end, uint16_t new_anim_speed, EKEY_CODE key, uint8_t newState)
{
    if(KEY_SAVED_STATE[key] == 1)
    {
        NodePlayer->setAnimationSpeed(new_anim_speed);
        NodePlayer->setFrameLoop(new_anim_start,new_anim_end);
        NodePlayer->setLoopMode(true);
        fsm_goNextState(newState);
    }
}

/* ******************************************************************************************************************************** */
/* 			                                           GO TO NEXT STATE                            									*/
/* ******************************************************************************************************************************** */

void fsm_goNextState(uint8_t newState)								/* Function for going to next state automatically ............. */
{
	next_state = newState;											/* Stay to actual state : leds flashing ....................... */
}


/* ******************************************************************************************************************************** */
/* 							                                FSM												                    	*/
/* ******************************************************************************************************************************** */

void fsm_perso_manage_anim(void)
{
    /// On relève le numero de la frame en cours
    frameEnCour = NodePlayer->getFrameNr();

    switch(state)
	{
	    case ST_IDLE_0:                                                             // Etat Idle
	        animation_bind_single(START_ATTACK_ANIM_FRAME  , ENDED_ATTACK_ANIM_FRAME   , ATCK_ANIM_SPEED, KEY_ATTK, ST_ATTAK_3);
	        animation_bind_single(START_JUMP_ANIM_FRAME    , ENDED_JUMP_ANIM_FRAME     , JUMP_ANIM_SPEED, KEY_JUMP, ST_JUMP_2);
	        animation_bind_single(START_TAKE_ANIM_FRAME    , ENDED_TAKE_ANIM_FRAME     , TAKE_ANIM_SPEED, KEY_TAKE, ST_TAKE_4);
	        animation_bind_single(START_GIVE_ANIM_FRAME    , ENDED_GIVE_ANIM_FRAME     , GIVE_ANIM_SPEED, KEY_GIVE, ST_GIVE_5);
	        animation_bind_looped(START_WALK_ANIM_FRAME    , ENDED_WALK_ANIM_FRAME     , WALK_ANIM_SPEED, KEY_WALK, ST_WALK_1);
	        break;
		case ST_WALK_1:
            animation_bind_single(START_ATTACK_ANIM_FRAME  , ENDED_ATTACK_ANIM_FRAME   , ATCK_ANIM_SPEED, KEY_ATTK, ST_ATTAK_3);
	        animation_bind_single(START_JUMP_ANIM_FRAME    , ENDED_JUMP_ANIM_FRAME     , JUMP_ANIM_SPEED, KEY_JUMP, ST_JUMP_2);
            animation_bind_idle(KEY_WALK);
            break;
		case ST_JUMP_2:
		    animation_bind_ended(ENDED_JUMP_ANIM_FRAME);
            animation_bind_idle(KEY_JUMP);
            break;
        case ST_ATTAK_3:
            animation_bind_ended(ENDED_ATTACK_ANIM_FRAME);
            animation_bind_idle(KEY_ATTK);
            break;
        case ST_TAKE_4:
            animation_bind_ended(ENDED_TAKE_ANIM_FRAME);
            if(NodeBox)NodePlayer->addChild(NodeBox);
            NodeBox -> setScale(vector3df(0.1f,0.1f,0.1f));
            NodeBox -> setPosition(vector3df(0.0f,-0.1f,0.0f));
            animation_bind_idle(KEY_TAKE);
            break;
        case ST_GIVE_5:
            animation_bind_ended(ENDED_GIVE_ANIM_FRAME);
            if(NodeBox)NodeTerrain -> addChild(NodeBox);
            if(NodeBox)NodePlayer->removeChild(NodeBox);
            NodeBox -> setScale(vector3df(0.5f,0.5f,0.5f));
            NodeBox -> setPosition(vector3df(0.0f,10.1f,0.0f));
            animation_bind_idle(KEY_GIVE);
            break;
		default :
            break;
	}
	state = next_state;
}


int main( int argc, char** argv )
{
    /// Initialisation
	IrrlichtDevice *device = createDevice( EDT_OPENGL, dimension2d<u32>(1024,768), 32, false, false, false,0); //EDT_SOFTWARE
	if (!device)    return 1;
	IVideoDriver* driver = device->getVideoDriver();
	ISceneManager* smgr = device->getSceneManager();
	IGUIEnvironment* guienv = device->getGUIEnvironment();

    /// Charge le node du player
    ePlayer = (IAnimatedMesh*)smgr->getMesh("media/ninja.b3d");
    NodePlayer = smgr->addAnimatedMeshSceneNode(ePlayer);
    NodePlayer->setMaterialTexture(0, driver->getTexture("media/nskinbl.jpg"));
    NodePlayer->setMaterialFlag(EMF_LIGHTING, false);
    NodePlayer->setScale(vector3df(0.05f,0.05f,0.05f));
    NodePlayer->setPosition(vector3df(-0.4f,1.1f,0.0f));
    NodePlayer->setRotation(vector3df(0.0f,-240.0f,-90.0f));
    NodePlayer->setAnimationSpeed(IDLE_ANIM_SPEED);
    NodePlayer->setFrameLoop(START_IDLE_ANIM_FRAME,ENDED_IDLE_ANIM_FRAME); // ATTENDRE

    /// Charge le node de l'accessoire
    eBox    =  (IAnimatedMesh*)smgr->getMesh("media/box2.X");
    NodeBox =  smgr->addAnimatedMeshSceneNode(eBox);
    NodeBox -> setMaterialTexture(0, driver->getTexture("media/box3.jpg"));
    NodeBox -> setMaterialFlag(EMF_LIGHTING, false);
    NodeBox -> setScale(vector3df(0.01f,0.01f,0.01f));
    NodeBox -> setPosition(vector3df(-0.4f,1.1f,0.4f));
    NodeBox -> setRotation(vector3df(0.0f,-240.0f,-90.0f));
    NodeBox -> setLoopMode(false);

    /// Charge le node du terrain
    eTerrain    =  (IAnimatedMesh*)smgr->getMesh("media/box2.X");
    NodeTerrain =  smgr->addAnimatedMeshSceneNode(eTerrain);
    NodeTerrain -> setMaterialTexture(0, driver->getTexture("media/box1.jpg"));
    NodeTerrain -> setMaterialFlag(EMF_LIGHTING, false);
    NodeTerrain -> setPosition(vector3df(-0.4f,1.1f,0.0f));
    NodeTerrain -> setRotation(vector3df(0.0f,-240.0f,-90.0f));
    NodeTerrain -> setScale(vector3df(0.01f,0.01f,0.01f));
    NodeTerrain -> setLoopMode(false);

    /// Crée la camera
    ICameraSceneNode *cam = smgr->addCameraSceneNode(0, vector3df(0,0,0), vector3df(0,5,0));
    cam->setFarValue(1000.0f);
    cam->setNearValue (0.0001f);

    /// Crée le receveur d'événements.
    MyEventReceiver receiver;
    device->setEventReceiver(&receiver);

	while(device->run())
	{
	   driver->beginScene(true, true, SColor(255,100,101,140));
           fsm_perso_manage_anim();/// La FSM est dans un état d'attente

	   smgr->drawAll();
	   guienv->drawAll();
	   driver->endScene();
	}
	device->drop();
	return 0;
}

Les nodes "accessoire" et "Terrain" sont uniquement là pour tester le addChild pour attraper ou relâcher un objet. L'objet est soit lié au personnage soit au terrain. On peut les remplacer par des box.

Sinon, c'est pas glorieux mais çà fonctionne, ce code me sert à manager les animations de mon personnage à la manière du topic sur l'animation binding.
Si tu vois d'autres optimisations sur ce code, tes conseils seront les bien venus.

Merci.

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
152 invités en ligne
membre en ligne: -
RSS Feed