【Cocos2d-x】升级Spine 3.8.95

发布时间 2023-07-14 19:23:54作者: 梦幻轮回

转载,原文连接:https://www.cnblogs.com/tomaszheng/p/14807373.html#!comments

  1. Spine官方下载3.8.95版本的spine-cpp、spine-cocos2dx;
  2. 删除cocos2d-x/cocos/editor-support/spine中所有的旧版本的spine代码;
  3. 把spine-cpp、spine-cocos2dx所有源文件全部拷贝到cocos2d-x/cocos/editor-support/spine目录;

一、Lua-binding

1、使用如下配置完全覆盖掉之前的cocos2dx_spine.ini

[cocos2dx_spine]
# the prefix to be added to the generated functions. You might or might not use this in your own
# templates
prefix = cocos2dx_spine

# create a target namespace (in javascript, this would create some code like the equiv. to `ns = ns || {}`)
# all classes will be embedded in that namespace
target_namespace = sp

android_headers = -I%(androidndkdir)s/platforms/android-14/arch-arm/usr/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/%(gnu_libstdc_version)s/libs/armeabi-v7a/include -I%(androidndkdir)s/sources/cxx-stl/gnu-libstdc++/%(gnu_libstdc_version)s/include
android_flags = -D_SIZE_T_DEFINED_ 

clang_headers = -I%(clangllvmdir)s/%(clang_lib_version)s/clang/%(clang_version)s/include
clang_flags = -nostdinc -x c++ -std=c++11 -U __SSE__

cocos_headers = -I%(cocosdir)s/cocos -I%(cocosdir)s/cocos/editor-support -I%(cocosdir)s/cocos/platform/android -I%(cocosdir)s/external

cocos_flags = -DANDROID

cxxgenerator_headers = 

# extra arguments for clang
extra_arguments = %(android_headers)s %(clang_headers)s %(cxxgenerator_headers)s %(cocos_headers)s %(android_flags)s %(clang_flags)s %(cocos_flags)s %(extra_flags)s 

# what headers to parse
headers = %(cocosdir)s/cocos/editor-support/spine/spine-cocos2dx.h

classes = SkeletonRenderer SkeletonAnimation VertexEffectDelegate  Animation TrackEntry AnimationState AnimationStateData Attachment AttachmentTimeline BoundingBoxAttachment Bone BoneData ClippingAttachment Color ColorTimeline CurveTimeline DeformTimeline DrawOrderTimeline Event EventData EventTimeline IkConstraint IkConstraintData IkConstraintTimeline MeshAttachment Polygon PathAttachment PathConstraint PathConstraintData PathConstraintMixTimeline PathConstraintPositionTimeline PathConstraintSpacingTimeline PointAttachment RegionAttachment RotateTimeline ScaleTimeline ShearTimeline Skeleton Slot Skin SkeletonBounds SkeletonData SlotData Timeline TransformConstraint TransformConstraintData TransformConstraintTimeline TranslateTimeline TwoColorTimeline VertexAttachment VertexEffect JitterVertexEffect SwirlVertexEffect ConstraintData

classes_need_extend = SkeletonAnimation

