[SOLVED] Playing a saved action as a class member variable

Hello , I just started using Cocos2dx and I am having a lot of fun learning about it.
I am currently attempting to load a saved animation from my sprite sheet. I have something like this

void HelloWorld::initiateFlyingAnimation()
{
//This is the plist
SpriteFrameCache::getInstance()->addSpriteFramesWithFile(“msprite.plist”);

//This is the real Texture file name
this->flyinganimation=Animation::create();
for(int i=0;i<=79;i++)
{
    char szName[100]={0};
    sprintf(szName,"tmp-%d.gif",i); //This is the frame names
    this->flyinganimation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(szName));
}
this->flyinganimation->setDelayPerUnit(0.1f);
this->flyingAction = CCRepeatForever::create( CCAnimate::create(this->flyinganimation));
flyingAction->setTag(12);

}

as you can see the variable flyingAction has been declared inside my class. Now in another method of mine I have something like this

 Caode Sample A:
    void HelloWorld::UpdateEagleMovement(float dt)
    {
        //Check if the eagle is suppose to be moving
        if(eglmotion.motionDirection == HelloWorld::EagleMotion::EnumRight)
        {
            sprite_eagle->runAction(this->flyingAction); //Crashes on this
        }
    }

Now when I run the above method sprite_eagle->runAction(this->flyingAction); causes a crash. Why is that ? since initiateFlyingAnimation method runs before this code. However if I do this the code works

code Sample : B
void HelloWorld::UpdateEagleMovement(float dt)
    {
        //Check if the eagle is suppose to be moving
        if(eglmotion.motionDirection == HelloWorld::EagleMotion::EnumRight)
        {
            SpriteFrameCache::getInstance()->addSpriteFramesWithFile("msprite.plist");
        
        Animation* animation=Animation::create();
        for(int i=0;i<=79;i++)
        {
            char szName[100]={0};
            sprintf(szName,"tmp-%d.gif",i); 
            animation->addSpriteFrame(SpriteFrameCache::getInstance()->getSpriteFrameByName(szName));
        }
        animation->setDelayPerUnit(0.1f);
        this->flyingAction = CCRepeatForever::create( CCAnimate::create(animation));
        this->flyingAction->setTag(12);
        
        //this->addChild(sprite_eagle, 0, 23);
        sprite_eagle->runAction(this->flyingAction);
        }
    }

Why doesnt code Sample A work if it is being called after the void HelloWorld::initiateFlyingAnimation()?

I think I figured out how to fix this problem however I do not know why this fix works and I would appreciate it if someone could explain this. The fix is as follows

In the method void HelloWorld::initiateFlyingAnimation() add the following two statements at the end

flyingAction->retain();
flyinganimation->retain();

Now before running the action in the method UpdateEagleMovement add the following before running the action

sprite_eagle->stopAllActions(); //Stop actions ? Why do we have to stop all the actions
sprite_eagle->runAction( flyingAction); //run the action

My question is why did we have to retain the flyingAction and flyingAnimation they were class members ? How did they get destroyed or why did I have to retain them ? Also why did I have to stopAllAction before running the action

after reading this article I understand why I need to call retain. However i still would like to know why I had to call stopAllActions before doing

sprite_eagle->runAction( flyingAction); //run the action

The sprite was not performing any action so why was there a need to do that ?

You don’t have to. It’s just a precaution in case you have actions running and don’t want the running actions interfere with the new one.

E.g, there’s a running action, which moves a sprite from left to right. Your new action moves the same sprite from right to left with the same movement speed. Now the two actions are stacked and the sprite will stay at its position. The actions will void each other, as they are run on the same sprite.

If you don’t want to run old actions, but only the new one, you stop all actions currently running on the sprite.

If you want to additionally run the new action on the same sprite, you don’t stop the currently running actions on the sprite.

1 Like

Thanks for the reply. I understand that but I wanted to know why my game crashes if I dont stop the action. And the sprite isnt performing any action.

Under some circumstances the interference of the new action could lead to a bad state and the action will crash. E.g, a missing initialization, which is performed by stopping all actions beforehand.

To find out, what the problem in your specific case is, you would have to step through the action’s code and debug it.

1 Like

Thanks for clearing that up. Seems like I was playing an action on RepeatForever and then I was trying to play that action again . Stoping that action first fixed my issue. Thanks again.