首页 > 其他分享 >【CC2DX随笔】多个精灵播放同一个动画时的问题(只播放最后一个动画)

【CC2DX随笔】多个精灵播放同一个动画时的问题(只播放最后一个动画)

时间:2024-04-25 18:23:18浏览次数:22  
标签:动画 target nullptr 精灵 element action 播放 CC2DX

多个精灵播放同一个动画时的问题

代码摘要

// pSpReinit 在 2 次循环里代表 2 个精灵.
for (short j = 0; j < 2; j++)
{
  for (short i = 0; i < THMAX_ANI_COUNT; i++)
  {
    if (0 == strcmp(m_arrpAniGroup[i]->szarrDesc, "batMove"))
    {
      pAniMoveTo = m_arrpAniGroup[i]->pAnimate;
      break;
    }
  }
  pSpReinit->pSpCharacter->runAction(pAniMoveTo);
  pSpReinit->pSpCharacter->runAction(pSeMoveTo);
}

异常情况

在2次循环里,给精灵都加上了相同的帧动画Action,但是只有最后一个精灵才能播放这个动画。

分析

通过看源码runAction()中的addAction(),可以看到在action->startWithTarget(target);里,一个action只能绑定一个精灵。

解决方案

将这个帧动画对象拷贝一份出来,成为独立不同的对象,就不会一个对象绑定到多个精灵上。
pSpReinit->pSpCharacter->runAction(pAniMoveTo->clone());

深度分析

对函数void ActionManager::addAction(Action *action, Node *target, bool paused)进行深度分析。

// 源码
void ActionManager::addAction(Action *action, Node *target, bool paused)
{
    CCASSERT(action != nullptr, "action can't be nullptr!");
    CCASSERT(target != nullptr, "target can't be nullptr!");
    if(action == nullptr || target == nullptr)
        return;

    tHashElement *element = nullptr;
    // we should convert it to Ref*, because we save it as Ref*
    Ref *tmp = target;
    HASH_FIND_PTR(_targets, &tmp, element);
    if (! element)
    {
        element = (tHashElement*)calloc(sizeof(*element), 1);
        element->paused = paused;
        target->retain();
        element->target = target;
        HASH_ADD_PTR(_targets, target, element);
    }

     actionAllocWithHashElement(element);
 
     CCASSERT(! ccArrayContainsObject(element->actions, action), "action already be added!");
     ccArrayAppendObject(element->actions, action);
 
     action->startWithTarget(target);
}
  • addAction函数读取或创建一个pElement哈希表项,一个pElement可以存放4个动画,超了则翻倍扩容。
  • pElement是用来存放动画和用此动画的精灵的哈希表。一个pElement只能放一次动画,否则ASSERT,这也是为什么一个动画不能重复添加的原因(可能是为了省内存?)。
  • 再设置这个动画是哪个精灵来使用,给后续的动画调用指导使用者。所以这里就是原因,因为只有帧动画Action是唯一的,有且只有一个,所以只能绑定一个精灵来使用
  • 上述循环的时候重复runAction, 也就是重复变换了使用者,只有最后一个使用者得到了这个Action。
  • 执行动画的逻辑可能还要深度分析 ActionManage,runAction只是添加,具体实现还是在update里的每个tick去做.
    • 该方法简要地说是对ActionManager的哈希链表_targets进行遍历,对遍历到的每个element的actions再遍历,对遍历到的action执行step(float dt)

参考:

标签:动画,target,nullptr,精灵,element,action,播放,CC2DX
From: https://www.cnblogs.com/hatsuzuki/p/18158287

相关文章