目录
前言
为什么需要实现皮肤合成?
想象这样一个应用场景,我有一个小人,他有一个衣柜,里面有x个帽子、y件衣服、z条裤子,我想穿出多套搭配怎么办?由于Spine 编辑器不能实现多个皮肤同时处于活跃状态,因此想在编辑器中实现各种搭配,就要做出x*y*z个皮肤。而本文旨在解决这个指数爆炸的问题。
方案:
在Spine编辑器中仅创建单个皮肤(单帽子、衣服)。然后,在运行时,通过组合单品皮肤完成套装皮肤。
一、一点spine动画基础知识
spine骨骼动画主要由:骨骼、动画、插槽、皮肤、附件组成
骨骼:类似与节点树,用于移动缩放旋转等,存在父子关系(子节点跟随父节点移动)
插槽:用于掌控绘制顺序、关联附件,骨骼可以关联多个插槽,一个插槽可以关联多个附件(但同时只有一个附件可见,皮肤实现原理)
附件:用于真正的显示(与图片资源绑定)
皮肤:用于重用骨骼和插槽,通过换一套新的附件来展示不同的动画效果
皮肤记录了什么?
记录了某个插槽应该显示什么附件,所以切换皮肤相当于切换一套附件
二、具体实现
1.实现原理
通过上面的知识,皮肤里存储的是附件,那么实现皮肤合成只需要拿出各个单品皮肤里的附件合成出一个新皮肤就行了
2.实现代码
核心函数(Skeleton.c):
void spSkeleton_attachSkin (spSkeleton* self, spSkin* attachSkin, spSkin* composedSkin) {
if (attachSkin) {
int i;
for ( i = 0; i < self->slotsCount; ++i) {
spSlot* slot = self->slots[i];
if (slot->data->attachmentName) {
spAttachment* attachment = spSkin_getAttachment(attachSkin, i, slot->data->attachmentName);
spAttachment* hadAttachment = spSkin_getAttachment(composedSkin, i, slot->data->attachmentName);//若有附件冲突,添加的冲突附件隶属于先附加皮肤
if (attachment && !hadAttachment) {
spSkin_addAttachment(composedSkin, i, slot->data->attachmentName, attachment); //添加附件
// spSlot_setAttachment(slot, attachment); //直接设置为被添加的附件
}
}
}
}
}
根据皮肤名字列表和待合成皮肤的个数生成并设置皮肤(Skeleton.c):
int spSkeleton_composeSkinByNameList (spSkeleton* self, const char** skinNameList, int num) {
if (!skinNameList) {
return 0;
}
char* tempName = "_COMPOSEDSKIN";
if(self->composedSkin) { //说明存在之前合成的皮肤,释放并初始化它
CONST_CAST(spSkin*, self->skin) = 0;
spComposedSkin_dispose(self->composedSkin);
CONST_CAST(spSkin*, self->composedSkin) = 0;
}
spSkin* composedSkin = 0;
CONST_CAST(spSkin*, composedSkin) = spSkin_create(tempName);
int i;
for ( i = 0; i < num; ++i) {
spSkin *skin;
const char* skinName = skinNameList[i];
if (!skinName){
spComposedSkin_dispose(composedSkin);
return 0;
}
skin = spSkeletonData_findSkin(self->data, skinName);
if (!skin) {
spComposedSkin_dispose(composedSkin);
return 0;
}
spSkeleton_attachSkin(self, skin, composedSkin);
}
if (composedSkin) {
CONST_CAST(spSkin*, self->composedSkin) = composedSkin;
CONST_CAST(spSkin*, self->skin) = self->composedSkin;
}
spSkeleton_setSkin(self, composedSkin);
return 1;
}
c++层调用
bool SkeletonRenderer::composeSkin (const char** skinNameList, int num) {
return spSkeleton_composeSkinByNameList(_skeleton, skinNameList, num) ? true : false;
}
使用lua开发的再自己做下lua-bingding就好了