剖析cocos2d-x之Action实现

cocos2d-x中的动作分析 在cocos2d-x中动作的执行调度是受cocos2d-x的全局定时器控制的 阅读详情

稍微了解cocos2d-x的朋友应该都知道cocos2d-x里面的动作都是通过CCAction的各种派生类来实现的。

比如我要将一个Sprite在1秒内从(0,0)移动到(400,400)

pSprite->setPosition(ccp(0,0));

CCMoveTo* moveTo = CCMoveTo::create(1.0f,,ccp(400,400));

pSprite->runAction(moveTo);

那么,让我们来看看Action在cocos2d-x到底是如何实现的。

首先必须要了解的几个类

1.CCAction和CCActionInterval

CCAction是所有动作的基类,从代码里可以看出它本身并不执行动作

void CCAction::update(float time)

{

    CC_UNUSED_PARAM(time);

    CCLOG("[Action update]. override me");

}

他的作用只是提供一部分接口,如stop,update等等,其本身的实际作用并不是太大

CCActionInterval反而相对重要些,这个是大部分常用动作的基类,如常用的CCMoveTo,CCRotateBy等都是继承自CCActionInterval,CCActionInterval还有很重要的一点就是他实现了step方法,这个方法是大部分其派生类更新动作的基础(后文会有讨论)

2.CCActionManager

从名字可以看出,这个类负责管理着所有的动作,

前面代码里的pSprite->runAction(moveTo);其实就是将moveTo这个Action和pSprite这个Node加入到了CCActionManager内部维护的m_pTargets的这个hash表中

看看代码:

  CCAction * CCNode::runAction(CCAction* action)
  {
      CCAssert( action != NULL, "Argument must be non-nil");
      m_pActionManager->addAction(action, this, !m_bIsRunning);
      return action;
  }

看看,内部是否是调用CCActionManager的addAction

接着我们再看看addAction的实现

  void CCActionManager::addAction(CCAction *pAction, CCNode *pTarget, bool paused)
  {
      CCAssert(pAction != NULL, "");
      CCAssert(pTarget != NULL, "");
  
      tHashElement *pElement = NULL;
      // we should convert it to CCObject*, because we save it as CCObject*
      CCObject *tmp = pTarget;
      HASH_FIND_INT(m_pTargets, &tmp, pElement);
      if (! pElement)
      {
          pElement = (tHashElement*)calloc(sizeof(*pElement), 1);
          pElement->paused = paused;
          pTarget->retain();
          pElement->target = pTarget;
          HASH_ADD_INT(m_pTargets, target, pElement);
      }
  
  
       actionAllocWithHashElement(pElement);
   
       CCAssert(! ccArrayContainsObject(pElement->actions, pAction), "");
       ccArrayAppendObject(pElement->actions, pAction);
   
       pAction->startWithTarget(pTarget);
  }

略去见面的Assert检查和后面的初始化设定不看,上面代码的大概意思就是将pAction(上文的moveTo),pTarget(上文的pSprite)加入到内部维护的m_Targets中,至于m_Targets到底是个什么东西我们可以不必深究,就理解为一个数组或者hash表就够了

贴出这个结构的源码,有兴趣的朋友可以看看

  typedef struct _hashElement
  {
      struct _ccArray             *actions;
      CCObject                  *target;
      unsigned int                actionIndex;
      CCAction                  *currentAction;
      bool                      currentActionSalvaged;
      bool                      paused;
      UT_hash_handle            hh;
  } tHashElement;

这里要注意的一点,一个target是可以附带多个Action的,从上面actions的类型是一个数组我们可以加以确认。

OK,一切都设置妥当,我们开始讲解最核心的update方法

首先要说明一点,这个CCActionManager的update是在CCDisplayLinkDirector的mainLoop->drawScene里调用m_pScheduler->update(m_fDeltaTime);中被调用的

m_pScheduler是CCScheduler类型,他负责系统全部子系统的更新,比如Touch,Action,脚本,定时器等等都在这里update,Action是在优先级 < 0的那个list里面的

