【源码分析】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 的定时调用, 这里调用了函数 ...
随机推荐
- Math.round、Math.floor、Math.ceil 区别
1.Math.round() 按照四舍五入的方式返回值 例如:Math.round(9.5)=10 Math.round(9.4)=9 2.Math.floor()返回最小整数 例如:Math. ...
- Java万年历,输入年月获取该年月日历表
//输入年份和月份,打印出这个月的日历表 /* 1.1900年1月1日是星期一 2.计算输入的年份距离1900年有多少天再计算当年1月1日距这个月有多少天 1) 3.总天数%7得出从星期几开始 注:计 ...
- clojure学习笔记(一)
下载地址 需要安装xmind打开 http://pan.baidu.com/s/1dDxKj1B
- 【Css】一个简单的选项卡
这次来做一个简单的选项卡. 选项卡其实就分3个部分:html代码,用于显示的内容:css代码,用于显示的样式:javascript代码,用于点击事件. 老规矩,先写一个html坯子. <!DOC ...
- D3学习笔记一
D3学习笔记一 什么是D3? D3(全称Data Driven Documents)是一个用来做Web数据可视化的JavaScript函数库.D3也称之为D3.js. D3是2011年由Mike Bo ...
- 计算两个NSDate之间,相隔多少秒数
计算两个NSDate之间,相隔多少秒数 //两个时间间隔秒数 - (NSInteger)intervalSecondsWithSmallDate:(NSDate*)smallDate bigDate: ...
- Amoeba+Mysql 实现读写分离
About Amoeba Amoeba可译为阿米巴.变型虫Amoeba是一个开源项目,致力于Mysq的分布式数据库前端代理层Amoeba是一个以MySQL为底层数据存储,并对应用提供MySQL协议接口 ...
- FZU 2139——久违的月赛之二——————【贪心】
久违的月赛之二 Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Submit Stat ...
- python-入门教程(操作mysql数据库)
pymsql是Python中操作MySQL的模块,其使用方法和MySQLdb几乎相同.但目前pymysql支持python3.x,而MySQLdb不支持3.x版本. 本文测试python版本:3.6. ...
- Go.网络篇-2
package main import ( "io/ioutil" "os" "io" "log" "net/ ...