skip = SkeletonRenderer::[create createWithData initWithData createWithSkeleton createWithFile getRenderOrder],
        SkeletonAnimation::[create createWithData createWithJsonFile createWithBinaryFile onTrackEntryEvent onAnimationStateEvent setStartListener setTrackStartListener setEndListener setTrackEndListener setInterruptListener setTrackInterruptListener setEventListener setTrackEventListener setTrackDisposeListener setDisposeListener setCompleteListener setTrackCompleteListener setPostUpdateWorldTransformsListener setPreUpdateWorldTransformsListener],
        Animation::[apply],
        TrackEntry::[setListener],
        AnimationState::[apply setListener],
        Attachment::[getRTTI],
        AttachmentTimeline::[apply getRTTI],
        BoundingBoxAttachment::[getRTTI],
        Bone::[worldToLocal localToWorld getRTTI],
        ClippingAttachment::[getRTTI],
        Color::[set add],
        ColorTimeline::[apply getRTTI],
        CurveTimeline::[apply getRTTI],
        DeformTimeline::[apply setFrame getVertices getRTTI],
        DrawOrderTimeline::[apply setFrame getDrawOrders getRTTI],
        EventTimeline::[apply getRTTI],
        IkConstraint::[apply getRTTI],
        IkConstraintTimeline::[apply getRTTI],
        MeshAttachment::[getRTTI],
        PathAttachment::[getRTTI],
        PathConstraint::[getRTTI],
        PathConstraintMixTimeline::[apply getRTTI],
        PathConstraintPositionTimeline::[apply getRTTI],
        PathConstraintSpacingTimeline::[apply getRTTI],
        PointAttachment::[computeWorldPosition getRTTI computeWorldRotation],
        RegionAttachment::[computeWorldVertices getRTTI],
        RotateTimeline::[apply getRTTI],
        ScaleTimeline::[apply getRTTI],
        ShearTimeline::[apply getRTTI],
        Skeleton::[getBounds getUpdateCacheList],
        Skin::[getAttachments findNamesForSlot findAttachmentsForSlot],
        SkeletonBounds::[update aabbIntersectsSkeleton],
        Timeline::[apply getRTTI],
        TransformConstraint::[getRTTI],
        TransformConstraintTimeline::[apply getRTTI],
        TranslateTimeline::[apply getRTTI],
        TwoColorTimeline::[apply getRTTI],
        VertexEffect::[begin transform end],
        JitterVertexEffect::[begin transform end],
        SwirlVertexEffect::[begin transform end],
        VertexAttachment::[computeWorldVertices getBones getRTTI]

field = Color::[r g b a]

remove_prefix = 

classes_have_no_parents =

base_classes_to_skip = Ref IMiddleware SpineObject HasRendererObject Updatable Constraint

abstract_classes = Animation TrackEntry AnimationState AnimationStateData Attachment AttachmentTimeline BoundingBoxAttachment Bone BoneData ClippingAttachment Color ColorTimeline CurveTimeline DeformTimeline DrawOrderTimeline Event EventData EventTimeline IkConstraint IkConstraintData IkConstraintTimeline MeshAttachment Polygon PathAttachment PathConstraint PathConstraintData PathConstraintMixTimeline PathConstraintPositionTimeline PathConstraintSpacingTimeline PointAttachment RegionAttachment RotateTimeline ScaleTimeline ShearTimeline Skeleton Slot Skin SlotData SkeletonBounds SkeletonData Timeline TransformConstraint TransformConstraintData TransformConstraintTimeline TranslateTimeline TwoColorTimeline VertexAttachment VertexEffect JitterVertexEffect SwirlVertexEffect ConstraintData

rename_functions =  SkeletonAnimation::[createWithFile=create],
                    SkeletonRenderer::[createWithFile=create]

rename_classes = SkeletonRenderer::Skeleton

# Determining whether to use script object(js object) to control the lifecycle of native(cpp) object or the other way around. Supported values are 'yes' or 'no'.
script_control_cpp = no

2、修改conversions.yaml

由于使用了spine-cpp版本,spine加了很多基础数据类型,在自动绑定lua时,需要定义类型转换代码

conversions:

    ...
    
    to_native:
        
        ...
        
        "String": "ok &= luaval_to_spine_string(tolua_S, ${arg_idx},&${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
        size_t: "ok &= luaval_to_size_t(tolua_S, ${arg_idx}, &${out_value}, \"${lua_namespaced_class_name}:${func_name}\")"
    
        object: ...
    
    from_native:
        
        ...
        
        # "@Vector<.*>": "ccvector_to_luaval(tolua_S, ${in_value})"
        "@Vector<(?!spine::).*>": "ccvector_to_luaval(tolua_S, ${in_value})"
        
        ...
        
        "String": "lua_pushlstring(tolua_S,${in_value}.buffer(),${in_value}.length())"
        "Color": "spine_color_to_luaval(tolua_S, ${in_value})"
        "@(?:\\bBoneData\\b|\\bSkeleton\\b|\\bColor\\b|\\bEventData\\b|\\bIkConstraintData\\b|\\bPathConstraintData\\b|\\bTransformConstraintData\\b|\\bBone\\b|\\bSlotData\\b)+(?!\\*)+":  "object_to_luaval<${ntype.replace('const ', '').replace('&', '')}>(tolua_S, \"${scriptname}\", (${ntype.replace('const ', '').replace('&', '')}*)&${in_value})"
        "@Vector<spine::((?!String).)*>": "spine_vector_ptr_to_luaval(tolua_S, ${in_value})"
        "@Vector<int.*>": "spine_vector_int_to_luaval(tolua_S, ${in_value})"
        "@Vector<unsigned int.*>": "spine_vector_uint_to_luaval(tolua_S, ${in_value})"
        "@Vector<short.*>": "spine_vector_short_to_luaval(tolua_S, ${in_value})"
        "@Vector<unsigned short.*>": "spine_vector_ushort_to_luaval(tolua_S, ${in_value})"
        "@Vector<float.*>": "spine_vector_float_to_luaval(tolua_S, ${in_value})"
        "@Vector<spine::String.*>": "spine_vector_spine_string_to_luaval(tolua_S, ${in_value})"
        size_t: "tolua_pushnumber(tolua_S,(lua_Number)${in_value})"
        
        object: ...

3、定义类型转换方法

在cocos2d-x/cocos/scripting/lua-bindings/manual/下增加SpineConversions.h、SpineConversions.cpp

// SpineConversions.h
#pragma once

extern "C" {
#include "lua.h"
#include "tolua++.h"
}
#include "scripting/lua-bindings/manual/tolua_fix.h"
#include "scripting/lua-bindings/manual/Lua-BindingsExport.h"
#include "editor-support/spine/Color.h"
#include "editor-support/spine/SpineString.h"
#include "editor-support/spine/Vector.h"

extern bool luaval_to_size_t(lua_State* L, int lo, size_t* outValue, const char* funcName = "");

extern bool luaval_to_spine_color(lua_State* L, int lo, spine::Color* outValue, const char* funcName);

extern bool luaval_to_spine_string(lua_State* L, int lo, spine::String* outValue, const char* funcName);

extern void spine_color_to_luaval(lua_State* L, const spine::Color& cc);

extern void spine_vector_int_to_luaval(lua_State* L, spine::Vector<int>& inValue);

extern void spine_vector_uint_to_luaval(lua_State* L, spine::Vector<unsigned int>& inValue);

extern void spine_vector_short_to_luaval(lua_State* L, spine::Vector<short>& inValue);

extern void spine_vector_ushort_to_luaval(lua_State* L, spine::Vector<unsigned short>& inValue);

extern void spine_vector_float_to_luaval(lua_State* L, spine::Vector<float>& inValue);

extern void spine_vector_spine_string_to_luaval(lua_State* L, spine::Vector<spine::String>& inValue);

template <class T>
void spine_vector_to_luaval(lua_State* L, const spine::Vector<T>& inValue)
{
    lua_newtable(L);

    if (nullptr == L)
        return;

    int indexTable = 1;
    spine::Vector<T> tmpv = inValue;
    for (size_t i = 0, count = (size_t)tmpv.size(); i < count; i++)
    {
        std::string typeName = typeid(tmpv[i]).name();
        auto iter = g_luaType.find(typeName);
        if (g_luaType.end() != iter)
        {
            lua_pushnumber(L, (lua_Number)indexTable);
            tolua_pushusertype(L, (void*)tmpv[i], iter->second.c_str());
            lua_rawset(L, -3);
            ++indexTable;
        }
    }
}

