cocos2dx加載骨骼動畫,獲取骨骼位置


2015/05/13

需求:

(1)希望在骨骼上綁定一個粒子特效

(2)獲取骨骼的位置

(3)獲取骨骼動畫的大小

(4)lua

1. cocostudio動畫編輯器

(1)綁定粒子特效(跟隨骨骼的移動移動)

        local boneNew  = ccs.Bone:create("particle")
            boneNew:addDisplay(particle, 0)
            --設置是否跟隨骨骼一起移動
            boneNew:setIgnoreMovementBoneData(true)
            --顯示骨骼上綁定的內容(這里是粒子特效,換裝也是同樣的接口)
            boneNew:changeDisplayWithIndex(0, true)
            --設置層級關系
            boneNew:setLocalZOrder(1)
            --Layer22為骨骼動畫中想綁定的骨骼,設置為該骨骼為粒子特效所在骨骼的父骨骼
            armature:addBone(boneNew, "Layer22")


* 其他的和骨骼的綁定也是通過此方式實現,感覺比較好用

(2)獲取骨骼位置

修改源代碼,從getWorldInfo中獲取數據,在Bone類中加一個接口

cocos2d::Vec2 Bone::getBonePosition() const
{
    BaseData *pData = getWorldInfo();
    return Vec2(pData->x, pData->y);
}

使用tolua++導出來之后如下(當然,自己也可以寫一個,就不用導出來這個步驟了):

int lua_cocos2dx_studio_Bone_getBonePosition(lua_State* tolua_S)
{
    int argc = 0;
    cocostudio::Bone* cobj = nullptr;
    bool ok  = true;

#if COCOS2D_DEBUG >= 1
    tolua_Error tolua_err;
#endif


#if COCOS2D_DEBUG >= 1
    if (!tolua_isusertype(tolua_S,1,"ccs.Bone",0,&tolua_err)) goto tolua_lerror;
#endif

    cobj = (cocostudio::Bone*)tolua_tousertype(tolua_S,1,0);

#if COCOS2D_DEBUG >= 1
    if (!cobj) 
    {
        tolua_error(tolua_S,"invalid 'cobj' in function 'lua_cocos2dx_studio_Bone_getBonePosition'", nullptr);
        return 0;
    }
#endif

    argc = lua_gettop(tolua_S)-1;
    if (argc == 0) 
    {
        if(!ok)
            return 0;
        cocos2d::Vec2 ret = cobj->getBonePosition();
        vec2_to_luaval(tolua_S, ret);
        return 1;
    }
    CCLOG("%s has wrong number of arguments: %d, was expecting %d \n", "getBonePosition",argc, 0);
    return 0;

#if COCOS2D_DEBUG >= 1
    tolua_lerror:
    tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_studio_Bone_getBonePosition'.",&tolua_err);
#endif

    return 0;
}


(3)獲取骨骼動畫大小

cocostudio導出來加載后的Armature本身就是一個node,直接getContentSize就可以了。但是spine的動畫就不行,getContentSize的結果為0,要使用別的接口,看下面。

 

2. spine動畫編輯器

(1)綁定粒子特效(跟隨骨骼的移動移動)

  沒有辦法做到,但是可以通過獲取骨骼的位置之后,添加一個特效到整個骨骼動畫的這個位置上,不過是不能跟隨骨骼一起移動的,一起移動看到有兩種方法,不過都沒有試過,就先記錄在這里,想用再來試一下

* update函數每幀獲取骨骼的位置,把粒子特效重現設置位置

 參考:[1]

* 重寫spine骨骼的的接口,每個骨骼和一個node對應

 參考:[2]

(2)獲取骨骼位置

  同studio(因為lua沒有導出函數接口),修改代碼,導出lua,在類中增加一個函數:

Vec2 Skeleton::getBonePosition(const char* boneName) const
{
    spBone *pBone = findBone(boneName);
    if (pBone)
        return cocos2d::Vec2(pBone->worldX, pBone->worldY);
    return cocos2d::Vec2(0, 0);
}

導出后的c++代碼如下,同樣的可以自己寫:

