首先抛出我们现在已有的问题:
问题1: 我们使用cocosbuilder来做特效,会有回调事件丢失的问题,主要出现在结束之前的几个关键帧。
问题2: 当回调函数失效的情况发生时,回调的一个CCString对象就会造成内存泄漏,虽然泄漏很少,但是依然是一个问题。
分析问题:
cocos2dx的动画系统不够安全 ?
最初我们认为是cocos2dx的动画系统是一个不完全依赖于帧处理的动画,是不可足够信赖的,所以会在加速的情况下,由于帧数的合并,造成丢失关键帧。经过我用加速器的测试,发现这是不对的,cocos2dx的动画系统是可信赖的,能够保证每一个关键帧不被丢失。
结论是:错误的,它的动画系统足够安全
为什么cocosbuilder的回调会失败 ?
问题出在cocosbuilder的解析代码中,具体是cocosbuilder会执行三个主线动画:整个时间轴的延时动画,之后是调用结束事件执行整个时间轴的事件回调执行整个时间轴的声音回调
乍一看这并没有什么问题,很符合我们的设定,分工明确,操作独立,然而作者忽略了一个问题,那就是在实际的设备执行过程中,每一帧的时间不是很理想的 1/30 或者 1/60,根据设备的运行状态,会有一些浮动。问题就出在这里,第一个动画控制着动画是否结束,他仅仅执行了一个延时,然后回调,相对来说是开销比较少的,第二个和第三个动画则不然,他们回去调用相关的逻辑,如果正常1/30的状态下,差距不会很大,但是如果我们开启了N倍的加速,就会把这个差距无限放大,时间的开销也就大了起来,最后的结果是第二个和第三个动画执行到最后的时间已经超过了动画的设定总时间,而在动画设定总时间到达的时候,已经调用了结束事件,也就是未被执行的关键帧就永远的被抛弃了,而分配的内存空间也就被遗弃在了内存中。
解决方案:让这三个动画变为一个动画执行,然后在执行完这3个动画之后,在执行结束动画。
代码如下:修改CCBAnimationManager::runAnimationsForSequenceIdTweenDuration函数
代码如下:
// mRootNode run actions once CCArray* spwans = CCArray::create(); // Make callback at end of sequence CCBSequence *seq = getSequence(nSeqId); CCAction *callDelayTime = CCDelayTime::create(seq->getDuration() + fTweenDuration); CCCallFunc *completeCall = CCCallFunc::create(this,callfunc_selector(CCBAnimationManager::sequenceCompleted)); spwans->addObject(callDelayTime); // add the event call back to spwans if(seq->getCallbackChannel() != NULL) { CCAction* action = (CCAction *)actionForCallbackChannel(seq->getCallbackChannel()); if(action != NULL) { spwans->addObject(action); } } // add the sound call back to spwans if(seq->getSoundChannel() != NULL) { CCAction* action = (CCAction *)actionForSoundChannel(seq->getSoundChannel()); if(action != NULL) { spwans->addObject(action); } } // after all actions,call action complete event CCSpawn *spwanAction = CCSpawn::create(spwans); mRootNode->runAction(CCSequence::createWithTwoActions(spwanAction,completeCall)); mRunningSequence = getSequence(nSeqId);