最终实现的效果是: 可以使用单张纹理构建自定义附件(attachment), 实现 Spine 骨骼动画的局部换装.
Cocos Creator 官方提供了 Spine 动画的一些功能, 如, 替换附件(attachment) 实现局部换装, 节点挂载,等另外的我没有用到,也就没怎么看.
官方提供的 替换附件是你在Spine里面编辑好得附件, 然后导出到CocosCreator编辑器里面,实现换装.
他这个缺点就是你要更换的纹理也在导出的图集里面, 如果你要更换的东西很多, 后面这个图集会越来越大, 后面你可能会为你要换装的部件专门导出一个图集, 但是实际上是没有解决这个问题.
我可以使用单张纹理构建附件, 实现局部换装.
在理解思路的时候需要你知道 骨骼(bone) 插槽(slot) 附件(attachment) 之间的关系.
1.获取任意一个插槽拿到插槽上面装载的附件解析这个数据类型
2.构建这个数据类型(附件)
3.用我们自定义的附件替换 或 设置附件.
数据结构
RegionAttachment
      -TextureAtlasRegion
            -TextureAtlasPage
                  -sp_SkeletonTexture
这个是上层数据类型使用了下层的数据类型.
我们从最下层开始说明.
我这里使用的是 ts 脚本语言.
// 构建 spine TextureAtlasRegion 需要的数据结构
type TextureAtlasPage = {
    name: string;
    height: number;
    width: number;
    texture: sp_SkeletonTexture;
    magFilter: number;
    minFilter: number;
    uWrap: number;
    vWrap: number;
}
type _size = {
    width: number;
    height: number;
}
type sp_SkeletonTexture = {
    _image: _size; // 图集的宽高
    _texture: cc.Texture2D; // cocos 原始纹理类型
}
// 如果研究过图集里面的参数这一块应该很简单
type TextureAtlasRegion = {
    degrees: number; // 图集里面旋转的角度
    height: number; // 图片在图集里面的高度
    u: number; // 要裁剪的图片在图集中的 uv 坐标, 也就是 图片的四个顶点 在 整个图集中所占用的百分比.
    u2: number;
    v: number;
    v2: number;
    width: number; //图片在图集里面的宽度
    x: number; // 图片在图集里面的x坐标
    y: number;
    index: number;
    name: string; // 插槽名字
    offsetX: number; // 裁剪出来的图片距离渲染尺寸的偏移量
    offsetY: number;
    originalHeight: number; // 图集的高度
    originalWidth: number;
    rotate: boolean; // 是否旋转
    page: TextureAtlasPage;
    renderObject: TextureAtlasRegion;
    texture: sp_SkeletonTexture;
}
因为我们使用的是单张纹理你可以将图集看成, 就是要替换的纹理.
cc.loader.loadRes(`<url>`, cc.Texture2D, (err: any, tex:cc.Texture2D) => {
      if(!!err) {
            console.error("纹理加载失败");
            return;
      }
      this.setRegion(hand, tex, "1.png", "Arms");
});
    setRegion(slot: any, tex: cc.Texture2D, texName:string, slotName: string) {
        let _s: _size = {
            width: tex.width,
            height: tex.height,
        }
        let sps: sp_SkeletonTexture = {
            _image: _s,
            _texture: tex,
        }
        let page: TextureAtlasPage = {
            name: texName,
            height: tex.height,
            width: tex.width,
            texture: sps,
            magFilter: tex["_magFilter"],
            minFilter: tex["_minFilter"],
            uWrap: tex["_wrapS"],
            vWrap: tex["_wrapT"],
        }
        let region: TextureAtlasRegion = {
            degrees: 0,
            height: tex.height, // 裁剪的数据 宽高
            width: tex.width,
            index: -1,
            name: slotName,
            x: 0,
            y: 0,
            offsetX: 0,
            offsetY: 0,
            originalHeight: tex.height,
            originalWidth: tex.width,
            rotate: false,
            page: page,
            renderObject: null,
            texture: sps,
            u: 0,
            u2: 1,
            v: 0,
            v2: 1,
        };
        region.renderObject = region;
        
        let attachment = new sp["spine"].RegionAttachment(slotName);
        attachment.setRegion(region);
        // console.log(sp.spine.AtlasAttachmentLoader.newRegionAttachment);
        attachment.height = tex.height;
        attachment.width = tex.width;
        let half_width = tex.width / 2;
        let half_height = tex.height / 2;
        let offset: Float32Array = new Float32Array([-half_width, -half_height, -half_width, half_height, half_width, half_height, half_width, -half_height]);
        attachment.offset = offset;//slot.offset;
        
        attachment.path = slotName;
        // attachment.rotation = 20;//slot.rotation;
        // attachment.scaleX = 1;//slot.scaleX;
        // attachment.scaleY = 1;//slot.scaleY;
        // attachment.x = 49.84;//slot.x;
        // attachment.y = -5.44;//slot.y;
        
        slot.setAttachment(attachment);
        // console.log(slot)
        // console.log(attachment);
    }
这个类型如果设置不正确, 就会渲染不出图片, 经过我的分析, 他其实就是以 图片的中心为坐标系构建图片周围四个顶点的坐标.
顺序必须是一致, 左下 -> 左上 -> 右上 -> 右下
这里可以去旋转插槽关联的骨骼去解决这个问题.
注意: 这个骨头不要录制动画, 让然你设置完成之后, 已播放动画,就会又回去了.
原文:https://www.cnblogs.com/vkerL/p/13030834.html