First of all, I need to notify you that my answer needs a slight modification to your approach in RunAnimation() to be able to let this answer works.
Personally I don't recommend you to use that version of RunAnimation() function as it always executes the code with CCRepeatForever manner. My answer here can be applied with your case with a slight modification to your RunAnimation(). I recommend you to cache all animations, and actions in time of loading/creating character phase then when you need to play them you play it in separate function ie. walk(), idle(). We can combine using them later.
Please note that I mean both of animation and actions. This will benefit for more complex animation handling similar to combo system for beat'em up game later on. It's cleaner. All in all this question is complex if we need to cover all cases and handle stuff properly, you will see why at Ideas section below.
Basically you have to utilize using CCRepeat, and CCSequence to create one combined action to be used for running animation. As always, keep CCRepeatForever away from other CCActions context. It should not be mingled around. I always treat CCRepeatForever as a special case (special care) I need to pay attention to.
First question
About playing 3-5 times of first idle animation, then 1-2 times of second idle animation then loop both of them endlessly, you can do this by using the similar code as follows.
CCAction *_cached_idleAction = CCRepeatForever::create(CCSequence::createWithTwoActions(CCRepeat::create(_cached_idle_anim_1, 5), CCRepeat::create(_cached_idle_anim_2, 3)));
Then you use
_cached_idleAction
variable in your idle() function.
void GameCharacter::idle() {
stopAllActions();
runAction(_cached_idleAction);
}
Second question
About running idle animation after jump and walk animation, this relates to some kind of following up approach. The difficulty comes because we shouldn't mingle CCRepeatForever with any other CCAction (to be clear it won't mix and match with CCSequence, so try to avoid combining these twos).
The solution is that you create a separate function to play idle animation like the following.
void GameCharacter::followUpAction(){
// simple case
idle();
}
This spans into 2 cases
1) Go to idle after non-repeat-forever action (jump)
CCSequence *_cached_jumpAction = CCSequence::createWithTwoActions(CCRepeat::create(_cached_jump_anim, 1), CCCallFunc::create(this, callfunc_selector(GameCharacter::followUpAction)));
Then you normally playing jump via jump() as follows.
void GameCharacter::jump() {
stopAllActions();
runAction(_cached_jumpAction);
}
After jump animation finishes playing, it will play idle animation endlessly.
2) Go to idle after repeat-forever action (walk)
Because you're walking (it's repeat-forever), you need to call
stopAllActions()
to stop it first, then call walk(). Thus it means there's no automatic-sense like in the 1st case. You need to detect it via code which time you need to make it stopped and then run another repeat-forever action subsequently.
Ideas
The above detail applies to normal and simple case. In order to cover all cases and handle things properly, we need to keep track of
The current state of character in which action (or say animation) it's acting (or playing).
You may need to inject CCCallFunc in each action created for all character's actions in order to set its state whenever it plays such animation. You don't set the state when you call runAction() because the animation will play next frame and not the same time as setting state and also remember that we can chain different action (state) inside one action.
previousAction and currentAction
stopAllActions() is not a cure. If you call this in the mid and intention to switch animation, you will probably have a high chance to stop other not related to animation ie. knockback translation due to hit-effect from enemies. Thus a character will freeze and such knockback effect won't properly apply. To solve this, we have to keep track of those two actions and stop it accordingly, not all.
- followUpAction() is a key