cocos2d-x中spine骨骼动画的应用

来源:互联网 发布:风力预报软件 编辑:程序博客网 时间:2024/04/30 03:34

之前自己搞的一个打飞机项目中使用了spine骨骼动画,现在记录下一些遇到的问题和经验。

创建spine骨骼动画

SkeletonAnimation::createWithFile("a.json", "a.atlas", 0.7f);

a.json 和 a.atlas是spine导出的两个文件,0.7f是对动画资源的压缩比例。

setTimeScale(2.0f);//设置播放速度

创建出来以后,你如果不播放任何动画的话,就是在spine编辑器中
setup模式下的静态图片。

播放spine动画

setAnimation(0, "Move_Normal", true);

0代表的是trackIndex,就是轨道id,我们肯定知道录音软件中的音轨一说,多条音轨混合同时播放,就可以达到混音效果。这个也是一个道理。
第二个参数就是动画名字,没什么可说的。
第三个参数代表是否循环播放。true代表循环,false代表只播放1次。如果要控制循环的次数,则需要在动画的监听事件中去处理。
setAnimation会让这条动画轨道重新开始,会把之前轨道上的内容全部清空。如果我们希望在原有轨道的后面添加内容,则可以用

addAnimation(0, "Move_Normal", true);

如果需要使动画之间的衔接变的顺畅,可以使用

setMix("Stand_Normal","Start_Normal",0.3f);

前两个参数就是需要融合的动画,最后面一个参数越大就越顺畅?这个需要测试

碰撞问题

spine编辑器可以编辑特别的碰撞区域,那么我们如何获取到这个碰撞区域呢?
SkeletonAnimation这个类是继承自Node的,因此也有getBoundingBox这个方法,但是是重写过的

Rect SkeletonRenderer::getBoundingBox () const {    float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;    float scaleX = getScaleX(), scaleY = getScaleY();    for (int i = 0; i < _skeleton->slotsCount; ++i) {        spSlot* slot = _skeleton->slots[i];        if (!slot->attachment) continue;        int verticesCount;        if (slot->attachment->type == SP_ATTACHMENT_REGION) {            spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment;            spRegionAttachment_computeWorldVertices(attachment, slot->bone, _worldVertices);            verticesCount = 8;        } else if (slot->attachment->type == SP_ATTACHMENT_MESH) {            spMeshAttachment* mesh = (spMeshAttachment*)slot->attachment;            spMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices);            verticesCount = mesh->verticesCount;        } else if (slot->attachment->type == SP_ATTACHMENT_SKINNED_MESH) {            spSkinnedMeshAttachment* mesh = (spSkinnedMeshAttachment*)slot->attachment;            spSkinnedMeshAttachment_computeWorldVertices(mesh, slot, _worldVertices);            verticesCount = mesh->uvsCount;        } else            continue;        for (int ii = 0; ii < verticesCount; ii += 2) {            float x = _worldVertices[ii] * scaleX, y = _worldVertices[ii + 1] * scaleY;            minX = min(minX, x);            minY = min(minY, y);            maxX = max(maxX, x);            maxY = max(maxY, y);        }    }    Vec2 position = getPosition();    return Rect(position.x + minX, position.y + minY, maxX - minX, maxY - minY);}

大概意思就是遍历所有slot的顶点vertices,然后得出在x,y轴上的最大偏移量。最后得出的其实就是包裹整个动画的矩形区域

但是这还是没法找到我们自己绘制的碰撞区域。我们发现官方自带的方法里,对好几种slot->type都做了判断,但却唯独没有
SP_ATTACHMENT_BOUNDING_BOX
看名字就知道这才是我们想要的
但是官方没有提供所以只好我们自己依样画葫芦重写一个方法了

Rect SkeletonRenderer::getBoundingBox(const std::string& name) const {    float minX = FLT_MAX, minY = FLT_MAX, maxX = FLT_MIN, maxY = FLT_MIN;    float scaleX = getScaleX(), scaleY = getScaleY();    spAttachment* spA = getAttachment(name, name);//根据命名的名字来找到attachement    if (spA == nullptr || spA->type != SP_ATTACHMENT_BOUNDING_BOX)        return Rect(0,0,0,0);    spBoundingBoxAttachment* box = (spBoundingBoxAttachment*)spA;    for (int ii = 0; ii < box->verticesCount; ii += 2) {        float x = box->vertices[ii] * scaleX, y = box->vertices[ii + 1] * scaleY;        minX = min(minX, x);        minY = min(minY, y);        maxX = max(maxX, x);        maxY = max(maxY, y);    }    spSlot* slot = findSlot(name);    float worldX = slot->bone->worldX;//这个世界坐标系是这个骨骼相对于整个动画来说的,不是场景中的,所以添加到场景中进行碰撞检测时还是需要再转换    float worldY = slot->bone->worldY;

事件回调

_planeView->setCompleteListener([this](int trackIndex, int loopCount){            dynamic_cast<EnemyPlane*>(this)->_canAttacked = true;            dynamic_cast<EnemyPlane*>(this)->_hpBar->setVisible(true);            dynamic_cast<EnemyPlane*>(this)->_bloodBg->setVisible(true);        });

spine中的事件监听有两大类,一种是监听动画的,一种是监听轨道的
监听动画的

setStartListener//动画开始播放setEndListenersetCompleteListener//动画结束播放

置于end和complete的区别 还得再研究
监听轨道的就是

setTrackStartListener
0 0
原创粉丝点击