关于cocos2dx中的action源码分析

action是cocos2dx扮演中很重要的角色,很多特殊的效果,都是通过他来实现,而且通过他可以方便的产生很多效果,

而不需要太多的相关知识储备、以及实现技巧。借着学习的思路,我们走一下cocos2dx中action的流程分析,大家共勉

吧。

【ActionManager篇】

一般action的入口在:

Action * Node::runAction(Action* action){CCASSERT( action != nullptr, "Argument must be non-nil");_actionManager->addAction(action, this, !_running);return action;}

他是node一个借口,而node是cocos2dx中绝大部分类的根类。所以意味着基本所有的cocos2dx具体类,都可以调用这个接口,

也意味着基本都可以为其添加特殊效果。

里面_actionManager成员,在Node::Node()构造函数里赋值,如下

_actionManager = director->getActionManager();从director类获取到了,而director类是cocosdx里的最基本的功能类,在其init方法里,_actionManager = new ActionManager();// 初始化完,马上就注册了update更新_scheduler->scheduleUpdate(_actionManager, Scheduler::PRIORITY_SYSTEM, false);在其初始化后,就注册了update更新事件,所以ActionManager的update方法在每帧都会调用了,达到可以更新action的作用。

接着分析ActionManager::addAction,看action是如何加入ActionManager

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;<span style="white-space:pre"></span>// 根据目标来查找对应的数据(tHashElement)    HASH_FIND_PTR(_targets, &tmp, element);    // 没有找到<span style="white-space:pre"></span>if (! element)    {<span style="white-space:pre"></span>// 构造元素tHashElement空间        element = (tHashElement*)calloc(sizeof(*element), 1);        element->paused = paused;        // 这里引用了target,为了防止在更新action,其宿主释放,这里retain一下<span style="white-space:pre"></span>target->retain();        element->target = target;        // 添加至_targets,以target的指针为key<span style="white-space:pre"></span>HASH_ADD_PTR(_targets, target, element);    }<span style="white-space:pre"></span>// 分配element里的成员空间     actionAllocWithHashElement(element); <span style="white-space:pre"></span>//     CCASSERT(! ccArrayContainsObject(element->actions, action), "");     // 将action放入element->actions<span style="white-space:pre"></span>ccArrayAppendObject(element->actions, action);<span style="white-space:pre"></span>// 这里设置一下action的对象     action->startWithTarget(target);}里面涉及的方法如下:// 分配tHashElement成员空间void ActionManager::actionAllocWithHashElement(tHashElement *element){// 分配action的存储空间,默认是4个// 4 actions per Node by defaultif (element->actions == nullptr){element->actions = ccArrayNew(4);}elseif (element->actions->num == element->actions->max) // action满了,空间翻倍{ccArrayDoubleCapacity(element->actions);}}

// 将action放入elementvoid ccArrayAppendObject(ccArray *arr, Ref* object){CCASSERT(object != nullptr, "Invalid parameter!");// 这里将action retain了一下object->retain();// 放置action序列末尾arr->arr[arr->num] = object;arr->num++;}// 设置action的对象void Action::startWithTarget(Node *aTarget){_originalTarget = _target = aTarget;}好了,到此,我们的action已经加入ActionManager中去了,现在由cocos2dx框架来驱动action了,前面已经分析了,ActionManager::update

会每帧调用,我们下面分析update

void ActionManager::update(float dt){// 遍历_targetsfor (tHashElement *elt = _targets; elt != nullptr; ){//_currentTarget = elt;_currentTargetSalvaged = false;// 该对象没有暂停if (! _currentTarget->paused){<span style="white-space:pre"></span>// 遍历该对象的所有actions// 英文提示该actions可能在循环里改变// The 'actions' MutableArray may change while inside this loop.for (_currentTarget->actionIndex = 0; _currentTarget->actionIndex < _currentTarget->actions->num;_currentTarget->actionIndex++){// 当前action_currentTarget->currentAction = (Action*)_currentTarget->actions->arr[_currentTarget->actionIndex];if (_currentTarget->currentAction == nullptr){continue;}_currentTarget->currentActionSalvaged = false;// 回调action::step_currentTarget->currentAction->step(dt);if (_currentTarget->currentActionSalvaged){// 这里action::release了,记得前面我们分析,在// void ccArrayAppendObject(ccArray *arr, Ref* object) retain了一下// The currentAction told the node to remove it. To prevent the action from// accidentally deallocating itself before finishing its step, we retained// it. Now that step is done, it's safe to release it._currentTarget->currentAction->release();} elseif (_currentTarget->currentAction->isDone()) // action完成{// 回调action::stop_currentTarget->currentAction->stop();// 移除该actionAction *action = _currentTarget->currentAction;// Make currentAction nil to prevent removeAction from salvaging it._currentTarget->currentAction = nullptr;// 移除该action,其会改变_currentTargetSalvaged的标志,// 也会改变_currentTarget->actions->numremoveAction(action);}// 清理一下当前action,_currentTarget->currentAction = nullptr;}}// elt, at this moment, is still valid// so it is safe to ask this here (issue #490)elt = (tHashElement*)(elt->hh.next);// 如果该actions没有action,并且_currentTargetSalvaged为真// only delete currentTarget if no actions were scheduled during the cycle (issue #481)if (_currentTargetSalvaged && _currentTarget->actions->num == 0){deleteHashElement(_currentTarget);}}// issue #635_currentTarget = nullptr;}简单来说,update的工作,就是遍历_targets,换句话说,就是遍历所有调用了runAction方法的Node对象,执行其Action的step方法,传入的是每帧

逝去的时间,在处理完后,看这个action是不是完成了,完成了的话,就移除该action,在最后,如果该tHashElement的actions都没有action,就移除

青春在我的心中是苦涩的又是甘甜的,是精致的又是粗糙的,

关于cocos2dx中的action源码分析

相关文章:

你感兴趣的文章:

标签云: