哪里有DemoBag背包系统cocos2dx demo手机游戏源码?

关于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);
他是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 =
& & // we should convert it to Ref*, because we save it as Ref*
& & Ref *tmp =
// 根据目标来查找对应的数据(tHashElement)
& & HASH_FIND_PTR(_targets, &tmp, element);
& & // 没有找到
if (! element)
// 构造元素tHashElement空间
& & & & element = (tHashElement*)calloc(sizeof(*element), 1);
& & & & element-&paused =
& & & & // 这里引用了target,为了防止在更新action,其宿主释放,这里retain一下
target-&retain();
& & & & element-&target =
& & & & // 添加至_targets,以target的指针为key
HASH_ADD_PTR(_targets, target, element);
// 分配element里的成员空间
& & &actionAllocWithHashElement(element);
& & &CCASSERT(! ccArrayContainsObject(element-&actions, action), &&);
& & &// 将action放入element-&actions
ccArrayAppendObject(element-&actions, action);
// 这里设置一下action的对象
& & &action-&startWithTarget(target);
里面涉及的方法如下:
// 分配tHashElement成员空间
void ActionManager::actionAllocWithHashElement(tHashElement *element)
// 分配action的存储空间,默认是4个
// 4 actions per Node by default
if (element-&actions == nullptr)
element-&actions = ccArrayNew(4);
if (element-&actions-&num == element-&actions-&max) // action满了,空间翻倍
ccArrayDoubleCapacity(element-&actions);
// 将action放入element
void ccArrayAppendObject(ccArray *arr, Ref* object)
CCASSERT(object != nullptr, &Invalid parameter!&);
// 这里将action retain了一下
object-&retain();
// 放置action序列末尾
arr-&arr[arr-&num] =
arr-&num++;
// 设置action的对象
void Action::startWithTarget(Node *aTarget)
_originalTarget = _target = aT
好了,到此,我们的action已经加入ActionManager中去了,现在由cocos2dx框架来驱动action了,前面已经分析了,ActionManager::update
会每帧调用,我们下面分析update
void ActionManager::update(float dt)
// 遍历_targets
for (tHashElement *elt = _ elt != )
_currentTarget =
_currentTargetSalvaged =
// 该对象没有暂停
if (! _currentTarget-&paused)
// 遍历该对象的所有actions
// 英文提示该actions可能在循环里改变
// The 'actions' MutableArray may change while inside this loop.
for (_currentTarget-&actionIndex = 0; _currentTarget-&actionIndex & _currentTarget-&actions-&
_currentTarget-&actionIndex++)
// 当前action
_currentTarget-¤tAction = (Action*)_currentTarget-&actions-&arr[_currentTarget-&actionIndex];
if (_currentTarget-¤tAction == nullptr)
_currentTarget-¤tActionSalvaged =
// 回调action::step
_currentTarget-¤tAction-&step(dt);
if (_currentTarget-¤tActionSalvaged)
// 这里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-¤tAction-&release();
if (_currentTarget-¤tAction-&isDone()) // action完成
// 回调action::stop
_currentTarget-¤tAction-&stop();
// 移除该action
Action *action = _currentTarget-¤tA
// Make currentAction nil to prevent removeAction from salvaging it.
_currentTarget-¤tAction =
// 移除该action,其会改变_currentTargetSalvaged的标志,
// 也会改变_currentTarget-&actions-&num
removeAction(action);
// 清理一下当前action,
_currentTarget-¤tAction =
// 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 =
简单来说,update的工作,就是遍历_targets,换句话说,就是遍历所有调用了runAction方法的Node对象,执行其Action的step方法,传入的是每帧
逝去的时间,在处理完后,看这个action是不是完成了,完成了的话,就移除该action,在最后,如果该tHashElement的actions都没有action,就移除
该tHashElement,其中里面涉及的方法分析如下:
void ActionManager::removeAction(Action *action)
// explicit null handling
if (action == nullptr)
// 找到该action对应的tHashElement
tHashElement *element =
Ref *target = action-&getOriginalTarget();
HASH_FIND_PTR(_targets, &target, element);
if (element)
// 获得该action在actions的索引
auto i = ccArrayGetIndexOfObject(element-&actions, action);
if (i != CC_INVALID_INDEX)
// 移除该索引位的action
removeActionAtIndex(i, element);
CCLOG(&cocos2d: removeAction: Target not found&);
里面涉及的方法如下:
void ActionManager::removeActionAtIndex(ssize_t index, tHashElement *element)
Action *action = (Action*)element-&actions-&arr[index];
// 如果该action是当前处理的action,将该action retain一下,并设置
// currentActionSalvaged 标志
if (action == element-¤tAction && (! element-¤tActionSalvaged))
element-¤tAction-&retain();
element-¤tActionSalvaged =
// 这里释放该索引位置的action,并拼合剩下action的位置关系
// 注意最后的参数传了true,说明要清理对象
ccArrayRemoveObjectAtIndex(element-&actions, index, true);
// 当前索引并移除,后面索引前移来填充,所以循环索引要回退。
// 仅仅也只有等于的情形吧
// update actionIndex in case we are in tick. looping over the actions
if (element-&actionIndex &= index)
element-&actionIndex--;
// 移除该索引后,actions里没有action里
if (element-&actions-&num == 0)
// 当前处理的element,就是移除action所属的tHashElement
// 意味这个tHashElement没有action了,标志其要移除出_targets
if (_currentTarget == element)
// 是当前处理的tHashElement,暂缓移除,标志一下
_currentTargetSalvaged =
// 如果element不是当前处理的tHashElement,就直接移除
deleteHashElement(element);
void ccArrayRemoveObjectAtIndex(ccArray *arr, ssize_t index, bool releaseObj/* = true*/)
// 要不要清理该对象
CCASSERT(arr && arr-&num & 0 && index&=0 && index & arr-&num, &Invalid index. Out of bounds&);
if (releaseObj)
CC_SAFE_RELEASE(arr-&arr[index]);
// actions个数减一
arr-&num--;
// 该位置移除,后面的填上
ssize_t remaining = arr-&num -
if(remaining&0)
memmove((void *)&arr-&arr[index], (void *)&arr-&arr[index+1], remaining * sizeof(Ref*));
至此,ActionManager部分,就是Aciton的框架部分,分析至此,脉络已经出来了,就是Scheduler驱动着这一切,我们只要调用runAction,
将Action交给ActionManager就好了,
【Action篇】
下面分析一下action的体系,action的怎样实现,造就了如此丰富的action效果,
下面是我重新摘除重点的action类定义
class CC_DLL Action : public Ref, public Clonable
/** returns a clone of action */
virtual Action* clone() const = 0;
/** returns a new action that performs the exactly the reverse action */
virtual Action* reverse() const = 0;
//! called before the action start. It will also set the target.
virtual void startWithTarget(Node *target);
//called after the action has finished. It will set the 'target' to nil.
virtual void stop();
//! called every frame with it's delta time. DON'T override unless you know what you are doing.
virtual void step(float dt);
For example:
- 0 means that the action just started
- 0.5 means that the action is in the middle
- 1 means that the action is over
virtual void update(float time);
protected:
*_originalT
/** The &target&.
The target will be set with the 'startWithTarget' method.
When the 'stop' method is called, target will be set to nil.
The target is 'assigned', it is not 'retained'.
/** The action tag. An identifier of the action */
透露了几个信息
1、该类继承自Clonable
class CC_DLL Clonable
/** returns a copy of the Ref */
virtual Clonable* clone() const = 0;
virtual ~Clonable() {};
就是定了克隆的接口,由于action的使用很频繁,所有有克隆是一个很重要的特性,
2、有reverse接口,说明reverse也是一个常备的特性,一个动作常常提供反转动作,但是也不是都会实现这个反转。
3、step是框架调用的,自己实现要慎重,后面会分析到,这个接口基本可以不用重载。
4、action的成员变量,就是有一个原始目标,还有一个目前目标,而且注明该目标是简单的赋值,不负责维护引用
这个action是个抽象类,规定了一些接口,用来为ActionManager提供操作接口。
下面看看最常用的有限时间动作,我摘除重要的部分如下:
class CC_DLL FiniteTimeAction : public Action
protected:
//! duration in seconds
其实就是增加了一个时间段。而且还是一个抽象类,没有什么具体作用,下面看看他的具体应用,区间动作(ActionInterval)
class CC_DLL ActionInterval : public FiniteTimeAction
// 实现了完成的条件,就是逝去时间大于动作区间
virtual bool isDone(void)
// 这里需要分析下,他是reverse实现的基础
virtual void step(float dt)
protected:
这里要注意下step的实现
void ActionInterval::step(float dt)
// 第一次调用,初始化下
if (_firstTick)
_firstTick =
// 逝去时间初始化
_elapsed = 0;
// 记录逝去的时间和
_elapsed +=
// 这个表达式表达就是,update的参数,就是逝去的时间在整个动作
// 时间的比例,而不是时间间隔了。
// _elapsed = 0,就是update(0)
// _elapsed = _duration 就是update(1)
this-&update(MAX (0,
// needed for rewind. elapsed could be negative
MIN(1, _elapsed /
MAX(_duration, FLT_EPSILON)
// division by 0
下面分析个实例吧,Repeat的实现
Repeat的辅助数据如下:
protected:
// 需要重复次数
unsigned int _
// 已重复次数
unsigned int _
// 重复动作时间占比,用于统计_total,
float _nextDt;
// 标记该动作是不是瞬时动作
bool _actionI
/** Inner action */
// 重复的动作
FiniteTimeAction *_innerA
具体说明都在注释上
void Repeat::startWithTarget(Node *target)
// 初始化已重复次数
_total = 0;
// 本动作在总时间的占比
_nextDt = _innerAction-&getDuration()/_
ActionInterval::startWithTarget(target);
// 内部动作也初始化下对象
_innerAction-&startWithTarget(target);
核心实现update,如下:
void Repeat::update(float dt)
// 当前时间比例,已经超过一次动作的时间比例
if (dt &= _nextDt)
// 出现这种情况,只有卡的情况吧,
// 时间比例超了动作时间占比,而次数又没有到目标
while (dt & _nextDt && _total & _times)
// 目标动作直接更新完成
_innerAction-&update(1.0f);
// 已重复次数增加
// 动作停止接着又开始,保证目标动作的回调函数都调用到
_innerAction-&stop();
_innerAction-&startWithTarget(_target);
// 重算下次目标占比
_nextDt = _innerAction-&getDuration()/_duration * (_total+1);
// 总时间占比完成,但是次数没有达到,一般是临界情况
// fix for issue #1288, incorrect end value of repeat
if(dt &= 1.0f && _total & _times)
// don't set an instant action back or update it, it has no use because it has no duration
if (!_actionInstant)
if (_total == _times)
_innerAction-&update(1);
_innerAction-&stop();
else // 最后一帧让他执行完
// issue #390 prevent jerk, use right update
_innerAction-&update(dt - (_nextDt - _innerAction-&getDuration()/_duration));
// 目标动作执行update(单动作的时间占比),
_innerAction-&update(fmodf(dt * _times,1.0f));
以上,就是action的一点点分析,希望对大家有点帮助。
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467142',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'Cocos2D-X《欢乐麻将》手游完整源码,Cocos2D-X,游戏源码,6m5m游戏素材
请求处理中...
Cocos2D-X《欢乐麻将》手游完整源码,Cocos2D-X引擎,源码仅供学习研究,禁止用于商业用途。
或 50 积分 ()
下载134浏览人数10951交付方式直接下载
注意:【1】本站只是个免费分享平台,并不敢保证所有源码人人都能编译,因素太多,旨在学习研究,如果您有顾虑或斤斤计较就请不要下载了,大家都不容易,互相理解,才能让更多的好资源出现!【2】本站资源仅限于学习研究,请在下载后24小时内删除,不要用于任何商业用途。【3】部分素材压缩包因体积过大而上传到百度等网盘上,如果发现在本站下载的压缩包只要有几K大小,说明该压缩包里只是网盘的下载链接,并非文件损坏,本站的所有素材都是经过了审核,大家可放心下载,欢迎监督反馈。【4】做个好平台真心不容易,我们一直在努力,因本站素材量大,难免会出现某网盘下载链接失效等问题,请大家及时反馈,我们会及时修正保证您可以拿到素材,请大家支持和理解!
免责声明:本网所展示的素材与服务信息由***双方自行提供,其真实性、准确性和合法性由信息发布人负责。本网不提供任何保证,并不承担法律责任,如有不妥之处请及时反馈,本网将会妥善处理。
友情提醒:本站旨在提供游戏素材的分享与交流,所展示的素材版权归原作者或公司所有,如果本站素材侵犯了您的权益,请与联系我们,我们将及时处理。
您可能感兴趣的同类素材
5金币 / 个
1金币 / 个
2金币 / 个
0金币 / 个
1金币 / 个
1金币 / 个
好评率100%

参考资料

 

随机推荐