Chaining Animations?

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Chaining Animations?

Post by thoma91 »

Hi! Is there a way to chain animations in Irrlicht?

With this code, the node walks until it takes a hit, then comes the second animation, and when it finishes, the node just stands still:

Code: Select all

 
node->setLoopMode(true);
node->setFrameLoop(0,24);
if(...){
node->setLoopMode(false);
node->setFrameLoop(272,288);}
 
With this code, when I want the node to return to walking after the hit, the hit taking animation does not happen, it walks all the time.

Code: Select all

 
node->setLoopMode(true);
node->setFrameLoop(0,24);
if(...){
node->setLoopMode(false);
node->setFrameLoop(272,288);
node->setLoopMode(true);
node->setFrameLoop(0,24);
}
 
How could this be solved?
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Re: Chaining Animations?

Post by serengeor »

if(...){
node->setLoopMode(false);
node->setFrameLoop(272,288);
node->setLoopMode(true);
node->setFrameLoop(0,24);
}
the animations don't go into some sort of queue AFAIK, so if you set it to one and at the same time change to other it would use the last one only, you have to think of something better. Maybe a callback for when animation ends, if irrlicht supports them.
Working on game: Marrbles (Currently stopped).
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Chaining Animations?

Post by thoma91 »

Sorry, it did not work. The result is just the same.
Any other ideas?
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Re: Chaining Animations?

Post by serengeor »

thoma91 wrote:Sorry, it did not work. The result is just the same.
Any other ideas?
What did not work? I just quoted your own code and explained why it shouldn't work.
You either have to set up some callbacks somehow or check every frame if it finished it's animation and start the other one.
Working on game: Marrbles (Currently stopped).
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Chaining Animations?

Post by thoma91 »

Sorry, I was inaccurate. I meant I tried to use a callback function, but it did not work.
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Re: Chaining Animations?

Post by serengeor »

thoma91 wrote:Sorry, I was inaccurate. I meant I tried to use a callback function, but it did not work.
Well, you should post it here how you tried and say where it fails.
Working on game: Marrbles (Currently stopped).
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Chaining Animations?

Post by thoma91 »