好了,继续讨论update,还是先看看源码

  void CCActionManager::update(float dt)
  {
      for (tHashElement *elt = m_pTargets; elt != NULL; )
      {
          m_pCurrentTarget = elt;
          m_bCurrentTargetSalvaged = false;
  
          if (! m_pCurrentTarget->paused)
          {
              // The 'actions' CCMutableArray may change while inside this loop.
              for (m_pCurrentTarget->actionIndex = 0; 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 == 0)
          {
              deleteHashElement(m_pCurrentTarget);
          }
      }
  
      // issue #635
      m_pCurrentTarget = NULL;
  }

其实update的代码很简单,就是遍历m_pTargets数组(或者链表,hash,随你高兴,不过他实际是hash),然后逐个更新每个tHashElement 里面的动作,当然他会有一些判断,比如动作是否暂停,是否结束之类的,并做相应处理,不如终止了自然要remove掉。如果一切正常,那就调用动作的step方法(这里必须知道多态的概念哦,因为step和后面的update方法都是virtual的)。

前面讲过CCActionInterval有实现step方法,好的,现在我们再来看看他做了什么事情

  void CCActionInterval::step(float dt)
  {
      if (m_bFirstTick)
      {
          m_bFirstTick = false;
          m_elapsed = 0;
      }
      else
      {
          m_elapsed += dt;
      }
      
      this->update(MAX (0,                                  // needed for rewind. elapsed could be negative
                        MIN(1, m_elapsed /
                            MAX(m_fDuration, FLT_EPSILON)   // division by 0
                            )
                        )
                   );
  }

简而言之,就是根据传入的时间间隔(dt),增加m_elapsed(目前动作的执行到的位置),并将其处理在一个合法范围内(通过MAX,MIN宏),然后传给update方法,最后在update方法里面会进行实际的动作更新,接下来,我们以CCMoveTo为例,看看他的update是如何实现的

  void CCMoveTo::update(float time)
  {
      if (m_pTarget)
      {
          m_pTarget->setPosition(ccp(m_startPosition.x + m_delta.x * time,
              m_startPosition.y + m_delta.y * time));
      }
  }

看到了吧,他在这里就会根据他目前的elapse设置他所负责的Node的位置了。

大家有兴趣也可以看看其他动作,如Rotate,Jump之类,看看他们是如何来设置位置的。

OK,到此结束

由于本人才疏学浅,以上内容如有错误,欢迎大家多多斧正


Cocos2d-x实战:热血三国小游戏开发与性能优化全解析 游戏引擎是游戏开发的核心框架,它通过封装底层图形渲染、物理模拟和资源管理等模块,为开发者提供高效的开发工具链。其原理在于将复杂的底层操作抽象为易用的API,使开发者能专注于游戏逻辑与玩法设计。在技术价值上,优秀的引擎能显著提升开发效率、保障游戏性能,并支持多平台发布。尤其在2D游戏开发领域,引擎的渲染效率、内存管理和跨平台能力至关重要。常见的应用场景包括移动端休闲游戏、独立游戏开发和原型快速验证等。本文以Cocos2d-x引擎为例,结合**状态机**和**对象池**等关键技术,深入剖析其在实现中度复杂度2D 阅读详情

相关推荐

CocosBuilder全套开发支持包:CCB/CCBi格式详解、三端引擎对接与插件编写实战指南

面向使用CocosBuilder进行UI和场景可视化搭建的开发者,提供从零开始的完整技术支撑。包含新建项目流程、CCB与CCBi文件结构定义、属性类型说明、多分辨率适配策略、动画编辑操作要点、自动缩放机制与图集处理方法、JavaScript调试技巧等内容。覆盖cocos2d-x、cocos2d-iphone、Cocos2d-JS三大目标平台的集成步骤,明确各平台加载CCB资源的方式、兼容性注意事项及常见问题处理路径。同时提供节点插件与导出插件的开发规范,包括接口定义、生命周期钩子、数据序列化要求等关键细节。

q3r4s5t的博客 296

EngineErrorMap 错误码

EngineErrorMap.md Cocos Creator Engine Errors 0100 %s not yet implemented. 1000 cc.ActionManager.addAction(): action must be non-null 1001 cocos2d: removeAction: Target not found 1002 cc.ActionManager.removeActionByTag(): an invalid tag ...

wang_we的专栏 4858

Cocos2d-x高级游戏开发实战:魔塔源码深度解析

想加滤镜?灰度?发光?扭曲?靠贴图可不够,得上 Shader!// 传参数片元着色器示例(灰度混合):在“DevilTower”中可用于中毒变色、受击闪红等特效,视觉反馈拉满 💥。Cocos2d-x 虽然不像新一代引擎那样炫目,但它用扎实的架构、清晰的分层、高效的渲染和灵活的脚本系统,证明了什么叫“老而弥坚”。从跨平台抽象到内存管理,从场景图到动作系统,再到物理模拟——每一个模块都在为“快速交付高质量2D游戏”服务。

weixin_30591519的博客 749

Cocos2d-X中的CCAction

CCAction用于创建各种动作

meishadevs的个人博客 1488

基于Simulink的前馈解耦SVPWM整流器仿真

本文提出了一种基于Simulink的前馈解耦SVPWM整流器仿真方案,针对传统双闭环控制存在的耦合严重、电压利用率低等问题进行优化。通过前馈补偿dq轴耦合项(ωLiq和ωLid)结合SVPWM调制算法,实现了电流跟踪误差<3%、电压利用率达0.99、THD<3%的性能指标。文章详细阐述了系统架构设计,包括前馈解耦原理推导、SVPWM算法实现步骤,并提供了完整的Simulink建模方法。仿真结果表明,该方案在动态响应速度(25ms)和直流电压纹波(1.1%)方面显著优于传统SPWM控制。同时给出了

MHD0815的博客 162

别再只看图了!代谢组学OPLS-DA分析,R2Y和Q2Y到底怎么看才不踩坑?

本文深入解析代谢组学OPLS-DA分析中的关键指标R2Y和Q2Y,揭示如何避免过拟合陷阱。通过详细解读模型解释能力(R2Y)和预测能力(Q2Y),结合置换检验方法,提供完整的模型评估流程与实战建议,帮助研究者获得可靠的分析结果。

weixin_42638178的博客 196

Cocos2d-x动作CCAction

本文原创版权归 博客园 ArmyShen 所有,转载请详细标明原创作者及出处,以示尊重! 作者:ArmyShen 原文:http://www.cnblogs.com/ArmyShen/p/3239677.html   1、动作基本概念 CCAction是动作的基类,所有的动作都派生自此类。CCAction的一个对象就是一个动作,动作或动画只能由CCNode来执行 CCSprite*

优秀技术文章收录 1954

LS-DYNA超高速碰撞仿真入门:从SPH算法配置到铝靶板穿孔分析(附K文件模板)

本文详细介绍了使用LS-DYNA中的SPH(光滑粒子流体动力学)算法进行超高速碰撞仿真的完整流程。以铝弹丸撞击铝靶板为例,从SPH算法原理、LS-PrePost前处理、材料模型与状态方程设置,到接触定义、边界条件及K文件生成,提供了系统的入门指导和关键参数调试经验,帮助工程师高效模拟材料破碎、穿孔等极端变形问题。

h0i1j2k3l的博客 725

Cocos2d-x 2.0 之 Actions “三板斧” 之一

之前我们讲解了Cocos2d-x 中的TestCpp工程,它包含了43个小示例。每个示例都是通过Controller.cpp中的CreateTestScene函数创建的场景来进行演示的,从今天起,我们来详细学习每一个示例。今天我们来学习第一个示例:”ActionsTest”。            “ActionsTest”-- 这个工程要演示的是什么节目呢?它演示了精灵的各种动画。包

weihongchang的专栏 878

Jetson Orin NX上PyTorch环境搭建与性能优化指南

本文详细指导如何在Jetson Orin NX上搭建高效的PyTorch开发环境。内容涵盖CUDA与cuDNN的“隐藏”配置、Miniconda虚拟环境管理、PyTorch for Jetson的正确安装与验证,并提供了电源模式设置、TensorRT加速、混合精度等关键性能优化实战技巧,帮助开发者充分释放边缘AI设备的算力。

weixin_29090089的博客 337

Argoverse2数据集保姆级导入教程:从下载到预处理全流程解析

本文详细解析了Argoverse2数据集的完整导入流程,从环境配置、数据下载到预处理和高效加载策略。作为自动驾驶领域的标杆数据集,Argoverse2提供多模态传感器数据和高精地图信息,帮助研究者快速搭建数据处理流水线。文章包含实用代码示例和性能优化技巧,特别适合自动驾驶算法开发者参考。

weixin_29035405的博客 332

cocos2dx - ActionManager内存泄露

ActionManager memory leak cocos2d-x3.7 都3.7了还有这样的bug,真是好难过,不过还是好开源的,谁都可以贡献一下 问题描述: 当创建一个node,并让它run一个action的时,如果这个node没有添加到任何其它节点(即没有父节点),那么改node和action将一直不会被释放。 原因: 在node调用runAction时,会将动画交给ActionMa...

weixin_34092455的博客 101

如何提高电路的抗干扰能力

本内容详细介绍了电源传导干扰处理,包括滤波、Feedthrough电容器、磁环、磁珠、屏蔽的使用与选型,EMC电磁兼容测试项目简介与要求,单片机与电源抗干扰处理等。

让你爱上电路设计 8595

cocos2d-x 源码剖析(9)

上一节讲了ActionManager,这节就顺势讲讲Action吧。下面是Action的继承图,这个结构看起来有点不对称,我也想不透作者是基于这种理由这样设计的,或许阅读晚源码之后会有所了解吧:   我们先从最简单的CCMove开始讲起。可以知道,CCMove继承至ActionInterval。ActionInterval有个特点,需要在一段时间内不断的调用step函数。与之对

姚大头 804

098、C3k2_Ghost:用 GhostConv 替代 C3k2 内标准卷积的轻量化改造代码

本文介绍了用GhostConv轻量化改造YOLOv11中C3k2模块的实践。作者通过线上部署案例引出问题,详细解析了GhostConv的核心实现逻辑,指出直接替换标准卷积会导致的两个关键问题:通道数不匹配和kernel_size冲突。文章提供了完整的C3k2_Ghost实现代码,包含注意事项和调试技巧。消融实验显示,该方法在小模型上可减少27%-28%参数量、34%-35%FLOPs,仅损失0.8mAP。作者总结了适用场景:小模型效果显著,大模型需谨慎;检测小目标任务不推荐;训练时需调整学习率。最后强调sh

sundong_81的博客 62

【考研复试】西安电子科技大学上机题

【考研复试】西安电子科技大学上机题

全网粉丝30W+,优快云、稀土掘金人工智能领域签约作者,人工智能、大模型、Python 爬虫,商务合作,请私信沟通。 1737

Cocos2d-x Lua库函数剖析(三)Cocos2dConstants

这部分主要是cocos2d-x在Lua下的常量定义,有兴趣的可以看看。 cc = cc or {} cc.SPRITE_INDEX_NOT_INITIALIZED = 0xffffffff cc.TMX_ORIENTATION_HEX = 0x1 cc.TMX_ORIENTATION_ISO = 0x2 cc.TMX_ORIENTATION_ORTHO = 0x0 cc.Z_COM...

qq_39218906的博客 566

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Cocos2d-x Lua库函数剖析(六)functions

这部分主要是封装了一些会常用的函数,比如printLog,等。 先上源码 --[[ Copyright (c) 2011-2014 chukong-inc.com Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated docu...

qq_39218906的博客 574

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

cocos2d-x 源码剖析(14)

今天大老板看我加班辛苦,不由上来教育一番,我等屌丝立马重树三观。后又老爸介绍一相亲对象,虽说无甚期待也足够让想象里驰骋会儿了。心情略好,嗯来一篇吧。为了接上思路,我把前面几章看了一遍。自己水平不够,国语稀烂,新手要看懂确实不容易,老手也没必要看了。哈哈,略显尴尬。看个大概就可以了。 好吧言归正传,自上一篇讲完Touch之后cocos2d-x的主逻辑就没什么类容了。我来整理下: co

姚大头 893

Cocos2d-x游戏引擎入门:从核心概念到实战开发全解析

游戏引擎是现代游戏开发的核心工具,它通过封装底层图形渲染、物理模拟、音频处理等复杂系统,为开发者提供高效的创作框架。其工作原理基于场景图管理、资源调度和事件驱动机制,旨在降低开发门槛并提升跨平台部署能力。在技术价值层面,优秀的引擎能显著优化性能、简化工作流,并支持快速迭代。尤其在2D游戏和移动端领域,对轻量级、高性能解决方案的需求持续增长。Cocos2d-x作为一款经典的C++开源跨平台引擎,凭借其开源免费、社区活跃的特性,在移动游戏开发中占据重要生态位。它通过场景、节点、精灵、动作等核心模块,帮助开发者高

weixin_33698043的博客 406

cocos2d-x 源码剖析(11)

好久没用动笔写博客了,今天是1024节,还是要表示下。而且今天检查邮箱发现了5个垃圾评论,觉得很高兴,也要来篇文章庆祝下。哈哈。 时间隔得太久,我都不记得我讲到那里来了。原来是打算将几个特殊点的Action为大家结尾,最后一看源码,发现有点杂乱,待我整理好之后再写。今天来讲一讲CCScheduler。之前讲过,在ActionManager创建出来之后立马就加入到CCScheduler中去了,然后

姚大头 837

Cocos2d-x 2.x图层特效:2D游戏视觉增强的核心原理与性能优化实战

在2D游戏开发中,视觉特效是提升游戏表现力的关键技术。其核心原理在于通过实时处理渲染后的像素数据,改变画面的几何形态与色彩表现,从而实现扭曲、闪烁、色彩变换等效果。这种技术为移动端游戏提供了一种高性能的视觉增强方案,尤其适用于资源受限但追求打击感与氛围感的项目。从实现层面看,特效主要分为基于网格变形的几何特效(如波浪、漩涡)和基于颜色通道的视觉特效(如闪烁、淡入淡出),它们通过作用于节点渲染管线,以可控的性能开销创造丰富的动态视觉效果。在实际应用中,图层特效常与粒子系统、骨骼动画结合,用于营造场景氛围(如熔

weixin_34279246的博客 371

cocos2d-x 源码剖析(10)

上一节讲CCActionInterval,这节讲CCActionInstant。同样为了方便,我们用CCPlace来讲解。作为了解过CCActionInterval的过来人来说,CCActionInstant意外的简单。还记得这两种Aciton之间的区别吗?前者需要一个duration,而后者调用一次就介绍了,自然也不用什么持续时间了。翻看源码,可以发现CCActionInstant和CCActi

姚大头 883

AndEngine与Cocos2d-x深度对比:2D游戏引擎选型实战指南

在移动游戏开发中,游戏引擎是构建项目的核心框架,其架构设计直接决定了开发效率与最终性能表现。引擎通过封装底层图形API(如OpenGL ES)和提供场景管理、物理模拟等模块,简化了游戏开发流程。理解引擎的渲染原理、内存管理机制和跨平台实现方式,对于优化游戏性能、避免常见问题(如Cocos2d游戏黑屏)至关重要。从技术价值看,合适的引擎能降低开发成本,提升代码可维护性,并保障项目长期稳定运行。在2D手游、微信小游戏等应用场景中,开发者常面临在轻量级原生引擎与功能丰富的跨平台引擎间的抉择。本文聚焦于AndEng

weixin_33675507的博客 376

Cocos2d-x实战:从零实现合成大西瓜游戏核心逻辑与优化

在2D游戏开发中,物理碰撞检测和对象池管理是提升性能与体验的核心技术。碰撞检测原理涉及几何计算与空间划分算法,如网格法,能有效减少计算复杂度,避免O(n²)的性能瓶颈。对象池通过复用游戏对象,减少内存分配与回收开销,是优化内存管理的经典设计模式。这些技术的工程价值在于保障游戏流畅运行,尤其在休闲类游戏中至关重要。本文以热门游戏“合成大西瓜”为应用场景,深入剖析如何基于Cocos2d-x引擎,自研轻量级碰撞系统并实现高效对象池,从而构建稳定可扩展的游戏架构。

weixin_30561177的博客 403

Cocos2d-x老兵实战:从引擎原理到商业级项目优化

在游戏开发领域,引擎原理与性能优化是构建高质量应用的核心基础。理解渲染管线、内存管理机制和跨平台架构,能够帮助开发者从底层掌握技术主动权,避免成为单纯的功能调用者。Cocos2d-x作为一款经典的2D游戏引擎,其价值在于提供了对底层图形API和C++运行时的深度控制能力,尤其适合追求极致性能、包体控制和代码透明度的项目。通过系统学习其渲染优化(如Draw Call合并、纹理管理)和内存管理艺术(如引用计数、循环引用处理),开发者可以将这些通用方法论应用于实际的游戏开发中,有效解决卡顿、闪退等常见性能问题,并

weixin_30326741的博客 550
上一篇: CCAnimation直接create报错分析
下一篇: 移植VC6工程到VS时for循环出错解决方案
RabbitLBJ
博客等级 码龄18年 46粉丝 47原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值