cocoscreator中spine局部换皮的探索

本文探讨了在CocosCreator中实现Spine局部换肤的需求和多种解决方案,包括多attachment切换、使用外部图片更新局部皮肤以及利用Spine挂点功能。对于每个方案,文章详细阐述了其优缺点,并提供了示例代码和实现方法。最终建议根据动画大小和换肤部位数量选择合适的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、需求情况

书之国中需要一个人物捏脸系统,要求可以让用户自由选择身体不同部位的形象,比如头发、眼睛、眉毛、上衣、裤子等。已经支持RegionAttacment和MeshAttachment,而且在realtime模式下也可以正常工作。cocoscreator v2.4.4版本验证通过。推荐使用外部图片进行局部换装.

2、方案探索

2.1 多attachment切换

由于spine动画的结构为bone→slot→attachment(即附件、图片),我们可以在动画文件中针对同一个部位(同一个slot)下做多个attachment,然后根据用户的选择进行切换attachment就行。
优点:web、native等多端统一代码。
缺点:随着可换装的部位越多、同一个部位皮肤越多,动画文件变得越来越大,由于spine动画文件是一次性加载进内存等,导致占用内存较多,实例化速度变慢。

主要代码如下:

// 局部换装 skinname一般默认为default
changePartialCloth(skeleton: sp.Skeleton, slotName: string, targetSkinName:string, targetAttaName:string) {
   
    // console.log('change cloth:', slotName, targetSkinName, targetAttaName);
    const slot = skeleton.findSlot(slotName);
    const skeletonData = skeleton.skeletonData.getRuntimeData();
    const skin = skeletonData.findSkin(targetSkinName);
    const slotIndex = skeletonData.findSlotIndex(slotName);
    const attachment = skin.getAttachment(slotIndex, targetAttaName);
    if (!slot || !attachment) {
   
        cc.error(slot && attachment, "slots: " + slotName + ", attach: " + targetAttaName + " not exists!");
        return;
    }
    slot.setAttachment(attachment);
    // 如果spine使用了private或者shared等缓存模式,则需要更新缓存。
    skeleton.invalidAnimationCache();
}

2.2 使用外部图片更新局部皮肤

由于attachemnt即是图片资源在spine内的表达,我们可以通过加载一张外部图片来更新attachment达到局部换装功能。
优点:spine动画每个部位可以只做一个attachment,这样动画文件结构简单,体积较小,内存占用较小加载速度也较快。
缺点:一是由于引擎本身不提供此功能,需要自己动手实现,而且web端和native端需要两套代码,必须修改引擎代码并重新编译引擎。二是动画在使用realtime模式时修改一个动画会影响使用同一个动画文件创建的其他动画,不过这个可以通过复制一份skeletonData来解决。如果皮肤套件特别多,这种方式不失为最佳方案。

2.2.1 web端代码:
  // 深拷贝一份skeletonData防止realtime下换装影响别的动画
  copySkeletonData(skeleton: sp.Skeleton) {
   
        // 复制一份skeletonData,换装时防止realtime模式下影响到别的动画
        let spData: sp.SkeletonData = skeleton.skeletonData;
        let copy = new sp.SkeletonData();
        cc.js.mixin(copy, spData);
        copy._uuid = spData._uuid + '_' + Date.now() + '_copy';
        let old = copy.name;
        let newName = copy.name + '_copy';
        copy.name = newName;
        copy.atlasText = copy.atlasText.replace(old, newName);
        copy.textureNames[0] = newName + '.png';
        copy.init && copy.init();
        skeleton.skeletonData = copy;
    }
	//  copySkeletonData(skeleton: sp.Skeleton) {
   
    //     // 复制一份skeletonData,换装时防止realtime模式下影响到别的动画
    //     let animation = skeleton.animation;
    //     let spData: sp.SkeletonData = skeleton.skeletonData;
    //     let copy = new sp.SkeletonData();
    //     cc.js.mixin(copy, spData);
    //     // @ts-ignore
    //     copy._uuid = Tool.uuid();
    //     let textureNames = copy['textureNames'];
    //     let copyTextureNames = [];
    //     for (let i = 0; i < textureNames.length; i++) {
   
    //         copy.atlasText = copy.atlasText.replace(textureNames[i], 'copy_' + textureNames[i]);
    //         copyTextureNames.push('copy_' + textureNames[i]);
    //     }
    //     copy['textureNames'] = copyTextureNames;
    //     // @ts-ignore
    //     copy.init && copy.init();
    //     skeleton.skeletonData = copy;
    //     skeleton.animation = animation;
    //     return copy;
    // }
// 使用外部图片换装
    changePartialWithExternalTexture(ani: sp.Skeleton, slotName: string, tex2d: cc.Texture2D) {
   
        let slot: sp.spine.Slot = ani.findSlot(slotName);
        let attach: sp.spine.RegionAttachment | sp.spine.MeshAttachment = slot.getAttachment() as (sp.spine.RegionAttachment | sp.spine.MeshAttachment);

        let spineTexture: sp.SkeletonTexture = new sp.SkeletonTexture({
    width: tex2d.width, height: tex2d.height });
        spineTexture.setRealTexture(tex2d);

		// 单张图片可以不用创建page
        // let page = new sp.spine.TextureAtlasPage();
        // page.
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值