template <class T>
void spine_vector_ptr_to_luaval(lua_State* L, const spine::Vector<T*>& inValue)
{
    lua_newtable(L);

    if (nullptr == L)
        return;

    int indexTable = 1;
    spine::Vector<T*> tmpv = inValue;
    for (size_t i = 0, count = (size_t)tmpv.size(); i < count; i++)
    {
        std::string typeName = typeid(*tmpv[i]).name();
        auto iter = g_luaType.find(typeName);
        if (g_luaType.end() != iter)
        {
            lua_pushnumber(L, (lua_Number)indexTable);
            tolua_pushusertype(L, (void*)tmpv[i], iter->second.c_str());
            lua_rawset(L, -3);
            ++indexTable;
        }
    }
}
// SpineConversions.cpp
#include "scripting/lua-bindings/manual/LuaBasicConversions.h"
#include "scripting/lua-bindings/manual/SpineConversions.h"
#include "scripting/lua-bindings/manual/tolua_fix.h"

bool luaval_to_size_t(lua_State* L, int lo, size_t* outValue, const char* funcName)
{
    return luaval_to_uint32(L, lo, reinterpret_cast<unsigned int*>(outValue), funcName);
}

bool luaval_to_spine_color(lua_State* L, int lo, spine::Color* outValue, const char* funcName)
{
    if (NULL == L || NULL == outValue)
        return false;

    bool ok = true;

    tolua_Error tolua_err;
    if (!tolua_istable(L, lo, 0, &tolua_err))
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L, "#ferror:", &tolua_err, funcName);
#endif
        ok = false;
    }

    if (ok)
    {
        lua_pushstring(L, "r");
        lua_gettable(L, lo);
        outValue->r = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
        lua_pop(L, 1);

        lua_pushstring(L, "g");
        lua_gettable(L, lo);
        outValue->g = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
        lua_pop(L, 1);

        lua_pushstring(L, "b");
        lua_gettable(L, lo);
        outValue->b = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
        lua_pop(L, 1);

        lua_pushstring(L, "a");
        lua_gettable(L, lo);
        outValue->b = lua_isnil(L, -1) ? 0 : lua_tonumber(L, -1);
        lua_pop(L, 1);
    }

    return ok;
}

bool luaval_to_spine_string(lua_State* L, int lo, spine::String* outValue, const char* funcName)
{
    if (NULL == L || NULL == outValue)
        return false;

    bool ok = true;

    tolua_Error tolua_err;
    if (!tolua_iscppstring(L, lo, 0, &tolua_err))
    {
#if COCOS2D_DEBUG >=1
        luaval_to_native_err(L, "#ferror:", &tolua_err, funcName);
#endif
        ok = false;
    }

    if (ok)
    {
        size_t size;
        auto rawString = lua_tolstring(L, lo, &size);
        *outValue = spine::String(rawString);
    }

    return ok;
}

void spine_color_to_luaval(lua_State* L, const spine::Color& cc)
{
    if (NULL == L)
        return;
    lua_newtable(L);                                    /* L: table */
    lua_pushstring(L, "r");                             /* L: table key */
    lua_pushnumber(L, (lua_Number)cc.r);               /* L: table key value*/
    lua_rawset(L, -3);                                  /* table[key] = value, L: table */
    lua_pushstring(L, "g");                             /* L: table key */
    lua_pushnumber(L, (lua_Number)cc.g);               /* L: table key value*/
    lua_rawset(L, -3);                                  /* table[key] = value, L: table */
    lua_pushstring(L, "b");                             /* L: table key */
    lua_pushnumber(L, (lua_Number)cc.b);               /* L: table key value*/
    lua_rawset(L, -3);                                  /* table[key] = value, L: table */
    lua_pushstring(L, "a");                             /* L: table key */
    lua_pushnumber(L, (lua_Number)cc.b);               /* L: table key value*/
    lua_rawset(L, -3);                                  /* table[key] = value, L: table */
}