Here's the code:
(I also set an intermediate function, for rotating the node a bit between the two moves. unfortunately this didn't change nothing, the first animation does not happen.)

Code: Select all

 
...
void enemymove2()
{
        printf("enemymove2 started\n");
        node->setLoopMode(true);
        int i;
        for (i = 0; i < 25; ++i){
            node->setFrameLoop(i,i);
            printf("Frame %d drawn\n",i);
            }
}
 
void enemymove()
{
        printf("enemymove started\n");
        node->setRotation(core::vector3df(0,-96,0));
        printf("rotation ok\n");
        enemymove2();
}
 
 
void loading(void incomingFuncName())
{
     printf("loading started\n");
     incomingFuncName();
}
 
 
bool shoot()
{
...
 
if(...){
        node->setLoopMode(false);
        int i;
        for (i = 272; i < 17; ++i){
            node->setFrameLoop(i,i);
            printf("Frame %d drawn\n",i);
        }
 
        printf("functioncall\n");
        loading(enemymove);
}
 
And this is what i get on the console:

Code: Select all

 
functioncall
loading started
enemymove started
rotation ok
enemymove2 started
Frame 0 drawn
...
Frame 24 drawn
 
So anyone got an idea how should I change animations in Irrlicht?
teto
Posts: 159
Joined: Thu Dec 03, 2009 9:37 pm
Location: /home
Contact:

Re: Chaining Animations?

Post by teto »

I think there will be a more efficient way to deal with animations in 1.8 (you need a lot of user code to get something nice right now).

Did you look at:
virtual void irr::scene::IAnimatedMeshSceneNode::setAnimationEndCallback ( IAnimationEndCallBack * callback = 0 )

It keeps getting called until a new animation is set.
Using trunk with mingw/gcc 4.6, Windows 7 64 bits driver opengl
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Re: Chaining Animations?

Post by serengeor »

thoma91 wrote:Here's the code:
(I also set an intermediate function, for rotating the node a bit between the two moves. unfortunately this didn't change nothing, the first animation does not happen.)

Code: Select all

 
...
void enemymove2()
{
        printf("enemymove2 started\n");
        node->setLoopMode(true);
        int i;
        for (i = 0; i < 25; ++i){
            node->setFrameLoop(i,i);
            printf("Frame %d drawn\n",i);
            }
}
 
void enemymove()
{
        printf("enemymove started\n");
        node->setRotation(core::vector3df(0,-96,0));
        printf("rotation ok\n");
        enemymove2();
}
 
 
void loading(void incomingFuncName())
{
     printf("loading started\n");
     incomingFuncName();
}
 
 
bool shoot()
{
...
 
if(...){
        node->setLoopMode(false);
        int i;
        for (i = 272; i < 17; ++i){
            node->setFrameLoop(i,i);
            printf("Frame %d drawn\n",i);
        }
 
        printf("functioncall\n");
        loading(enemymove);
}
 
And this is what i get on the console:

Code: Select all

 
functioncall
loading started
enemymove started
rotation ok
enemymove2 started
Frame 0 drawn
...
Frame 24 drawn
 
So anyone got an idea how should I change animations in Irrlicht?
You just rewrote the same thing that you did before just with functions :?

When I was talking about callbacks I meant something like this: http://irrlicht.sourceforge.net/docu/cl ... e48393f1bd
Working on game: Marrbles (Currently stopped).
Ravi08
Posts: 249
Joined: Thu Jul 17, 2008 12:25 pm

Re: Chaining Animations?

Post by Ravi08 »

Hi, not sure if this will help but i used it in the past, i used it for something else but could work for you.

Code: Select all

int newAnim = 0;
int currentAnim = 0;
 
if(newAnim != currentAnim)
{
      currentAnim = newAnim;
      if(currentAnim == 1)
      {
           node->setFrameLoop(0,0);
           node->setAnimationSpeed(0);
      }
      if(currentAnim == 2)
      {
           node->setFrameLoop(1,40);
           node->setAnimationSpeed(10);
      }
      if(currentAnim == 3)
      {
           node->setFrameLoop(43,93);
           node->setAnimationSpeed(10);
      }
}
You have to select when and where you change the value of newAnim, ie change it to 1 when standing, 2 for walk and 3 for shot.
"Hey Baby Wobbling Wobbling"
-Russell Peters
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Chaining Animations?

Post by thoma91 »

Hi!
Thanks for the answers, but none of them works for me.
Maybe it's my fault, perhaps you could try your recommendations at home if you've got time.
(setAnimationEndCallback(0); does nothing for me)

I could only achieve this:

Code: Select all

 
int currentAnim = 0;
...
void enemyReact()
{
if(currentAnim == 0){
        // hit-taking animation
        node->setLoopMode(false);
        node->setFrameLoop(272,288);
        currentAnim++;
}
else if(currentAnim == 1){
        // walking animation
        node->setLoopMode(true);
        node->setFrameLoop(0,24);
        currentAnim=0;
}
}
 
The enemyReact function is called when the enemy takes hit.
For the first hit, the hit-taking animation runs, then the enemy stops.
For the second hit, it just starts walking again.
The third is like the first,etc,until it dies. The dying animation works well.

But this isn't the right way, because I want the walking anim right after one hit-taking anim.

But ANYHOW I call the walking animation after the other animation, the first one gets ignored. It's kinda frustrating..
Isn't here someone who experienced or dealt with this before?
Ravi08
Posts: 249
Joined: Thu Jul 17, 2008 12:25 pm

Re: Chaining Animations?

Post by Ravi08 »

Hi, sorry im no expert on this but il try, first the code i posted works for me. What i use it for is to do walking animation and saluting animation. (1 = standing, 2 = walk, 3 = salute) Now the way i use it is like this: when player presses forward newAnim becomes 2, when player needs to salute newAnim is 3 and other times newAnim is 1, might not be best way but its simple.

If you posted the whole file i wouldn't mind having a closer look but thats up to you.

Lastly i believe "setAnimationEndCallback" requires the node to be in non looped mode, not 100% check the doc.
"Hey Baby Wobbling Wobbling"
-Russell Peters
serengeor
Posts: 1712
Joined: Tue Jan 13, 2009 7:34 pm
Location: Lithuania

Re: Chaining Animations?

Post by serengeor »

Ravi08 wrote:Hi, sorry im no expert on this but il try, first the code i posted works for me. What i use it for is to do walking animation and saluting animation. (1 = standing, 2 = walk, 3 = salute) Now the way i use it is like this: when player presses forward newAnim becomes 2, when player needs to salute newAnim is 3 and other times newAnim is 1, might not be best way but its simple.
He has a problem with playing one animation after another, not identifying/naming the animations.
thoma91 wrote: Maybe it's my fault, perhaps you could try your recommendations at home if you've got time.
(setAnimationEndCallback(0); does nothing for me)
I could but I won't, you need to read some c++ tutorials and learn how to read API doc if you're serious about this. I can't help someone who doesn't want to help himself :wink:
Working on game: Marrbles (Currently stopped).
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Re: Chaining Animations?

Post by sudi »

Here is a simple example on how you could do it

CAnimationController.h

Code: Select all

 
#ifndef CANIMATIONCONTROLLER_H
#define CANIMATIONCONTROLLER_H
 
#include <IAnimatedMeshSceneNode.h>
#include <irrMap.h>
 
class CAnimationController : public irr::scene::IAnimationEndCallBack
{
public:
    struct Animation
    {
        Animation()
        {
            name = "";
            start = 0;
            end = 1;
            looping = false;
        }
        Animation(const irr::c8* n, const irr::u32& s, const irr::u32& e, const bool& loop)
        {
            name = n;
            start = s;
            end = e;
            looping = loop;
        }
        Animation(const Animation& other)
        {
            name = other.name;
            start = other.start;
            end = other.end;
            looping = other.looping;
        }
 
        irr::core::stringc name;
        irr::u32 start;
        irr::u32 end;
        bool looping;
    };
 
    CAnimationController();
    virtual ~CAnimationController();
 
    void setAnimatedMeshNode(irr::scene::IAnimatedMeshSceneNode* node);
 
    void addAnimation(const irr::c8* name, const irr::u32& start, const irr::u32& end, const bool& loop = false);
 
    void playAnimation(const irr::c8* name);
 
    void OnAnimationEnd(irr::scene::IAnimatedMeshSceneNode* node);
protected:
    void setAnimation(const Animation& anim);
 
    irr::core::map<irr::core::stringc, Animation> animations;
    Animation currentAnimation;
    Animation nextAnimation;
    irr::scene::IAnimatedMeshSceneNode*animatedNnode;
    bool animationRunning;
    bool hasNext;
};
 
#endif // CANIMATIONCONTROLLER_H
 
CAnimationController.cpp

Code: Select all

#include "CAnimationController.h"
 
CAnimationController::CAnimationController()
{
    animatedNnode = 0;
    animationRunning = false;
    hasNext = false;
}
 
CAnimationController::~CAnimationController()
{
    if (animatedNnode)
    {
        animatedNnode->setAnimationEndCallback(0);
        animatedNnode->drop();
    }
    animatedNnode = 0;
}
 
void CAnimationController::OnAnimationEnd(irr::scene::IAnimatedMeshSceneNode *node)
{
    animationRunning = false;
    if ((hasNext || currentAnimation.looping) && animatedNnode)
    {
        if (hasNext)
            setAnimation(nextAnimation);
        else
            setAnimation(currentAnimation);
        hasNext = false;
    }
}
 
void CAnimationController::addAnimation(const irr::c8 *name, const irr::u32 &start, const irr::u32 &end, const bool& loop)
{
    animations[name] = Animation(name, start, end, loop);
}
 
void CAnimationController::setAnimatedMeshNode(irr::scene::IAnimatedMeshSceneNode *node)
{
    if (animatedNnode == node)
        return;
 
    if (animatedNnode)
    {
        animatedNnode->setAnimationEndCallback(0);
        animatedNnode->drop();
    }
 
    animatedNnode = node;
 
    if (animatedNnode)
    {
        animatedNnode->grab();
 
        currentAnimation.start = 0;
        currentAnimation.end = animatedNnode->getEndFrame(); //There is no way to get the actual frame count...
 
        animatedNnode->setAnimationEndCallback(this);
    }
}
 
void CAnimationController::playAnimation(const irr::c8 *name)
{
    if (animations.find(name) == 0)
        return;
 
    printf("change Animation to %s\n", name);
 
    if (animationRunning)
    {
        nextAnimation = animations[name];
        hasNext = true;
    }
    else
        setAnimation(animations[name]);
}
 
void CAnimationController::setAnimation(const Animation& anim)
{
    currentAnimation = anim;
    animatedNnode->setFrameLoop(currentAnimation.start, currentAnimation.end);
    animatedNnode->setCurrentFrame(currentAnimation.start);
    animatedNnode->setLoopMode(false);
    animationRunning = true;
}

main.cpp

Code: Select all

#include "CAnimationController.h"
#include <irrlicht.h>
 
struct events : irr::IEventReceiver
{
    bool OnEvent(const irr::SEvent& event)
    {
        if (event.EventType == irr::EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown)
        {
            if (event.KeyInput.Key == irr::KEY_KEY_Q)
            {
                controller.playAnimation("idle");
            }
            else if (event.KeyInput.Key == irr::KEY_KEY_W)
            {
                controller.playAnimation("crouch");
            }
            else if (event.KeyInput.Key == irr::KEY_KEY_E)
            {
                controller.playAnimation("stand");
            }
            else if (event.KeyInput.Key == irr::KEY_ESCAPE)
            {
                device->closeDevice();
            }
        }
        return false;
    }
    CAnimationController controller;
    irr::IrrlichtDevice* device;
};
 
int main()
{
    irr::IrrlichtDevice* device = irr::createDevice(irr::video::EDT_OPENGL);
 
    irr::scene::IAnimatedMeshSceneNode* dwarf = device->getSceneManager()->addAnimatedMeshSceneNode(device->getSceneManager()->getMesh("../lib/irrlicht-1.7.2/media/dwarf.x")); //change to fit your media path
    dwarf->setMaterialFlag(irr::video::EMF_LIGHTING, false);
    dwarf->setLoopMode(false);
 
    printf("Total frames: %i\n", dwarf->getEndFrame());
 
    device->getSceneManager()->addCameraSceneNodeFPS();
 
    events event;
 
    event.device = device;
 
    event.controller.setAnimatedMeshNode(dwarf);
 
    printf("!!!Total frames: %i\n", dwarf->getEndFrame());
 
    event.controller.addAnimation("crouch", 0, 20);
    event.controller.addAnimation("idle", 21, 30, true);
    event.controller.addAnimation("stand", 31, 54);
 
    device->setEventReceiver(&event);
 
    while (device->run())
    {
        device->getVideoDriver()->beginScene();
        device->getSceneManager()->drawAll();
        device->getVideoDriver()->endScene();
    }
 
    device->drop();
 
    return 0;
}
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
thoma91
Posts: 28
Joined: Tue Aug 09, 2011 10:00 am

Re: Chaining Animations?

Post by thoma91 »

Thank you Sudi for your example, but it's still not, what I'm looking for.
This changes animations by pressing keys.
I need automatic change, after one animation is finished/played.
The problem is, when I set up a second animation, the first one gets ignored.
Even if there's an if condition before it, like this:

Code: Select all

 
int something=0;
...
void reaction()
{
if(something==0)
{
        node->setLoopMode(false);
        node->setFrameLoop(272,288);
        ++something;
        reaction();
}
else if(something==1)
{
        node->setLoopMode(true);
        node->setFrameLoop(0,24);
        --something;
}
}
...
bool shoot()
{
...
if(...){        // takes hit
reaction();
}
...
 
So the first animation has to be played, before the second could start, but only the second one is played.
Sudi, and others: could you help me solving this?
Post Reply