【源码分析】cocos2dx的Action
第一次去学习Action,总会找到一篇入门的帖子(官网:http://cn.cocos2d-x.org/article/index?type=cocos2d-x&url=/doc/cocos-docs-master/manual/framework/native/v3/action/zh.md)。也会初步了解Action是怎么用的?
*创建动作对象,eg:移动、旋转等
*调用Node的runAction函数,这个动作就表现出来了
auto actionTo = MoveTo::create(, Vec2(s.width-, s.height-));
auto actionBy = MoveBy::create(, Vec2(,));
auto actionByBack = actionBy->reverse(); _tamara->runAction( actionTo);
_grossini->runAction( Sequence::create(actionBy, actionByBack, nullptr));
_kathia->runAction(MoveTo::create(, Vec2(,)));
So Easy!但是,但是,看完之后你会有一溜的问题!
(1)类结构中即时动作和持续动作在原理上有什么不同?
(2)FiniteTimeAction、Follow和Speed这两个是干嘛的?尤其是后面两个。
(3)Action工作的一个原理是什么?
然而,还有一个一开始容易被忽视的问题,但是你去看了之后才发现有很多技术或者知识细节需要去弄明白,再加一个问题:
(4)不管是即时动作(ActionInstant)还是ActionInterval(持续动作)里面包含了许多动作类,他们表现上的差异在原理上有什么不同?如何实现的?
*友情提示*上面的问题记得看一篇入门文章,后面的内容并不一定按照上面问题的顺序和分节去讲,只是按照自己学习的思路记录一下,增强自己的记忆和梳理一些遗漏的知识点,如果能帮助一些和我一样的菜鸟朋友,权当无心插柳!^_^
----------------------------------------------------------------------------------------------------------------------------------------------------------
--下面进入高能阶段--
----------------------------------------------------------------------------------------------------------------------------------------------------------
一、Action的原理
看cocos提供的例子,很容易理解一些基本的动作,比如move、rotate、jump等,但是当你看源码的时候,你是想知道,这个整体的逻辑是怎么设计和实现的,先上Action的流程图,如下所示:

1.流程图解析
(1)没有方框的名字是类名,eg:Director, Scheduler,ActionManager,Action,Timer等
(2)没有方框但是带有‘*’开头的是旁白,为了帮助自己记忆和更容易看明白
(3)有颜色的的都是自己觉得比较重要的关键点,当然其他细节也需要弄明白,一些表示状态的标记等
* 两条蓝色的箭头是Scheduler(看调度器时候重要)调用update函数的地方,所以不管是动作的ActionManager还是定时器的Timer,主要逻辑都还是在update中完成的
* 紫色的step函数是Action的逻辑主要完成地方,但是由于Action是基类。最后各个动作都是继承的Action,但是没有重载step函数,所以基类Action中的step是调用了update函数的,因此你可以看到多数动作的逻辑是自己重载update函数完成的,而为什么要有step呢?那是因为有些类是需要重载step的,他不需要update,可以看Follow和Speed的源码。
void Follow::step(float dt)
{
CC_UNUSED_PARAM(dt); if(_boundarySet)
{
// whole map fits inside a single screen, no need to modify the position - unless map boundaries are increased
if(_boundaryFullyCovered)
return; Vec2 tempPos = _halfScreenSize - _followedNode->getPosition(); _target->setPosition(Vec2(clampf(tempPos.x, _leftBoundary, _rightBoundary),
clampf(tempPos.y, _bottomBoundary, _topBoundary)));
}
else
{
_target->setPosition(_halfScreenSize - _followedNode->getPosition());
}
}
当然,也可以这么理解:由于连续性动作需要时间上有个计时器的概念,所以他需要每隔一段时间update,而其他类不需要,只要把逻辑写在step里面就可以了,所以需要一个step和update的层次概念,这样是不是很好理解了呢?(clever!^_^)
* 各个真正使用的动作类(如Move、Jump等)都是重载了update函数的,那么update干嘛了呢?只有update函数这里有差异,所以update是区分各个动作的关键所在!来看一个简单的动作代码(MoveBy):
void MoveBy::update(float t)
{
if (_target)
{
#if CC_ENABLE_STACKABLE_ACTIONS
Vec2 currentPos = _target->getPosition();
Vec2 diff = currentPos - _previousPosition;
_startPosition = _startPosition + diff;
Vec2 newPos = _startPosition + (_positionDelta * t);
_target->setPosition(newPos);
_previousPosition = newPos;
#else
_target->setPosition(_startPosition + _positionDelta * t);
#endif // CC_ENABLE_STACKABLE_ACTIONS
}
}
稍微看一下就明白了,他只做了一件事情,就是设置节点(_target是node对象,例如一个精灵Sprite)的位置。有点乱~,往前看,这里看下连续性动作ActionInternal的代码,再联系上这里的update
void ActionInterval::step(float dt)
{
if (_firstTick)
{
_firstTick = false;
_elapsed = ;
}
else
{
_elapsed += dt;
} this->update(MAX (, // needed for rewind. elapsed could be negative
MIN(, _elapsed /
MAX(_duration, FLT_EPSILON) // division by 0
)
)
);
}
看到了没?每一帧都会调用update函数,而update函数的参数是一个比例值_elapsed/MAX(_duration, FLT_EPSILOW)。去掉一些MIN、MAX等宏(防止除数为0等的情况),很容易看明白这个比例表示了当前时间点在整个持续动作过程的某个位置(注:这里的update参数和scheduler中的update参数意义不一样,step的参数和scheduler中的update参数是一个意义)!
那么一个宏观的逻辑就算是比较清晰了,那么发散思维一下:如果是Jump呢?他的update做了什么呢?同样的也是setPosition,只不过不近要处理水平坐标,还要处理纵坐标;Scale呢?就是直接设置Node(eg:精灵Sprite)的scale,(eg:setScaleX,setScaleY)...
(4)Timer中红色方框边缘的节点表示的是关键函数,这里面执行的就是定时器传进来的函数参数。
(5)深绿色方框边缘的判断语句“时间到”只是表示他们都是一样的:_elapsed >= _interval,看源代码也很好理解。命名很赞!
2. cocos文件
cocos中的文件很好找,在工程里面libcocos2d/2d目录下面一开始就可以看到一槽排的CCActionXXX.h和CCActionXXX.cpp文件,具体自己去看吧。(个人版本:cocos2dx-3.2)
3. 问题
4. 总结
(1)整体理解一下,Action是一系列不同的对象,绑定Node。ActionManager维护一个hash表,并且每帧处理!
(2)跳出来看,每一个Action就是让Node做某件事情,也就是设定Node的某项属性。如果是即时动作,这立马执行。如果是持续性动作,就是每帧去处理节点的属性,因为牵涉到时间概念,所以有一个简单的计算过程(比例值的计算)。
---先到这里---后面继续记录>>>
----------------------------------------------------------------------------------------------------------------------------------------------------------
二、各种动作详细解读
【源码分析】cocos2dx的Action的更多相关文章
- cocos2dx骨骼动画Armature源码分析(一)
源码分析一body { font-family: Helvetica, arial, sans-serif; font-size: 14px; line-height: 1.6; padding-to ...
- Struts2 源码分析——DefaultActionInvocation类的执行action
本章简言 上一章讲到关于拦截器的机制的知识点,让我们对拦截器有了一定的认识.我们也清楚的知道在执行用户action类实例之前,struts2会先去执行当前action类对应的拦截器.而关于在哪里执行a ...
- Struts2 源码分析——Action代理类的工作
章节简言 上一章笔者讲到关于如何加载配置文件里面的package元素节点信息.相信读者到这里心里面对struts2在启动的时候加载相关的信息有了一定的了解和认识.而本章将讲到关于struts2启动成功 ...
- Struts2 源码分析——调结者(Dispatcher)之执行action
章节简言 上一章笔者写关于Dispatcher类如何处理接受来的request请求.当然读者们也知道他并非正真的执行action操作.他只是在执行action操作之前的准备工作.那么谁才是正真的执行a ...
- 【Cocos2d-x 3.x】 事件处理机制源码分析
在游戏中,触摸是最基本的,必不可少的.Cocos2d-x 3.x中定义了一系列事件,同时也定义了负责监听这些事件的监听器,另外,cocos定义了事件分发类,用来将事件派发出去以便可以实现相应的事件. ...
- Cocos2dx源码赏析(4)之Action动作
Cocos2dx源码赏析(4)之Action动作 本篇,依然是通过阅读源码的方式来简单赏析下Cocos2dx中Action动画的执行过程.当然,这里也只是通过这种方式来总结下对Cocos2dx引擎的理 ...
- [转帖]cocos2D-X源码分析之从cocos2D-X学习OpenGL(3)----BATCH_COMMAND
原贴: cocos2D-X源码分析之从cocos2D-X学习OpenGL(3)----BATCH_COMMAND 上一篇介绍了QUAD_COMMAND渲染命令,顺带介绍了VAO和VBO,这一篇介绍批处 ...
- [转帖]cocos2D-X源码分析之从cocos2D-X学习OpenGL(2)----QUAD_COMMAND
原文:cocos2D-X源码分析之从cocos2D-X学习OpenGL(2)----QUAD_COMMAND 上一篇文章介绍了cocos2d-x的基本渲染结构,这篇顺着之前的渲染结构介绍渲染命令QUA ...
- 5 cocos2dx 3.0源码分析 渲染 render
渲染,感觉这个挺重要了,这里代入一个简单的例子 Sprite 建立及到最后的画在屏幕上, 我们描述一下这个渲染的流程: 1 sprite 初始化(纹理, 坐标,及当前元素的坐标大小信息) 2 主循 ...
- 3 cocos2dx 3.0 源码分析-mainLoop详细
简述: 我靠上面图是不是太大了, 有点看不清了. 总结一下过程: 之前说过的appController 之后经过了若干初始化, 最后调用了displayLinker 的定时调用, 这里调用了函数 ...
随机推荐
- 2019.04.19 读书笔记 比较File.OpenRead()和File.ReadAllBytes()的差异
最近涉及到流的获取与转化,终于要还流的债了. 百度了一下,看到这样的两条回复,于是好奇心,决定看看两种写法的源码差异. 先来看看OpenRead() public static FileStream ...
- vue element 常见问题
1. vue2.0 给data对象新增属性,并触发视图更新 $set this.$set(this.ossData, "signature", 222) // 正确用法 // 数 ...
- APP的功能分类及打包与发布的分类方式
智能手机的出现改变了我们的生活,同时各种各样的APP充斥在我们的手机当中.那么我先现在在来熟悉一下APP的分类及其用途:工具类.社交类.信息类.娱乐类.生活类等几大类.我么了解了APP的用途分类,那么 ...
- APP开发的三种技术对比
目前来说主流的App开发方式有三种:Native App .Web App.Hybird App.下面我们来分析一下这三种App开发方式的优劣对比: 一 :Native App 即 原生App开发 优 ...
- 对Map的一些总结
1:Map接口. Collection体系中存储的是单个元素,单身汉,而Map中存储的是2个元素,存储的是成对的元素. Map和Collection是没有联系的!!不要以为Map是Collection ...
- windows下限制Redis端口只能由本机访问
在使用redis的时候,我只想要本机能够访问,这时可通过防火墙会阻止外界的访问 1.找到防火墙,选择高级设置2.点击"入站规则",再点击"新建规则" 3.点击& ...
- r.js 配置文件 example.build.js 不完整注释
/* * This is an example build file that demonstrates how to use the build system for * require.js. * ...
- html控件
checkbox val = "<li class='layer'><label><input type='checkbox' checked name='la ...
- WEB项目构建优化之自动清除CSS中的图片缓存
在web项目构建发布时,经常遇到css中图片的修改优化,那么如何清除图片的缓存成为必须要解决的问题.曾经有过傻傻的方法就是直接在图片后面添加随机数.今天主要是从构建自动化方式来解决这个问题,提高开发及 ...
- angular 与 layer 集成过程
layer 的提示框和弹层确实也好用,在使用angular的前提下,使用layer遇到诸多麻烦,记录下来. 在类型是1页面层,主要问题在遮罩方面,造成无法编辑. 开始:引入layer 样式,angul ...