void spine_vector_int_to_luaval(lua_State* L, spine::Vector<int>& inValue)
{
    if (nullptr == L)
        return;

    lua_newtable(L);

    spine::Vector<int> tmpv = inValue;
    for (size_t i = 0, count = (size_t)tmpv.size(); i < count; i++)
    {
        lua_pushnumber(L, (lua_Number)(i + 1));
        lua_pushnumber(L, (lua_Number)tmpv[i]);
        lua_rawset(L, -3);
    }
}

void spine_vector_uint_to_luaval(lua_State* L, spine::Vector<unsigned int>& inValue)
{
    if (nullptr == L)
        return;

    lua_newtable(L);

    spine::Vector<unsigned int> tmpv = inValue;
    for (size_t i = 0, count = (size_t)tmpv.size(); i < count; i++)
    {
        lua_pushnumber(L, (lua_Number)(i + 1));
        lua_pushnumber(L, (lua_Number)tmpv[i]);
        lua_rawset(L, -3);
    }
}

void spine_vector_short_to_luaval(lua_State* L, spine::Vector<short>& inValue)
{
    if (nullptr == L)
        return;

    lua_newtable(L);

    spine::Vector<short> tmpv = inValue;
    for (size_t i = 0, count = (size_t)tmpv.size(); i < count; i++)
    {
        lua_pushnumber(L, (lua_Number)(i + 1));
        lua_pushnumber(L, (lua_Number)tmpv[i]);
        lua_rawset(L, -3);
    }
}

void spine_vector_ushort_to_luaval(lua_State* L, spine::Vector<unsigned short>& inValue)
{
    if (nullptr == L)
        return;

    lua_newtable(L);

    spine::Vector<unsigned short> tmpv = inValue;
    for (size_t i = 0, count = (size_t)tmpv.size(); i < count; i++)
    {
        lua_pushnumber(L, (lua_Number)(i + 1));
        lua_pushnumber(L, (lua_Number)tmpv[i]);
        lua_rawset(L, -3);
    }
}

void spine_vector_float_to_luaval(lua_State* L, spine::Vector<float>& inValue)
{
    if (nullptr == L)
        return;

    lua_newtable(L);

    spine::Vector<float> tmpv = inValue;
    for (size_t i = 0, count = (size_t)tmpv.size(); i < count; i++)
    {
        lua_pushnumber(L, (lua_Number)(i + 1));
        lua_pushnumber(L, (lua_Number)tmpv[i]);
        lua_rawset(L, -3);
    }
}

void spine_vector_spine_string_to_luaval(lua_State* L, spine::Vector<spine::String>& inValue)
{
    if (nullptr == L)
        return;

    lua_newtable(L);

    spine::Vector<spine::String> tmpv = inValue;
    for (size_t i = 0, count = (size_t)tmpv.size(); i < count; i++)
    {
        lua_pushnumber(L, (lua_Number)(i + 1));
        lua_pushstring(L, tmpv[i].buffer());
        lua_rawset(L, -3);
    }
}

4、自动导入SpineConversions.h

修改cocos2d-x/tools/bindings-generator/targets/lua/templates/layout_head.c,自动导入SpineConversion.h

...

\#include "scripting/lua-bindings/manual/tolua_fix.h"
\#include "scripting/lua-bindings/manual/LuaBasicConversions.h"
\#include "scripting/lua-bindings/manual/SpineConversions.h"

...

5、适配Skeleton的创建接口

由于Spine 3.8.95增加了二进制文件格式,因此Cocos2dx的适配层LuaSkeletonAnimation需要做如下修改:

