Spine在cocos2d-x中进行局部换肤

原文来自 [url=http://www.cnblogs.com/jiushichenan/p/4379990.html][/url]


最近发现越来越多的游戏热衷用spine来做动画,做出来的效果真是生动美妙啊。我也来研究一下。期间就遇到了两个问题,一个是局部换肤的问题,一个是碰撞的时候。我先来解决局部换肤的问题。


这是测试效果图:


[img=http://img.bbs.csdn.net/upload/201504/11/1428722928_421760.gif][/img]


    看了看cocos2d-x 提供的spine的demo,虽然没有局部换肤但是有整体换肤的功能,我觉得这就是解决问题的突破口。在cocos2d-x3.4中,换肤的函数是SkeletonRenderer 类中的这个函数:
[code=c]bool setSkin (const std::string& skinName);[/code]
    首先看看函数的实现,它是直接调用了另外一个函数:
[code=c]bool SkeletonRenderer::setSkin (const std::string& skinName) {
    return spSkeleton_setSkinByName(_skeleton, skinName.c_str()) ? true : false;
}[/code]
    然后我再进入spSkeleton_setSkinByName函数里一探究竟。这个函数的实现是这样的:
[code=c]int spSkeleton_setSkinByName (spSkeleton* self, const char* skinName) {
    spSkin *skin;
    if (!skinName) {
        spSkeleton_setSkin(self, 0);
        return 1;
    }
    skin = spSkeletonData_findSkin(self->data, skinName);
    if (!skin) return 0;
    spSkeleton_setSkin(self, skin);
    return 1;
}[/code]
    首先它判断皮肤名称是不是有效的,如果无效就设置皮肤为nullptr。如果有效就通过骨架数据根据皮肤名进行查找,看存不存在这个皮肤。如果存在就调用spSkeleton_setSkin函数,我们再进入这个函数看一看:
[code=c]void spSkeleton_setSkin (spSkeleton* self, spSkin* newSkin) {
    if (newSkin) {
        if (self->skin)
            spSkin_attachAll(newSkin, self, self->skin);
        else {
            /* No previous skin, attach setup pose attachments. */
            int i;
            for (i = 0; i < self->slotsCount; ++i) {
                spSlot* slot = self->slots[i];
                if (slot->data->attachmentName) {
                    spAttachment* attachment = spSkin_getAttachment(newSkin, i, slot->data->attachmentName);
                    if (attachment) spSlot_setAttachment(slot, attachment);
                }
            }
        }
    }
    CONST_CAST(spSkin*, self->skin) = newSkin;
}[/code]
    我们来看看这个函数做了些什么事情。当当前皮肤不为nullptr的时候就调用spSkin_attachAll将新皮肤的所有附件替换到原皮肤上,否则(当前没有皮肤的时候)就遍历当前骨架的所有slot,将新皮肤的附件添加到骨架对应的slot上来。


    写到这里我想我已经知道解决方法了。在遍历骨架的slot的时候,我可以在slot的数据中获取到附件的名称。在遍历的时候只有当这个名称为我想要替换掉的那个位置的名称时我才进行替换处理,这样就可以实现局部换肤了。


    为此我新增了一个类继承自 spine::SkeletonAnimation类,在这个类里面增加了局部换肤的函数:
[code=c]bool replacementParts(const std::string& skinName, const std::string& attachmentName);[/code]


    下面给出完整代码:
[code=c]
#ifndef SPINENODE_H
#define SPINENODE_H
 
#include "spine/SkeletonAnimation.h"
 
class SpineNode final : public spine::SkeletonAnimation
{
public:
    static SpineNode* createWithData(spSkeletonData* skeletonData);
    static SpineNode* createWithFile(const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1);
    static SpineNode* createWithFile(const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
 
public:
    /**
     * 新增函数
     * 是否已经翻转x轴
     */
    bool isFlippedX() const;
 
    /**
     * 新增函数
     * 设置x轴翻转
     */
    void setFlippedX(bool flippedX);
 
    /**
     * 新增函数
     * 是否已经翻转y轴
     */
    bool isFlippedY() const;
 
    /**
     * 新增函数
     * 设置y轴翻转
     */
    void setFlippedY(bool flippedY);
 
    /**
     * 新增函数
     * 更换部件,将目标皮肤的的某个部件替换到当前皮肤上
     * @ 参数 std::string 皮肤名称, std::string 附件名称
     */
    bool replacementParts(const std::string& skinName, const std::string& attachmentName);
 
private:
    SpineNode(spSkeletonData* skeletonData);
    SpineNode(const std::string& skeletonDataFile, spAtlas* atlas, float scale = 1);
    SpineNode(const std::string& skeletonDataFile, const std::string& atlasFile, float scale = 1);
     
private:
    cocos2d::CustomCommand _customCommand;
};
 
#endif


#include "SpineNode.h"
using namespace cocos2d;
 
struct _Entry
{
    int slotIndex;
    const char* name;
    spAttachment* attachment;
    _Entry* next;
};
 
typedef struct
{
    spSkin super;
    _Entry* entries;
} _spSkin;
 
SpineNode::SpineNode(spSkeletonData* skeletonData)
    : SkeletonAnimation(skeletonData)
{
 
}
 
SpineNode::SpineNode(const std::string& skeletonDataFile, spAtlas* atlas, float scale)
    : SkeletonAnimation(skeletonDataFile, atlas, scale)
{
 
}
 
SpineNode::SpineNode(const std::string& skeletonDataFile, const std::string& atlasFile, float scale)
    : SkeletonAnimation(skeletonDataFile, atlasFile, scale)
{
 
}
 
SpineNode* SpineNode::createWithData(spSkeletonData* skeletonData)
{
    SpineNode* node = new SpineNode(skeletonData);
    node->autorelease();
    return node;
}
 
SpineNode* SpineNode::createWithFile(const std::string& skeletonDataFile, spAtlas* atlas, float scale)
{
    SpineNode* node = new SpineNode(skeletonDataFile, atlas, scale);
    node->autorelease();
    return node;
}
 
SpineNode* SpineNode::createWithFile(const std::string& skeletonDataFile, const std::string& atlasFile, float scale)
{
    SpineNode* node = new SpineNode(skeletonDataFile, atlasFile, scale);
    node->autorelease();
    return node;
}
 
bool SpineNode::isFlippedX() const
{
    return _skeleton->flipX != 0;
}
 
void SpineNode::setFlippedX(bool flippedX)
{
    _skeleton->flipX = flippedX ? 1 : 0;
}
 
bool SpineNode::isFlippedY() const
{
    return _skeleton->flipY != 0;
}
 
void SpineNode::setFlippedY(bool flippedY)
{
    _skeleton->flipY = flippedY ? 1 : 0;
}
 
bool SpineNode::replacementParts(const std::string& skinName, const std::string& attachmentName)
{
    if (skinName.empty())
    {
        return false;
    }
 
    spSkin *skin = spSkeletonData_findSkin(_skeleton->data, skinName.c_str());
    if (!skin) return false;
 
    if (_skeleton->skin)
    {
        const _Entry *entry = reinterpret_cast<_spSkin *>(_skeleton->skin)->entries;
        while (entry)
        {
            spSlot *slot = _skeleton->slots[entry->slotIndex];
            if (strcmp(slot->data->name, attachmentName.c_str()) == 0)
            {
                spAttachment *attachment = spSkin_getAttachment(skin, entry->slotIndex, entry->name);
                if (attachment) spSlot_setAttachment(slot, attachment);
                return true;
            }
            entry = entry->next;
        }
    }
    else
    {
        for (int i = 0; i < _skeleton->slotsCount; ++i)
        {
            spSlot* slot = _skeleton->slots[i];
            if (strcmp(slot->data->name, attachmentName.c_str()) == 0)
            {
                spAttachment* attachment = spSkin_getAttachment(skin, i, slot->data->attachmentName);
                if (attachment) spSlot_setAttachment(slot, attachment);
                return true;
            }
        }
    }
 
    return false;
}[/code]
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值