int lua_cocos2dx_spine_Skeleton_getBonePosition(lua_State* tolua_S)
{
    int argc = 0;
    spine::Skeleton* cobj = nullptr;
    bool ok  = true;

#if COCOS2D_DEBUG >= 1
    tolua_Error tolua_err;
#endif


#if COCOS2D_DEBUG >= 1
    if (!tolua_isusertype(tolua_S,1,"sp.Skeleton",0,&tolua_err)) goto tolua_lerror;
#endif

    cobj = (spine::Skeleton*)tolua_tousertype(tolua_S,1,0);

#if COCOS2D_DEBUG >= 1
    if (!cobj) 
    {
        tolua_error(tolua_S,"invalid 'cobj' in function 'lua_cocos2dx_spine_Skeleton_getBonePosition'", nullptr);
        return 0;
    }
#endif

    argc = lua_gettop(tolua_S)-1;
    if (argc == 1) 
    {
        const char* arg0;

        std::string arg0_tmp; ok &= luaval_to_std_string(tolua_S, 2, &arg0_tmp); arg0 = arg0_tmp.c_str();
        if(!ok)
            return 0;
        cocos2d::Vec2 ret = cobj->getBonePosition(arg0);
        vec2_to_luaval(tolua_S, ret);
        return 1;
    }
    CCLOG("%s has wrong number of arguments: %d, was expecting %d \n", "getBonePosition",argc, 1);
    return 0;

#if COCOS2D_DEBUG >= 1
    tolua_lerror:
    tolua_error(tolua_S,"#ferror in function 'lua_cocos2dx_spine_Skeleton_getBonePosition'.",&tolua_err);
#endif

    return 0;
}

 

(3)獲取骨骼動畫大小

  這個比較重要!!不能使用接口getContentSize,得出來的是0,但是Skeleton類提供了另外一個接口,也導出了lua接口:

Rect Skeleton::getBoundingBox () const {
    float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;
    float scaleX = getScaleX();
    float scaleY = getScaleY();
    float vertices[8];
    for (int i = 0; i < skeleton->slotCount; ++i) {
        spSlot* slot = skeleton->slots[i];
        if (!slot->attachment || slot->attachment->type != ATTACHMENT_REGION) continue;
        spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;
        spRegionAttachment_computeWorldVertices(attachment, slot->skeleton->x, slot->skeleton->y, slot->bone, vertices);
        minX = min(minX, vertices[VERTEX_X1] * scaleX);
        minY = min(minY, vertices[VERTEX_Y1] * scaleY);
        maxX = max(maxX, vertices[VERTEX_X1] * scaleX);
        maxY = max(maxY, vertices[VERTEX_Y1] * scaleY);
        minX = min(minX, vertices[VERTEX_X4] * scaleX);
        minY = min(minY, vertices[VERTEX_Y4] * scaleY);
        maxX = max(maxX, vertices[VERTEX_X4] * scaleX);
        maxY = max(maxY, vertices[VERTEX_Y4] * scaleY);
        minX = min(minX, vertices[VERTEX_X2] * scaleX);
        minY = min(minY, vertices[VERTEX_Y2] * scaleY);
        maxX = max(maxX, vertices[VERTEX_X2] * scaleX);
        maxY = max(maxY, vertices[VERTEX_Y2] * scaleY);
        minX = min(minX, vertices[VERTEX_X3] * scaleX);
        minY = min(minY, vertices[VERTEX_Y3] * scaleY);
        maxX = max(maxX, vertices[VERTEX_X3] * scaleX);
        maxY = max(maxY, vertices[VERTEX_Y3] * scaleY);
    }
    Vec2 position = getPosition();
    return Rect(position.x + minX, position.y + minY, maxX - minX, maxY - minY);
}

說明:
* 返回四個值:x, y, height, width

* 說明:(x, y)左下角的坐標,相對於rootbone的原點;height, width就是整個骨骼動畫的大小

* rootbone可以理解為cocos里面的錨點

* 【重要】在調用該接口之前,需要調用update接口初始化一遍數據,不然也是沒有數據的,參考[3] 

3. 總結

(1)獲取位置都是需要新加接口的

(2)雖然spine編輯器要好用,但是對於程序來說spine綁定特效還沒有cocostudio方便

(3)cocostudio的位置最好不要直接拿來用,例如轉換為全局坐標,最好直接addBone的方式

(4)spine的坐標也是直接骨骼動畫addChild

4. 參考

[1]http://www.cnblogs.com/mrblue/p/3414158.html

[2]http://blog.csdn.net/n5/article/details/21795265

[3]http://blog.csdn.net/wk3368/article/details/38903095

 


免責聲明!

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



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