// scripting/lua-bindings/manual/LuaSkeletonAnimation.cpp
LuaSkeletonAnimation* LuaSkeletonAnimation::createWithFile(const std::string& skeletonFilepath, Atlas* atlas, float scale) {
    LuaSkeletonAnimation* node = new LuaSkeletonAnimation();
    if (FileUtils::getInstance()->getFileExtension(skeletonFilepath) == ".json") {
        node->initWithJsonFile(skeletonFilepath, atlas, scale);
    }
    else {
        node->initWithBinaryFile(skeletonFilepath, atlas, scale);
    }
    node->autorelease();
    return node;
}

LuaSkeletonAnimation* LuaSkeletonAnimation::createWithFile(const std::string& skeletonFilepath, const std::string& atlasFile, float scale) {
    LuaSkeletonAnimation* node = new LuaSkeletonAnimation();
    if (FileUtils::getInstance()->getFileExtension(skeletonFilepath) == ".json") {
        node->initWithJsonFile(skeletonFilepath, atlasFile, scale);
    }
    else {
        node->initWithBinaryFile(skeletonFilepath, atlasFile, scale);
    }
    node->autorelease();
    return node;
}

二、Win32

用VS2017打开项目工程,移除所有的旧的Spine代码引用,再把新的Spine代码引入进来,重新编译。

三、IOS

类似Win32,唯一区别是把VS2017换成Xcode

四、Android平台

Android需要改动到Android.mk(如果使用NDK进行编译)或CMakeList.txt(如果使用CMake),以下以NDK编译示例

1,Spine库的Android.mk

Spine库的Android.mk在目录cocos2d-x/cocos/editor-support/spine/Android.mk,使用以下代码覆盖掉之前的。

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)

LOCAL_MODULE := spine_static

LOCAL_MODULE_FILENAME := libspine

LOCAL_ARM_MODE := arm

LOCAL_SRC_FILES := \
Animation.cpp \
AnimationState.cpp \
AnimationStateData.cpp \
Atlas.cpp \
AtlasAttachmentLoader.cpp \
Attachment.cpp \
AttachmentLoader.cpp \
AttachmentTimeline.cpp \
AttachmentVertices.cpp \
Bone.cpp \
BoneData.cpp \
BoundingBoxAttachment.cpp \
ClippingAttachment.cpp \
ColorTimeline.cpp \
ConstraintData.cpp \
CurveTimeline.cpp \
DeformTimeline.cpp \
DrawOrderTimeline.cpp \
Event.cpp \
EventData.cpp \
EventTimeline.cpp \
Extension.cpp \
IkConstraint.cpp \
IkConstraintData.cpp \
IkConstraintTimeline.cpp \
Json.cpp \
LinkedMesh.cpp \
MathUtil.cpp \
MeshAttachment.cpp \
PathAttachment.cpp \
PathConstraint.cpp \
PathConstraintData.cpp \
PathConstraintMixTimeline.cpp \
PathConstraintPositionTimeline.cpp \
PathConstraintSpacingTimeline.cpp \
PointAttachment.cpp \
RegionAttachment.cpp \
RotateTimeline.cpp \
RTTI.cpp \
ScaleTimeline.cpp \
ShearTimeline.cpp \
Skeleton.cpp \
SkeletonAnimation.cpp \
SkeletonBatch.cpp \
SkeletonBinary.cpp \
SkeletonBounds.cpp \
SkeletonClipping.cpp \
SkeletonData.cpp \
SkeletonJson.cpp \
SkeletonRenderer.cpp \
SkeletonTwoColorBatch.cpp \
Skin.cpp \
Slot.cpp \
SlotData.cpp \
spine-cocos2dx.cpp \
SpineObject.cpp \
TextureLoader.cpp \
Timeline.cpp \
TransformConstraint.cpp \
TransformConstraintData.cpp \
TransformConstraintTimeline.cpp \
TranslateTimeline.cpp \
Triangulator.cpp \
TwoColorTimeline.cpp \
Updatable.cpp \
VertexAttachment.cpp \
VertexEffect.cpp

LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/..

LOCAL_C_INCLUDES := $(LOCAL_PATH)/..

