cocos2d-x动作原理
首先CCAction是所有动作的基类,如下图继承关系:
那么来看看CCAction的定义:
class CC_DLL CCAction : public CCObject
{
public:
CCAction(void);
virtual ~CCAction(void); const char* description();
virtual CCObject* copyWithZone(CCZone *pZone);
//! return true if the action has finished
virtual bool isDone(void);
virtual void startWithTarget(CCNode *pTarget);
/**
called after the action has finished. It will set the 'target' to nil.
IMPORTANT: You should never call "[action stop]" manually. Instead, use: "target->stopAction(action);"
*/
virtual void stop(void);
//! called every frame with it's delta time. DON'T override unless you know what you are doing.
virtual void step(float dt);
virtual void update(float time);
inline CCNode* getTarget(void) { return m_pTarget; }
inline void setTarget(CCNode *pTarget) { m_pTarget = pTarget; }
inline CCNode* getOriginalTarget(void) { return m_pOriginalTarget; }
inline void setOriginalTarget(CCNode *pOriginalTarget) { m_pOriginalTarget = pOriginalTarget; }
inline int getTag(void) { return m_nTag; }
inline void setTag(int nTag) { m_nTag = nTag; } public:
static CCAction* create();
protected:
CCNode *m_pOriginalTarget;
CCNode *m_pTarget;
int m_nTag;
};
在类定义最后有三个成员变量,而继承自CCAction的CCFiniteTimeAction主要新增加了一个用于保存该动作总完成时间的成员变量float m_fDuration;
对于其两个子类CCActionInstant和CCActionInterval,前者没有新增任何函数和变量,而后者增加了两个成员变量:float m_elapsed(记录从动作开始起逝去的时间);和bool m_bFirstTick(一个控制变量);
那么动作是如何执行的呢?
当一个节点调用runAction方法时,动作管理类CCActionManager(单例类)会将新的动作和节点添加到其管理的动作表中。
CCAction * CCNode::runAction(CCAction* action)
{
CCAssert( action != NULL, "Argument must be non-nil");
m_pActionManager->addAction(action, this, !m_bRunning);
return action;
}
在addAction中,将动作添加到动作队列后,就会对该动作调用其成员函数startWithTarget(CCNode* pTarget)来绑定该动作的执行节点,和初始化动作类的成员变量。
这些工作都完成后,每一帧刷新屏幕时,系统就会在CCActionManager中遍历动作表中的每一个动作,并调用动作的step(float)方法。而step方法主要负责计算m_elapsed的值,并调用update(float)方法。
void CCActionInterval::step(float dt)
{
if (m_bFirstTick)
{
m_bFirstTick = false;
m_elapsed = ;
}
else
{
m_elapsed += dt;
} this->update(MAX (, // needed for rewind. elapsed could be negative
MIN(, m_elapsed / MAX(m_fDuration, FLT_EPSILON) // division by 0
)
)
);
}
传入update方法的float型参数表示逝去的时间与动作完成需要的时间的比值,介于0-1之间,即动作完成的百分比。然后在update方法中,通过完成比例对节点的属性进行操作来达到动作的效果。
例如:对MoveBy调用update时,通过传入的比例调用setPosition直接修改节点的属性。
最后在每一帧结束后,CCActionManager的update会检查动作队列中每个动作的isDone函数是否返回true,如果返回true,则动作结束,将其从队列中删除。
——————————————————————————————————————————————————————————————————————————
从上面知道:动作都是由CCActionManager来管理。那我们再来看看CCActionManager的工作原理。
在CCDirector初始化时,执行了如下代码:
// scheduler
m_pScheduler = new CCScheduler();
// action manager
m_pActionManager = new CCActionManager();
m_pScheduler->scheduleUpdateForTarget(m_pActionManager, kCCPrioritySystem, false);
可见动作管理类在创建时就注册了Update定时器,那么CCScheduler在游戏的每一帧mainLoop更新中都会触发CCActionManager注册的update(float )方法。调度器原理请参照此链接:http://www.cnblogs.com/songcf/p/3162414.html
// main loop
void CCActionManager::update(float dt)
{
//枚举动作表中的每一个节点
for (tHashElement *elt = m_pTargets; elt != NULL; )
{
m_pCurrentTarget = elt;
m_bCurrentTargetSalvaged = false; if (! m_pCurrentTarget->paused)
{
//枚举节点的每一个动作 actions数组可能会在循环中被修改
for (m_pCurrentTarget->actionIndex = ; m_pCurrentTarget->actionIndex < m_pCurrentTarget->actions->num;
m_pCurrentTarget->actionIndex++)
{
m_pCurrentTarget->currentAction = (CCAction*)m_pCurrentTarget->actions->arr[m_pCurrentTarget->actionIndex];
if (m_pCurrentTarget->currentAction == NULL)
{
continue;
} m_pCurrentTarget->currentActionSalvaged = false; m_pCurrentTarget->currentAction->step(dt); if (m_pCurrentTarget->currentActionSalvaged)
{
// 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.
m_pCurrentTarget->currentAction->release();
} else
if (m_pCurrentTarget->currentAction->isDone())
{
m_pCurrentTarget->currentAction->stop(); CCAction *pAction = m_pCurrentTarget->currentAction;
// Make currentAction nil to prevent removeAction from salvaging it.
m_pCurrentTarget->currentAction = NULL;
removeAction(pAction);
} m_pCurrentTarget->currentAction = NULL;
}
} // elt, at this moment, is still valid
// so it is safe to ask this here (issue #490)
elt = (tHashElement*)(elt->hh.next); // only delete currentTarget if no actions were scheduled during the cycle (issue #481)
if (m_bCurrentTargetSalvaged && m_pCurrentTarget->actions->num == )
{
deleteHashElement(m_pCurrentTarget);
}
} // issue #635
m_pCurrentTarget = NULL;
}
cocos2d-x动作原理的更多相关文章
- 【Cocos2d入门教程四】Cocos2d-x菜单篇
游戏世界多姿多彩,无论多靓丽的游戏,多耐玩的游戏,在与游戏用户交互上的往往是菜单. 上一章我们已经大概了解了导演.节点.层.精灵.这一章以菜单为主题. 菜单(Menu)包含以下内容: 1.精灵菜单项( ...
- cocos2D(三)---- 第一cocos2d的程序代码分析
在第一讲中已经新建了第一个cocos2d程序,执行效果例如以下: 在这讲中我们来分析下里面的代码,了解cocos2d的工作原理,看看屏幕上的这个"Hello World"是怎样显示 ...
- Cocos2D中Action的进阶使用技巧(一)
大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请多提意见,如果觉得不错请多多支持点赞.谢谢! hopy ;) 大家对Cocos2d中动作的使用大概都很清楚了,其实本身act ...
- 三、第一个cocos2d程序的代码分析
http://blog.csdn.net/q199109106q/article/details/8591706 在第一讲中已经新建了第一个cocos2d程序,运行效果如下: 在这讲中我们来分析下里面 ...
- 18、Cocos2dx 3.0游戏开发找小三之cocos2d-x,请问你是怎么调度的咩
重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/30478251 Cocos2d 的一大特色就是提供了事 ...
- oracle pfile spfile
1.参数文件的定义.作用 oracle数据库通过一系列参数来对数据库进行配置.这些参数是以键-值对的形式来表 示的,如:MAXLOGFILES=50BACKGROUND_DUMP_DEST=C:DUM ...
- Mecanim的Avater
角色共用同一套动作原理 先说说为什么不同的角色可以共用同一套动作:因为导入之后,我们需要为它们每一个模型都创建一个Avater,而Avater里存储了骨骼的蒙皮信息(创建Avater时把三维软件里的蒙 ...
- linux内核数据结构学习总结
目录 . 进程相关数据结构 ) struct task_struct ) struct cred ) struct pid_link ) struct pid ) struct signal_stru ...
- 使用 CodeIgniter 框架快速开发 PHP 应用(三)
原文:使用 CodeIgniter 框架快速开发 PHP 应用(三) 分析网站结构既然我们已经安装 CI ,我们开始了解它如何工作.读者已经知道 CI 实现了MVC式样. 通过对目录和文件的内容进行分 ...
随机推荐
- 2016 Multi-University Training Contest 5 1011 Two DP
http://acm.hdu.edu.cn/showproblem.php?pid=5791 HDU5791 Two 题意 :两个数组,多少个不连续子串相等 思路: dp[i][j] :a串i结尾,b ...
- Android滑动动画ViewFlipper和视频播放VideoView的使用
Android滑动动画,可以用ViewPager或者ViewFlipper实现. ViewPager自带触摸滑动功能,结合Fragment使用很好,来自补充组件android-support-v4.j ...
- 新手指南:详解Linux Top 命令
Linux top命令简介 top 命令是最流行的性能监视工具之一,我们必需了解.它是一个优秀的交互式工具,用于监视性能.它提供系统整体性能,但报告进程信息才是 top 命令的长处.top 命令交互界 ...
- rop框架签名功能控制
平台级控制: 通过<rop:annotation-driven/>的 sign-enable 属性即可开启或关闭服务平台签名验证功能:<rop:annotation-driven s ...
- 在Android4.0中Contacts拨号盘界面剖析(源码)
通过在 ViewPager 的适配器对象中,发现过一下三行代码 private DialpadFragment mDialpadFragment; private CallLogFragment ...
- POJ 2828 Buy Tickets (线段树 or 树状数组+二分)
题目链接:http://poj.org/problem?id=2828 题意就是给你n个人,然后每个人按顺序插队,问你最终的顺序是怎么样的. 反过来做就很容易了,从最后一个人开始推,最后一个人位置很容 ...
- SQLite的37个核心函数
转载:http://www.feiesoft.com/00012/ abs(X) abs(X)返回 X 的绝对值. Abs(X) returns NULL if X is NULL. Abs(X) r ...
- Unity3D之Mecanim动画系统学习笔记(三):Animation View
动画组件之间的关系 我们先看一张图: 这里我们可以看到,我们在GameObject之上绑定的Animator组件是控制模型进行动画播放的. 而其属性Controller则对应一个Animator Co ...
- C#学习笔记(六):可空类型、匿名方法和迭代器
可空类型 为啥要引入可空类型? 在数据库中,字段是可以为null值的,那么在C#中为了方便的操作数据库的值,微软引入了可空类型. 声明可空类型 我们可以使用两种方法声明一个可空类型: Nullable ...
- 菜鸟学习 git
到新公司学习和使用 git 有一段时间了.不得不说 git 真的很牛逼,当然,git 的牛逼是建立在 Linux 之父的牛逼的基础上的. 首先跪着推荐 git 学习网站:http://www.liao ...