Better AnimationState listeners, including on a TrackEntry.

This commit is contained in:
NathanSweet 2014-05-11 21:00:50 +02:00
parent cd7538d6a1
commit 7199d22417
9 changed files with 155 additions and 59 deletions

View File

@ -57,6 +57,8 @@ struct spTrackEntry {
float delay, time, lastTime, endTime, timeScale;
spAnimationStateListener listener;
float mixTime, mixDuration, mix;
void* rendererObject;
};
struct spAnimationState {

View File

@ -74,6 +74,7 @@
#include <spine/MeshAttachment.h>
#include <spine/SkinnedMeshAttachment.h>
#include <spine/BoundingBoxAttachment.h>
#include <spine/AnimationState.h>
#ifdef __cplusplus
extern "C" {
@ -86,6 +87,8 @@ extern "C" {
void _spAtlasPage_createTexture (spAtlasPage* self, const char* path);
void _spAtlasPage_disposeTexture (spAtlasPage* self);
char* _spUtil_readFile (const char* path, int* length);
spTrackEntry* _spAnimationState_createTrackEntry (spAnimationState* self);
void _spAnimationState_disposeTrackEntry (spAnimationState* self, spTrackEntry* entry);
#ifdef SPINE_SHORT_NAMES
#define _AtlasPage_createTexture(...) _spAtlasPage_createTexture(__VA_ARGS__)
@ -109,6 +112,11 @@ char* _readFile (const char* path, int* length);
/**/
spTrackEntry* _spTrackEntry_create ();
void _spTrackEntry_dispose (spTrackEntry* entry);
/**/
void _spAttachmentLoader_init (spAttachmentLoader* self, /**/
void (*dispose) (spAttachmentLoader* self), /**/
spAttachment* (*newAttachment) (spAttachmentLoader* self, spSkin* skin, spAttachmentType type, const char* name,

View File

@ -45,14 +45,6 @@ void _spTrackEntry_dispose (spTrackEntry* entry) {
FREE(entry);
}
void _spTrackEntry_disposeAll (spTrackEntry* entry) {
while (entry) {
spTrackEntry* next = entry->next;
_spTrackEntry_dispose(entry);
entry = next;
}
}
/**/
typedef struct {
@ -71,12 +63,20 @@ spAnimationState* spAnimationState_create (spAnimationStateData* data) {
return self;
}
void _spAnimationState_disposeAllEntries (spAnimationState* self, spTrackEntry* entry) {
while (entry) {
spTrackEntry* next = entry->next;
_spAnimationState_disposeTrackEntry(self, entry);
entry = next;
}
}
void spAnimationState_dispose (spAnimationState* self) {
int i;
_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
FREE(internal->events);
for (i = 0; i < self->trackCount; ++i)
_spTrackEntry_disposeAll(self->tracks[i]);
_spAnimationState_disposeAllEntries(self, self->tracks[i]);
FREE(self->tracks);
FREE(self);
}
@ -140,7 +140,7 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
if (alpha >= 1) {
alpha = 1;
_spTrackEntry_dispose(current->previous);
_spAnimationState_disposeTrackEntry(self, current->previous);
current->previous = 0;
}
spAnimation_mix(current->animation, skeleton, current->lastTime, time,
@ -203,8 +203,8 @@ void spAnimationState_clearTrack (spAnimationState* self, int trackIndex) {
self->tracks[trackIndex] = 0;
if (current->previous) _spTrackEntry_dispose(current->previous);
_spTrackEntry_disposeAll(current);
if (current->previous) _spAnimationState_disposeTrackEntry(self, current->previous);
_spAnimationState_disposeAllEntries(self, current);
}
spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index) {
@ -237,9 +237,9 @@ void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEnt
} else
entry->previous = current;
} else
_spTrackEntry_dispose(current);
_spAnimationState_disposeTrackEntry(self, current);
if (previous) _spTrackEntry_dispose(previous);
if (previous) _spAnimationState_disposeTrackEntry(self, previous);
}
self->tracks[index] = entry;
@ -260,9 +260,9 @@ spTrackEntry* spAnimationState_setAnimationByName (spAnimationState* self, int t
spTrackEntry* spAnimationState_setAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop) {
spTrackEntry* entry;
spTrackEntry* current = _spAnimationState_expandToIndex(self, trackIndex);
if (current) _spTrackEntry_disposeAll(current->next);
if (current) _spAnimationState_disposeAllEntries(self, current->next);
entry = _spTrackEntry_create();
entry = _spAnimationState_createTrackEntry(self);
entry->animation = animation;
entry->loop = loop;
entry->endTime = animation->duration;
@ -280,7 +280,7 @@ spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIn
float delay) {
spTrackEntry* last;
spTrackEntry* entry = _spTrackEntry_create();
spTrackEntry* entry = _spAnimationState_createTrackEntry(self);
entry->animation = animation;
entry->loop = loop;
entry->endTime = animation->duration;

View File

@ -47,16 +47,34 @@ bool ExampleLayer::init () {
if (!LayerColor::initWithColor(Color4B(128, 128, 128, 255))) return false;
skeletonNode = SkeletonAnimation::createWithFile("spineboy.json", "spineboy.atlas", 0.6f);
skeletonNode->setMix("walk", "jump", 0.2f);
skeletonNode->setMix("jump", "run", 0.2f);
skeletonNode->setAnimationListener(&ExampleLayer::animationStateEvent, this);
// skeletonNode->timeScale = 0.3f;
skeletonNode->debugBones = true;
skeletonNode->startListener = [this](int trackIndex) {
spTrackEntry* entry = spAnimationState_getCurrent(skeletonNode->state, trackIndex);
const char* animationName = (entry && entry->animation) ? entry->animation->name : 0;
log("%d start: %s", trackIndex, animationName);
};
skeletonNode->endListener = [](int trackIndex) {
log("%d end", trackIndex);
};
skeletonNode->completeListener = [](int trackIndex, int loopCount) {
log("%d complete: %d", trackIndex, loopCount);
};
skeletonNode->eventListener = [](int trackIndex, spEvent* event) {
log("%d event: %s, %d, %f, %s", trackIndex, event->data->name, event->intValue, event->floatValue, event->stringValue);
};
skeletonNode->setMix("walk", "jump", 0.2f);
skeletonNode->setMix("jump", "run", 0.2f);
skeletonNode->setAnimation(0, "walk", true);
skeletonNode->addAnimation(0, "jump", false, 3);
spTrackEntry* jumpEntry = skeletonNode->addAnimation(0, "jump", false, 3);
skeletonNode->addAnimation(0, "run", true);
skeletonNode->setStartListener(jumpEntry, [](int trackIndex) {
log("jumped!", trackIndex);
});
// skeletonNode->addAnimation(1, "test", true);
// skeletonNode->runAction(RepeatForever::create(Sequence::create(FadeOut::create(1), FadeIn::create(1), DelayTime::create(5), NULL)));
@ -73,24 +91,3 @@ void ExampleLayer::update (float deltaTime) {
// Test releasing memory.
// Director::getInstance()->replaceScene(ExampleLayer::scene());
}
void ExampleLayer::animationStateEvent (SkeletonAnimation* node, int trackIndex, spEventType type, spEvent* event, int loopCount) {
spTrackEntry* entry = spAnimationState_getCurrent(node->state, trackIndex);
const char* animationName = (entry && entry->animation) ? entry->animation->name : 0;
switch (type) {
case SP_ANIMATION_START:
log("%d start: %s", trackIndex, animationName);
break;
case SP_ANIMATION_END:
log("%d end: %s", trackIndex, animationName);
break;
case SP_ANIMATION_COMPLETE:
log("%d complete: %s, %d", trackIndex, animationName, loopCount);
break;
case SP_ANIMATION_EVENT:
log("%d event: %s, %s: %d, %f, %s", trackIndex, animationName, event->data->name, event->intValue, event->floatValue, event->stringValue);
break;
}
fflush(stdout);
}

View File

@ -44,8 +44,6 @@ public:
CREATE_FUNC (ExampleLayer);
private:
spine::SkeletonAnimation* skeletonNode;
void animationStateEvent (spine::SkeletonAnimation* node, int trackIndex, spEventType type, spEvent* event, int loopCount);
};
#endif // _EXAMPLELAYER_H_

View File

@ -40,8 +40,12 @@ using std::vector;
namespace spine {
static void callback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) {
((SkeletonAnimation*)state->context)->onAnimationStateEvent(trackIndex, type, event, loopCount);
static void animationCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) {
((SkeletonAnimation*)state->rendererObject)->onAnimationStateEvent(trackIndex, type, event, loopCount);
}
static void trackEntryCallback (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, int loopCount) {
((SkeletonAnimation*)state->rendererObject)->onTrackEntryEvent(trackIndex, type, event, loopCount);
}
SkeletonAnimation* SkeletonAnimation::createWithData (spSkeletonData* skeletonData) {
@ -65,8 +69,8 @@ SkeletonAnimation* SkeletonAnimation::createWithFile (const char* skeletonDataFi
void SkeletonAnimation::initialize () {
ownsAnimationStateData = true;
state = spAnimationState_create(spAnimationStateData_create(skeleton->data));
state->context = this;
state->listener = callback;
state->rendererObject = this;
state->listener = animationCallback;
}
SkeletonAnimation::SkeletonAnimation (spSkeletonData *skeletonData)
@ -106,8 +110,8 @@ void SkeletonAnimation::setAnimationStateData (spAnimationStateData* stateData)
ownsAnimationStateData = false;
state = spAnimationState_create(stateData);
state->context = this;
state->listener = callback;
state->rendererObject = this;
state->listener = animationCallback;
}
void SkeletonAnimation::setMix (const char* fromAnimation, const char* toAnimation, float duration) {
@ -145,7 +149,64 @@ void SkeletonAnimation::clearTrack (int trackIndex) {
}
void SkeletonAnimation::onAnimationStateEvent (int trackIndex, spEventType type, spEvent* event, int loopCount) {
if (listener) listener(this, trackIndex, type, event, loopCount);
switch (type) {
case SP_ANIMATION_START:
if (startListener) startListener(trackIndex);
break;
case SP_ANIMATION_END:
if (endListener) endListener(trackIndex);
break;
case SP_ANIMATION_COMPLETE:
if (completeListener) completeListener(trackIndex, loopCount);
break;
case SP_ANIMATION_EVENT:
if (eventListener) eventListener(trackIndex, event);
break;
}
}
void SkeletonAnimation::onTrackEntryEvent (int trackIndex, spEventType type, spEvent* event, int loopCount) {
spTrackEntry* entry = spAnimationState_getCurrent(state, trackIndex);
if (!entry->rendererObject) return;
_TrackEntryListeners* listeners = (_TrackEntryListeners*)entry->rendererObject;
switch (type) {
case SP_ANIMATION_START:
if (listeners->startListener) listeners->startListener(trackIndex);
break;
case SP_ANIMATION_END:
if (listeners->endListener) listeners->endListener(trackIndex);
break;
case SP_ANIMATION_COMPLETE:
if (listeners->completeListener) listeners->completeListener(trackIndex, loopCount);
break;
case SP_ANIMATION_EVENT:
if (listeners->eventListener) listeners->eventListener(trackIndex, event);
break;
}
}
static _TrackEntryListeners* getListeners (spTrackEntry* entry) {
if (!entry->rendererObject) {
entry->rendererObject = NEW(spine::_TrackEntryListeners);
entry->listener = trackEntryCallback;
}
return (_TrackEntryListeners*)entry->rendererObject;
}
void SkeletonAnimation::setStartListener (spTrackEntry* entry, StartListener listener) {
getListeners(entry)->startListener = listener;
}
void SkeletonAnimation::setEndListener (spTrackEntry* entry, EndListener listener) {
getListeners(entry)->endListener = listener;
}
void SkeletonAnimation::setCompleteListener (spTrackEntry* entry, CompleteListener listener) {
getListeners(entry)->completeListener = listener;
}
void SkeletonAnimation::setEventListener (spTrackEntry* entry, spine::EventListener listener) {
getListeners(entry)->eventListener = listener;
}
}

View File

@ -37,8 +37,17 @@
namespace spine {
class SkeletonAnimation;
typedef std::function<void(spine::SkeletonAnimation* node, int trackIndex, spEventType type, spEvent* event, int loopCount)> AnimationStateListener;
typedef std::function<void(int trackIndex)> StartListener;
typedef std::function<void(int trackIndex)> EndListener;
typedef std::function<void(int trackIndex, int loopCount)> CompleteListener;
typedef std::function<void(int trackIndex, spEvent* event)> EventListener;
typedef struct _TrackEntryListeners {
StartListener startListener;
EndListener endListener;
CompleteListener completeListener;
EventListener eventListener;
} _TrackEntryListeners;
/** Draws an animated skeleton, providing an AnimationState for applying one or more animations and queuing animations to be
* played later. */
@ -61,25 +70,29 @@ public:
void setAnimationStateData (spAnimationStateData* stateData);
void setMix (const char* fromAnimation, const char* toAnimation, float duration);
template<class _Rx, class _Farg0, class _Arg0> void setAnimationListener (_Rx _Farg0::* const type, _Arg0&& target) {
using namespace std::placeholders;
this->listener = std::bind(type, target, _1, _2, _3, _4, _5);
}
spTrackEntry* setAnimation (int trackIndex, const char* name, bool loop);
spTrackEntry* addAnimation (int trackIndex, const char* name, bool loop, float delay = 0);
spTrackEntry* getCurrent (int trackIndex = 0);
void clearTracks ();
void clearTrack (int trackIndex = 0);
StartListener startListener;
EndListener endListener;
CompleteListener completeListener;
EventListener eventListener;
void setStartListener (spTrackEntry* entry, StartListener listener);
void setEndListener (spTrackEntry* entry, EndListener listener);
void setCompleteListener (spTrackEntry* entry, CompleteListener listener);
void setEventListener (spTrackEntry* entry, EventListener listener);
virtual void onAnimationStateEvent (int trackIndex, spEventType type, spEvent* event, int loopCount);
virtual void onTrackEntryEvent (int trackIndex, spEventType type, spEvent* event, int loopCount);
protected:
SkeletonAnimation ();
private:
typedef SkeletonRenderer super;
AnimationStateListener listener;
bool ownsAnimationStateData;
void initialize ();

View File

@ -55,8 +55,19 @@ char* _spUtil_readFile (const char* path, int* length) {
return bytes;
}
spTrackEntry* _spAnimationState_createTrackEntry (spAnimationState* self) {
return _spTrackEntry_create();
}
void _spAnimationState_disposeTrackEntry (spAnimationState* self, spTrackEntry* entry) {
if (entry->rendererObject) FREE(entry->rendererObject);
_spTrackEntry_dispose(entry);
}
/**/
namespace spine {
void spRegionAttachment_updateQuad (spRegionAttachment* self, spSlot* slot, V3F_C4B_T2F_Quad* quad, bool premultipliedAlpha) {
float vertices[8];
spRegionAttachment_computeWorldVertices(self, slot->skeleton->x, slot->skeleton->y, slot->bone, vertices);
@ -106,3 +117,5 @@ void spRegionAttachment_updateQuad (spRegionAttachment* self, spSlot* slot, V3F_
quad->br.texCoords.u = self->uvs[SP_VERTEX_X4];
quad->br.texCoords.v = self->uvs[SP_VERTEX_Y4];
}
}

View File

@ -36,6 +36,10 @@
#include <spine/SkeletonRenderer.h>
#include <spine/SkeletonAnimation.h>
namespace spine {
void spRegionAttachment_updateQuad (spRegionAttachment* self, spSlot* slot, cocos2d::V3F_C4B_T2F_Quad* quad, bool premultiplied = false);
}
#endif /* SPINE_COCOS2DX_H_ */