LOCAL_STATIC_LIBRARIES := cocos2dx_internal_static

include $(BUILD_STATIC_LIBRARY)

2,luacocos2d库的Android.mk

把SpineConversions放入luacocos2d库中

...

LOCAL_SRC_FILES += ../manual/spine/lua_cocos2dx_spine_manual.cpp \
                   ../manual/spine/LuaSkeletonAnimation.cpp \
                   ../manual/SpineConversions.cpp \
                   ../auto/lua_cocos2dx_spine_auto.cpp

...

五、实现挂点

实现Spine挂点,有两种方案:

  1. Creator的实现方案:根据骨骼层次生成节点树,在Spine每次render时更新节点树的世界矩阵;
  2. 不创建节点树,在Spine每次transform后,同步更新需要挂载的节点;

对于方案一,在Cocos2d-x中较难实现,主要是在矩阵转换上比较麻烦,而且对引擎侵入性较大,对于此方案,目前没有找到比较好的解决方法。

采用方案二简单实现挂点

1,定义PostUpdateWorldTransforms事件

// cocos2d-x/cocos/editor-support/spine/AnimationState.h
enum EventType {
    ...
    
    EventType_PostUpdate,
};
// cocos2d-x/cocos/scripting/lua-bindings/manual/cocos2d/LuaScriptHandlerMgr.h
enum class HandlerType: int
{
    ...
    
    EVENT_SPINE_ANIMATION_POST_UPDATE
}

// cocos/spine/SpineConstants.lua
sp.EventType =
{
    ...
    
    ANIMATION_POST_UPDATE = 6,
}

2,手动绑定监听

//  cocos2d-x/cocos/scripting/lua-bindings/manual/spine/lua_cocos2dx_spine_manual.cpp
int tolua_Cocos2d_CCSkeletonAnimation_registerSpineEventHandler00(lua_State* tolua_S)
{
    ...
    
    switch (eventType) {
        ...
        
        case EventType::EventType_PostUpdate: {
            self->setPostUpdateWorldTransformsListener([=](SkeletonAnimation* skeletonAnimation) {
                handleSpineUpdateEvent(handler, skeletonAnimation);
            });
            ScriptHandlerMgr::getInstance()->addObjectHandler((void*)self, handler, ScriptHandlerMgr::HandlerType::EVENT_SPINE_ANIMATION_POST_UPDATE);
            break;
        }
    }
}

int tolua_Cocos2d_CCSkeletonAnimation_unregisterSpineEventHandler00(lua_State* tolua_S)
{
    ...
    
    switch (eventType) {
        ...
        
        case EventType::EventType_PostUpdate: {
            handlerType = ScriptHandlerMgr::HandlerType::EVENT_SPINE_ANIMATION_POST_UPDATE;
            break;
        }
    }
}

增加回调处理方法

static int handleSpineUpdateEvent(int handler, spine::SkeletonAnimation* skeletonAnimation)
{
    LuaStack* stack = LuaEngine::getInstance()->getLuaStack();

    stack->pushObject(skeletonAnimation, "sp.SkeletonAnimation");

    stack->executeFunctionByHandler(handler, 1);
    stack->clean();

    return 0;
}

3,lua中调用

self.skeleton:registerSpineEventHandler(function(event)
    updateAttachedNode(self.skeleton, self.attachedBoneName, self.attachedNode)
end, sp.EventType.ANIMATION_POST_UPDATE)

function updateAttachedNode(skeleton, boneName, attachedName)
    local bone = skeleton:findBone(boneName)
    attachedNode:setPosition(cc.p(bone:getWorldX(), bone:getWorldY()))
    attachedNode:setRotation(-bone:getWorldRotationX())
    attachedNode:setScaleX(bone:getWorldScaleX())
    attachedNode:setScaleY(bone:getWorldScaleY())
    attachedNode:setVisible(bone:isActive())
end