<span style="white-space:pre"> </span>starSprite->runAction(path); _emitter->runAction(path);
当你像这样有两个节点同时调用path这样一个动作时,运行之后是否有疑惑————
为啥只有下面的_emitter执行了这个动作,而starSprite愣是纹丝不动呢?
老规矩(???什么时候说过的规矩。。。)最有效的办法还是看cocos的源代码去。
首先查看runAction
Action * Node::runAction(Action* action) { CCASSERT( action != nullptr,"Argument must be non-nil"); _actionManager->addAction(action,this,!_running); return action; }
没多少内容,很容易猜到主要内容在addAction()函数当中
继续翻源码。。。
<pre name="code" class="cpp">void ActionManager::addAction(Action *action,Node *target,bool paused) { CCASSERT(action != nullptr,""); //有效性判断 CCASSERT(target != nullptr,""); tHashElement *element = nullptr; //定义哈希表项的指针并置空 // we should convert it to Ref*,because we save it as Ref* Ref *tmp = target; HASH_FIND_PTR(_targets,&tmp,element); //通过这个指针找到对应的哈希表项返回给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); //为哈希表项element申请内存以存放动画集 CCASSERT(! ccArrayContainsObject(element->actions,action),""); //判断action是否已在element的动画集中,确保只放一个action ccArrayAppendObject(element->actions,action); //将action放入element的动画集中 action->startWithTarget(target); //根据当前node来执行此动画 }
根据注释应该看得大懂大致内容,并且我们知道了重要的一点,我们的问题是由最后一句引起的
action->startWithTarget(target);
查看cocos的文档我们可以知道:
当有节点执行一个动画时,这个node会变为这个action的target,且一个action都有且仅有一个target成员,所以假如在一个node调用一个action后,此action的target设为此node
但之后当有另一个node调用同样这个action时,此action的target又会变为这个node,由上面addAction函数可知,action运行是根据target的值来选择哪个node运行的,所以这个action只能被后面的node调用,那么解决办法就是,让后面的node通通调用动作的clone()函数。
总结一句话:一个动作action无法被一块相同的区域调用runAction,想要让多个节点执行相同的action,可以让其他的节点全部调用action的clone()
如这样:
<pre name="code" class="cpp"> starSprite->runAction(path); _emitter->runAction(path->clone();