diff --git a/cocos/spine/skeleton.ts b/cocos/spine/skeleton.ts index f8dad2c6f27..5c17e3f8557 100644 --- a/cocos/spine/skeleton.ts +++ b/cocos/spine/skeleton.ts @@ -1744,7 +1744,7 @@ export class Skeleton extends UIRenderer { * @param listener @en Listener for registering callback functions. @zh 监听器对象,可注册回调方法。 */ public setTrackStartListener (entry: spine.TrackEntry, listener: TrackListener): void { - TrackEntryListeners.getListeners(entry).start = listener; + TrackEntryListeners.getListeners(entry, this._instance).start = listener; } /** @@ -1754,7 +1754,7 @@ export class Skeleton extends UIRenderer { * @param listener @en Listener for registering callback functions. @zh 监听器对象,可注册回调方法。 */ public setTrackInterruptListener (entry: spine.TrackEntry, listener: TrackListener): void { - TrackEntryListeners.getListeners(entry).interrupt = listener; + TrackEntryListeners.getListeners(entry, this._instance).interrupt = listener; } /** @@ -1764,7 +1764,7 @@ export class Skeleton extends UIRenderer { * @param listener @en Listener for registering callback functions. @zh 监听器对象,可注册回调方法。 */ public setTrackEndListener (entry: spine.TrackEntry, listener: TrackListener): void { - TrackEntryListeners.getListeners(entry).end = listener; + TrackEntryListeners.getListeners(entry, this._instance).end = listener; } /** @@ -1774,7 +1774,7 @@ export class Skeleton extends UIRenderer { * @param listener @en Listener for registering callback functions. @zh 监听器对象,可注册回调方法。 */ public setTrackDisposeListener (entry: spine.TrackEntry, listener: TrackListener): void { - TrackEntryListeners.getListeners(entry).dispose = listener; + TrackEntryListeners.getListeners(entry, this._instance).dispose = listener; } /** @@ -1788,10 +1788,10 @@ export class Skeleton extends UIRenderer { const loopCount = Math.floor(trackEntry.trackTime / trackEntry.animationEnd); const listenerID = TrackEntryListeners.addListener(listener); listener(trackEntry, loopCount); - this._instance.setListener(listenerID, spine.EventType.event); - this._listener!.event = listener; + // this._instance.setListener(listenerID, spine.EventType.event); + // this._listener!.event = listener; }; - TrackEntryListeners.getListeners(entry).complete = onComplete; + TrackEntryListeners.getListeners(entry, this._instance).complete = onComplete; } /** @@ -1801,7 +1801,7 @@ export class Skeleton extends UIRenderer { * @param listener @en Listener for registering callback functions. @zh 监听器对象,可注册回调方法。 */ public setTrackEventListener (entry: spine.TrackEntry, listener: TrackListener|TrackListener2): void { - TrackEntryListeners.getListeners(entry).event = listener; + TrackEntryListeners.getListeners(entry, this._instance).event = listener; } /** diff --git a/cocos/spine/track-entry-listeners.ts b/cocos/spine/track-entry-listeners.ts index 777f8ca00bf..39f7beb1385 100644 --- a/cocos/spine/track-entry-listeners.ts +++ b/cocos/spine/track-entry-listeners.ts @@ -25,6 +25,7 @@ import spine from './lib/spine-core.js'; let _listener_ID = 0; +let _track_ID = 0; type TrackListener = (x: spine.TrackEntry) => void; type TrackListener2 = (x: spine.TrackEntry, ev: spine.Event) => void; @@ -38,9 +39,12 @@ export class TrackEntryListeners { complete?: ((entry: spine.TrackEntry) => void); event?: ((entry: spine.TrackEntry, event: spine.Event) => void); - static getListeners (entry: spine.TrackEntry): spine.AnimationStateListener { + static getListeners (entry: spine.TrackEntry, instance: spine.SkeletonInstance): spine.AnimationStateListener { if (!entry.listener) { entry.listener = new TrackEntryListeners() as any; + const id = ++_track_ID; + instance.setTrackListener(id, entry); + TrackEntryListeners._trackSet.set(id, entry); } return entry.listener; } @@ -54,6 +58,45 @@ export class TrackEntryListeners { } } + static emitTrackListener (id: number, entry: spine.TrackEntry, event: spine.Event, eventType: spine.EventType): void { + const curTrack = this._trackSet.get(id); + if (!curTrack) return; + // eslint-disable-next-line default-case + switch (eventType as number) { + case spine.EventType.start: + if (curTrack.listener.start) { + curTrack.listener.start(entry); + } + break; + case spine.EventType.interrupt: + if (curTrack.listener.interrupt) { + curTrack.listener.interrupt(entry); + } + break; + case spine.EventType.end: + if (curTrack.listener.end) { + curTrack.listener.end(entry); + } + break; + case spine.EventType.dispose: + if (curTrack.listener.dispose) { + curTrack.listener.dispose(entry); + } + this._trackSet.delete(id); + break; + case spine.EventType.complete: + if (curTrack.listener.complete) { + curTrack.listener.complete(entry); + } + break; + case spine.EventType.event: + if (curTrack.listener.event) { + curTrack.listener.event(entry, event); + } + break; + } + } + static addListener (listener: CommonTrackEntryListener): number { const id = ++_listener_ID; TrackEntryListeners._listenerSet.set(id, listener); @@ -61,6 +104,7 @@ export class TrackEntryListeners { } private static _listenerSet = new Map(); + private static _trackSet = new Map(); } globalThis.TrackEntryListeners = TrackEntryListeners; diff --git a/native/cocos/editor-support/spine-wasm/library_spine.js b/native/cocos/editor-support/spine-wasm/library_spine.js index a3f74d94bab..3e0d2829b37 100644 --- a/native/cocos/editor-support/spine-wasm/library_spine.js +++ b/native/cocos/editor-support/spine-wasm/library_spine.js @@ -5,5 +5,14 @@ mergeInto(LibraryManager.library, { var trackEntry = wasmUtil.getCurrentTrackEntry(); var event = wasmUtil.getCurrentEvent(); globalThis.TrackEntryListeners.emitListener(listenerID, trackEntry, event); + }, + + spineTrackListenerCallback: function() { + var wasmUtil = Module['SpineWasmUtil']; + var listenerID = wasmUtil.getCurrentListenerID(); + var eventType = wasmUtil.getCurrentEventType(); + var trackEntry = wasmUtil.getCurrentTrackEntry(); + var event = wasmUtil.getCurrentEvent(); + globalThis.TrackEntryListeners.emitTrackListener(listenerID, trackEntry, event, eventType.value); } }); diff --git a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp index c9a92049e9b..fe3f34d9068 100644 --- a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp +++ b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.cpp @@ -11,14 +11,24 @@ SlotMesh globalMesh(nullptr, nullptr, 0, 0); extern "C" { extern void spineListenerCallBackFromJS(); +extern void spineTrackListenerCallback(); } using namespace spine; static void animationCallback(AnimationState *state, EventType type, TrackEntry *entry, Event *event) { - SpineSkeletonInstance *instance = (SpineSkeletonInstance *)state->getRendererObject(); + SpineSkeletonInstance *instance = (static_cast(state->getRendererObject())); instance->onAnimationStateEvent(entry, type, event); } +void trackEntryCallback(AnimationState *state, EventType type, TrackEntry *entry, Event *event) { + (static_cast(state->getRendererObject()))->onTrackEntryEvent(entry, type, event); + if (type == EventType_Dispose) { + if (entry->getRendererObject()) { + entry->setRendererObject(nullptr); + } + } +} + SpineSkeletonInstance::SpineSkeletonInstance() { _model = new SpineModel(); SpineSkeletonSystem::addSpineInstance(this); @@ -420,6 +430,14 @@ void SpineSkeletonInstance::setListener(uint32_t listenerID, uint32_t type) { } } +void SpineSkeletonInstance::setTrackListener(uint32_t trackId, TrackEntry *entry) { + if (!entry->getRendererObject()) { + _trackListenerID = trackId; + entry->setRendererObject(this); + entry->setListener(trackEntryCallback); + } +} + void SpineSkeletonInstance::setUseTint(bool useTint) { _userData.useTint = useTint; } @@ -428,6 +446,15 @@ void SpineSkeletonInstance::setDebugMode(bool debug) { _userData.debugMode = debug; } +void SpineSkeletonInstance::onTrackEntryEvent(TrackEntry *entry, EventType type, Event *event) { + if (!entry->getRendererObject()) return; + SpineWasmUtil::s_listenerID = _trackListenerID; + SpineWasmUtil::s_currentType = type; + SpineWasmUtil::s_currentEntry = entry; + SpineWasmUtil::s_currentEvent = event; + spineTrackListenerCallback(); +} + void SpineSkeletonInstance::onAnimationStateEvent(TrackEntry *entry, EventType type, Event *event) { SpineWasmUtil::s_currentType = type; SpineWasmUtil::s_currentEntry = entry; diff --git a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.h b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.h index 7b83ec6cb6e..0911638004c 100644 --- a/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.h +++ b/native/cocos/editor-support/spine-wasm/spine-skeleton-instance.h @@ -9,12 +9,6 @@ #include "spine-model.h" using namespace spine; -typedef std::function StartListener; -typedef std::function InterruptListener; -typedef std::function EndListener; -typedef std::function DisposeListener; -typedef std::function CompleteListener; -typedef std::function EventListener; enum DEBUG_SHAPE_TYPE { DEBUG_REGION = 0, @@ -58,7 +52,9 @@ class SpineSkeletonInstance { AnimationState *getAnimationState(); void setMix(const std::string &from, const std::string &to, float duration); void setListener(uint32_t listenerID, uint32_t type); + void setTrackListener(uint32_t trackId, TrackEntry *entry); void onAnimationStateEvent(TrackEntry *entry, EventType type, Event *event); + void onTrackEntryEvent(TrackEntry *entry, EventType type, Event *event); std::vector &getDebugShapes(); void resizeSlotRegion(const std::string &slotName, uint32_t width, uint32_t height, bool createNew = false); void setSlotTexture(const std::string &slotName, uint32_t index); @@ -83,6 +79,7 @@ class SpineSkeletonInstance { uint32_t _disposeListenerID = 0; uint32_t _completeListenerID = 0; uint32_t _eventListenerID = 0; + uint32_t _trackListenerID = 0; UserData _userData; std::vector _debugShapes{}; std::map slotTextureSet{}; diff --git a/native/cocos/editor-support/spine-wasm/spine-type-export.cpp b/native/cocos/editor-support/spine-wasm/spine-type-export.cpp index d6ecbbd8df9..20515d014c1 100644 --- a/native/cocos/editor-support/spine-wasm/spine-type-export.cpp +++ b/native/cocos/editor-support/spine-wasm/spine-type-export.cpp @@ -1604,6 +1604,7 @@ EMSCRIPTEN_BINDINGS(spine) { .function("getAnimationState", &SpineSkeletonInstance::getAnimationState, allow_raw_pointer()) .function("setMix", &SpineSkeletonInstance::setMix) .function("setListener", &SpineSkeletonInstance::setListener) + .function("setTrackListener", &SpineSkeletonInstance::setTrackListener, allow_raw_pointer()) .function("setDebugMode", &SpineSkeletonInstance::setDebugMode) .function("getDebugShapes", &SpineSkeletonInstance::getDebugShapes) .function("resizeSlotRegion", &SpineSkeletonInstance::resizeSlotRegion)