cocos2dx-lua的spine局部换装之进阶篇
来源:互联网 发布:tensorflow源码语言 编辑:程序博客网 时间:2024/05/22 17:12
之前写了一篇文章关于cocos2dx-lua的spine局部换装的。主要原理就是根据cocos2dx中SpineRenderer.cpp中setSkin()方法,添加了addSkin()方法。并在
lua_cocos2dx_spine_auto.cpp中添加方法 int lua_cocos2dx_spine_SkeletonRenderer_addSkin(la_State* tolua_S),完成lua-building,使在lua端可以调用。
上一篇地址:http://blog.csdn.net/u010536615/article/details/51137235
写进阶篇的原因是:
Spine动画制作时有个关键帧的东西,一般做动画时第一帧就要把所有的相关部件(slots)等都key上关键帧。然而我们之前做动画时并没key上关键帧,所以之前addSkin()方法没有任何问题。但将关键帧key上之后,尽管方法实现没有任何问题,但addSkin()方法不管用了。于是就把spine的从解析到动画实现的代码都看了一遍。使方法支持key上关键帧后的局部换装。
解决方法直接看标题3。
---------------------------------------------------------------1.换装原理--------------------------------------------
更换slots插槽中的attachment部件。
具体是找到对应slots的attachment部件,然后遍历skins中当前skin是否有该attachment部件,如果有,将该部件替换掉原slots中的attachment部件。
---------------------------------------------------------------2.问题产生原因--------------------------------------------
-------原因:
self.actor = sp.SkeletonAnimation:create("red/red.json", "red/red.atlas", 1)
self.actor:setAnimation(0, "red_wait", true)
self.actor:setPosition(450, 300)
self:addChild(self.actor)
其实只创建,不掉用动画self.actor:setAnimation(0, "red_wait", true),addSkin()方法是好用的。
那么问题就出在播放动画的时候。播放动画时会重新根据当前的skin替换掉slots中的attachment。所以之前设置的addSkin()中替换的,当动画动起来时就不起作用了。
-------引擎带的setSkin()起作用:
那为什么setSkin()是好用的呢。这就是关键。
之前也说了,替换的时候是找到当前设置的skin。而引擎的逻辑中只能设置整体的skin,也就是整套换装。没有提供设置单个部件skin的功能。
setSkin方法中通过
CONST_CAST(spSkin*, self->skin) = newSkin;
来设置当前的整体装备。
通过当前皮肤去替换每一个部件:
if (self->skin) {
spAttachment *attachment =spSkin_getAttachment(self->skin, slotIndex, attachmentName);
if (attachment)return attachment;
}
if (self->data->defaultSkin) {
spAttachment *attachment =spSkin_getAttachment(self->data->defaultSkin, slotIndex, attachmentName);
if (attachment)return attachment;
}
----所以我们需要做的就是给每一个slot都加上skin的属性。
替换时查找当前部件是否有skin,有的话应用该部件的skin。而不用整体的skin。
--------------------------------------3.解决方法--------------------------------------------
1.为每一个slot都加上skin的属性
editor-support->spine->SlotData.h中spSlotData结构体中增加spSkin*const skin属性并附上初始值。
添加Skin.h #include<spine/Skin.h>
typedef struct spSlotData {
constchar*const name;
const spBoneData* const boneData;
const char* attachmentName;
float r, g, b, a;
spBlendMode blendMode;
spSkin* const skin;//新增skin属性
#ifdef __cplusplus
spSlotData() :
name(0),
boneData(0),
attachmentName(0),
skin(0),//新增skin属性
r(0), g(0), b(0), a(0),
blendMode(SP_BLEND_MODE_NORMAL) {
}
#endif
} spSlotData;
2.addSkin()方法中,给替换的对应slot附上skineditor-support->spine->Skeleton.c中修改我上一篇中的spSkeleton_addSkin方法:
void spSkeleton_addSkin (spSkeleton* self,spSkin* newSkin,constchar* partName) {
if (newSkin) {
int i;
for (i = 0; i < self->slotsCount; ++i) {
spSlot* slot = self->slots[i];
if (slot->data->attachmentName) {
if (strcmp(slot->data->attachmentName, partName) ==0) {
spAttachment* attachment =spSkin_getAttachment(newSkin, i, slot->data->attachmentName);
if (attachment)
{
CONST_CAST(spSkin*, self->data->slots[i]->skin) = newSkin;//slot->skin赋值
spSlot_setAttachment(slot, attachment);
}
}
}
}
}
}
3.替换slot的attachment部件时判断当前slot的skin修改editor-support->spine->Skeleton.c中spSkeleton_getAttachmentForSlotIndex方法,其中两个if是新增代码。
spAttachment* spSkeleton_getAttachmentForSlotIndex (constspSkeleton* self,int slotIndex, constchar* attachmentName) {
if (slotIndex == -1)return0;
if (self->skin) {
//新增
if (self->data->slots[slotIndex]->skin) {
spAttachment *attachment =spSkin_getAttachment(self->data->slots[slotIndex]->skin, slotIndex, attachmentName);
if (attachment)return attachment;
}
spAttachment *attachment =spSkin_getAttachment(self->skin, slotIndex, attachmentName);
if (attachment)return attachment;
}
if (self->data->defaultSkin) {
//新增
if (self->data->slots[slotIndex]->skin) {
spAttachment *attachment =spSkin_getAttachment(self->data->slots[slotIndex]->skin, slotIndex, attachmentName);
if (attachment)return attachment;
}
spAttachment *attachment =spSkin_getAttachment(self->data->defaultSkin, slotIndex, attachmentName);
if (attachment)return attachment;
}
return0;
}
4.应用
其中setSkin方法用来对比检测用。
self.actor = sp.SkeletonAnimation:create("red/red.json", "red/red.atlas", 1)
self.actor:setAnimation(0, "red_wait", true)
self.actor:setPosition(450, 300)
self:addChild(self.actor)
self.actor:setSkin("HM_LV1")
local fashionStr = string.format("HM_LV%d", 4)
self.actor:addSkin("HM_LV2", "weap_wuqi")
self.actor:addSkin(fashionStr, "HM_huwan_z")
self.actor:addSkin(fashionStr, "HM_R_jiao")
self.actor:addSkin(fashionStr, "HM_jiao_L")--HM_L_jiao
self.actor:addSkin(fashionStr, "HM_dun")
self.actor:addSkin(fashionStr, "HM_kuzi")
--------------------------------------4.说明&备注--------------------------------------------
-------首先附上动画key和不key关键帧后json文件的区别:
key上:
"animations": {"red_wait": {"slots": {
"HM_R_jiao": {"attachment": [
{ "time": 0, "name": "HM_R_jiao" },
{ "time": 0.6, "name": null }],
"color": [
{ "time": 0, "color": "ffffffff" },
{ "time": 0.3, "color": "00ffffff" }
]}}}
不key上:
"animations": {"red_wait": {"slots": {
]}}}
其实就是key上了就有slots"HM_R_jiao"的属性,关键就在attachment属性,其实去掉attachment属性,只保留color属性,之前的addSkin()局部换装也是好用的。
-------动画代码:
SkeletonAnimation.cpp中
void SkeletonAnimation::update (float deltaTime) {
super::update(deltaTime);
deltaTime *= _timeScale;
spAnimationState_update(_state, deltaTime);
spAnimationState_apply(_state, _skeleton);
spSkeleton_updateWorldTransform(_skeleton);
}
这段代码看看就行,重点在下面。-------解析上一段的代码的attachment属性:
SkeletonJson.c文件中的_spSkeletonJson_readAnimation方法:
else if (strcmp(timelineArray->name, "attachment") == 0) {
spAttachmentTimeline *timeline = spAttachmentTimeline_create(timelineArray->size);
timeline->slotIndex = slotIndex;
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
Json* name = Json_getItem(frame, "name");
spAttachmentTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0),
name->type == Json_NULL ? 0 : name->valueString);
}
animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
duration = timeline->frames[timelineArray->size - 1];
if (duration > animation->duration) animation->duration = duration;
}
-------其中spAttachmentTimeline_create(timelineArray->size):
spAttachmentTimeline* spAttachmentTimeline_create (int framesCount) {
spAttachmentTimeline* self =NEW(spAttachmentTimeline);
_spTimeline_init(SUPER(self),SP_TIMELINE_ATTACHMENT,_spAttachmentTimeline_dispose,_spAttachmentTimeline_apply);
CONST_CAST(int, self->framesCount) = framesCount;
CONST_CAST(float*, self->frames) =CALLOC(float, framesCount);
CONST_CAST(char**, self->attachmentNames) =CALLOC(char*, framesCount);
return self;
}
-------关键就在_spAttachmentTimeline_apply动画应用attachment的方法 :Animation.c中的_spAttachmentTimeline_apply()方法。
void _spAttachmentTimeline_apply (constspTimeline* timeline,spSkeleton* skeleton,float lastTime, float time,
spEvent** firedEvents,int* eventsCount,float alpha) {
int frameIndex;
const char* attachmentName;
spAttachmentTimeline* self = (spAttachmentTimeline*)timeline;
if (time < self->frames[0]) {
if (lastTime > time)_spAttachmentTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX,0,0,0);
return;
} else if (lastTime > time) /**/
lastTime = -1;
frameIndex = time >= self->frames[self->framesCount -1] ?
self->framesCount -1 :binarySearch1(self->frames, self->framesCount, time) -1;
if (self->frames[frameIndex] < lastTime)return;
attachmentName = self->attachmentNames[frameIndex];
spSlot_setAttachment(skeleton->slots[self->slotIndex],
attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) :0);
}
--------重点:
最后一句是key上关键帧后addSkin()方法失效的关键。这句就是替换slot中的attachment部件。
spSlot_setAttachment(skeleton->slots[self->slotIndex],
attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0);
--------重点重点spSkeleton_getAttachmentForSlotIndex方法:
spAttachment* spSkeleton_getAttachmentForSlotIndex (constspSkeleton* self,int slotIndex, constchar* attachmentName) {
if (slotIndex == -1)return0;
if (self->skin) {
spAttachment *attachment =spSkin_getAttachment(self->skin, slotIndex, attachmentName);
if (attachment)return attachment;
}
if (self->data->defaultSkin) {
spAttachment *attachment =spSkin_getAttachment(self->data->defaultSkin, slotIndex, attachmentName);
if (attachment)return attachment;
}
return0;
}
--------问题所在其中的self->skin是skeleton的属性,所有部件只有统一的一个。每当动画播放时,就用这统一的skin去替换掉所有的skin。所以想局部换装就要纪录每个slot的skin,替换时单独判断。
- cocos2dx-lua的spine局部换装之进阶篇
- cocos2dx-lua的spine局部换装
- cocos2dx-3.x spine换装
- Unity动态换装之Spine换装
- spine-cocos2dx
- cocos2dx csb动画换装的问题
- 3.4 lua 使用 spine 的一些问题
- lua 使用 spine 的一些问题
- 【Cocos2dx】之绑定lua---的坑
- createjs支持spine骨骼的简单封装(更新,加入换装)
- spine的问题之二、、、
- cocos2dx之lua基础
- cocos2dx-2.0.6 spine骨骼动画的实现
- Lua的局部变量
- Lua的局部变量
- cocos2dx的lua绑定
- cocos2dx的lua绑定
- cocos2dx的lua绑定
- 购物车实现思路
- 服务器黑屏、无显示
- 浏览器hack总结 详细的浏览器兼容性的快速解决方法
- java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
- HashTable分析
- cocos2dx-lua的spine局部换装之进阶篇
- 【java知识点】mysql
- 本机尺寸
- IntelliJ IDEA 14和Maven创建java web项目
- Android5.0录屏方案
- Linux MacOS 查看端口占用及关闭命令
- spring使用模板发送邮件及附件笔记
- AES 加密解密的 JAVA 实现 【二】
- opencv imshow 图片无法显示, 显示不全问题,只出现一部分