【Cocos2d-x】升級Spine 3.8.95


  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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM