最终实现的效果是: 可以使用单张纹理构建自定义附件(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