@tsaintthomas, as you said, since both your animations don't key the same bone properties, you can apply them both and they won't overwrite each other. But first, a little description of CCSkeleton and AnimationState.
AnimationState tracks which animation is active and how long it has been active. Also, when the active animation is changed, it does mixing from an old animation to a new animation. CCSkeleton has an AnimationState for convenience, because it is very common to want to apply just one animation at a time with mixing when the animation changes. There are an unlimited number of ways someone might want to apply and mix animations or manipulate bones manually, so for any other behavior you'll need to write some code that describes what you want to do. To do this, extend CCSkeleton and override the update method.
Eg, maybe you want to keep track of two animations and their times and apply them both:
// Class fields.
Animation* animation1;
float time1;
Animation* animation2;
float time2;
...
- (void) update:(ccTime)deltaTime {
Skeleton_update(skeleton, deltaTime);
time1 += deltaTime;
Animation_apply(animation1, skeleton, time1, true);
time2 += deltaTime;
Animation_apply(animation2, skeleton, time1, true);
Skeleton_updateWorldTransform(skeleton);
}
Note both apply calls in this example always pass true for looping. You can get an Animation* from the SkeletonData:
Animation* animation = SkeletonData_findAnimation(skeleton->data, "jump");
The example above keeps track of the times and animations. If you wanted to do mixing when the animations change, you'd need to manage all that state. Doing this is a little tricky and, as described, AnimationState already does this, so you may want to use 2 AnimationStates:
// Class fields.
AnimationState* state1;
AnimationState* state2;
...
// Initialization.
AnimationStateData* stateData = AnimationStateData_create(skeletonData);
AnimationStateData_setMixByName(stateData, "walk", "jump", 0.4f);
AnimationStateData_setMixByName(stateData, "jump", "walk", 0.4f);
state1 = AnimationState_create(stateData);
state2 = AnimationState_create(stateData);
...
- (void) update:(ccTime)deltaTime {
Skeleton_update(skeleton, deltaTime);
AnimationState_update(state1, deltaTime);
AnimationState_apply(state1, skeleton);
AnimationState_update(state2, deltaTime);
AnimationState_apply(state2, skeleton);
Skeleton_updateWorldTransform(skeleton);
}
...
// Clean up.
- (void) dealloc {
AnimationStateData_dispose(state1->data); // Only need to dispose the state data once.
AnimationState_dispose(state1);
AnimationState_dispose(state2);
[super dealloc];
}
I don't know your exact use case, but this is probably how I'd do it. ๐ Note the AnimationStateData could be stored outside your CCSkeleton instance and could be reused if you are creating many instances that use the same AnimationStateData.
I should also explain the functions used:
Skeleton_update increments the skeleton's time. Slots use this to keep track of how long an attachment has been in the slot. This can be used by an attachment in various ways, eg to show frame by frame animation. Note that currently no attachments actually make use of this, so not calling Skeleton_update would be fine.
Animation_apply, sets the skeleton's bones and slots based on the keys for the animation at the specified time.
Animation_mix, not shown above, but this sets the skeleton's bones and slots to somewhere between the current skeleton pose and the pose for the animation at the specified time. The interpolation between these poses is controlled by the alpha parameter. If use AnimationState mixing is done for you, otherwise ask if you have specific questions.
AnimationState_update, this increments the time for the AnimationState.
AnimationState_apply, this applies the current animation. It may also do mixing when transitioning from an old animation.
Skeleton_updateWorldTransform, this is very important. The skeleton is made up of bones. The bones are arranged in a hierarchy and the coordinate system for bones is defined by the parent's transform. When the skeleton is posed, it means the bones' local x, y, rotation, scaleX, and scaleY are set. These make up the local transform, meaning they are relative to the parent bone. To draw, we need to get world transform. Skeleton_updateWorldTransform goes through the bone hierarchy and calculates the world x, y, rotation, scaleX, and scaleY for each bone based on the parent transforms. Any time the local transforms are changed for a bone, Skeleton_updateWorldTransform should be called so drawing will reflect the changes.
Hope that makes sense! Be sure to ask for clarification if it doesn't. I will be writing some actual documentation soon.