cocos2dx2.0 帧动画的创建和播放过程 深入分析
一、帧动画的创建过程
帧动画的实现有四个不可或缺的类,如下:
1.CCSpriteFrame:精灵帧信息。存储帧动画的每一帧的纹理基本信息。
class CC_DLL CCSpriteFrame : public CCObject
{
public:
//函数略...
protected:
CCPoint m_obOffset; // 去掉纹理块空白后所导致的锚点偏移
CCSize m_obOriginalSize; // 纹理块的原始大小(未去掉空白的大小)
CCRect m_obRectInPixels; // 纹理块的大小(像素单位)
bool m_bRotated; // 矩形块是否旋转
CCRect m_obRect; // 纹理块
CCPoint m_obOffsetInPixels; // 去掉纹理块空白后所导致的锚点偏移(像素单位)
CCSize m_obOriginalSizeInPixels; // 纹理块的原始大小(像素单位)
CCTexture2D *m_pobTexture; // 图集纹理
std::string m_strTextureFilename; // 对应的图集图片
};
2.CCAnimationFrame:序列帧动画单帧信息,我们把它叫做动画帧。存储了精灵帧信息和单帧信息(持续帧数和附加数据)。
class CC_DLL CCAnimationFrame : public CCObject
{
public:
//函数略... // 定义一个精灵帧成员指针变量m_pSpriteFrame,代表当前动画帧所对应的精灵帧。
CC_SYNTHESIZE_RETAIN(CCSpriteFrame*, m_pSpriteFrame, SpriteFrame) // 注意:
// 此序列帧动画单帧持续的帧数(如果m_fDelayUnits为5,则这一动画帧连续播放5帧)
CC_SYNTHESIZE(float, m_fDelayUnits, DelayUnits) // 定义一个词典成员指针变量m_pUserInfo
CC_SYNTHESIZE_RETAIN(CCDictionary*, m_pUserInfo, UserInfo)
};
3.CCAnimation:序列帧动画信息。存储了帧动画需要的所有单帧信息和对单帧信息的管理。
class CC_DLL CCAnimation : public CCObject
{
public:
//函数略... // 总帧数
// 只读属性,不能人为设置
// 因为 总帧数为所有动画帧的持续帧数之和
// m_fTotalDelayUnits = animationframe1->getgetDelayUnits() + animationframe2->getgetDelayUnits() + ...
// 注意:这里的总帧数和图片数是两个概念,一幅图片可能连着播放多帧,
// 帧:刷新的次数单位
// 动画帧:对应一幅图片
CC_SYNTHESIZE_READONLY(float, m_fTotalDelayUnits, TotalDelayUnits) // 每两帧间的时间间隔
CC_SYNTHESIZE(float, m_fDelayPerUnit, DelayPerUnit) // 动画总时间
CC_PROPERTY_READONLY(float, m_fDuration, Duration) // 保存所有动画帧
CC_SYNTHESIZE_RETAIN(CCArray*, m_pFrames, Frames) // 是否在动画结束时恢复至初始帧
CC_SYNTHESIZE(bool, m_bRestoreOriginalFrame, RestoreOriginalFrame) // 循环播放次数
CC_SYNTHESIZE(unsigned int, m_uLoops, Loops)
};
4.CCAnimate:序列帧动画处理类。利用序列帧动画信息类CCAnimation运行动画。
class CC_DLL CCAnimate : public CCActionInterval
{
public: // 初始化动画
bool initWithAnimation(CCAnimation *pAnimation); // 重载基类的相应函数
virtual CCObject* copyWithZone(CCZone* pZone);
virtual void startWithTarget(CCNode *pTarget);
virtual void stop(void);
virtual void update(float t);
virtual CCActionInterval* reverse(void); public:
// 创建一个序列帧动画,内部调用create实现。参数为序列帧动画信息结构指针。
CC_DEPRECATED_ATTRIBUTE static CCAnimate* actionWithAnimation(CCAnimation *pAnimation);
// 创建一个序列帧动画。
static CCAnimate* create(CCAnimation *pAnimation);
// 定义一个序列帧动画信息结构指针变量以及存取此变量的函数。
CC_SYNTHESIZE_RETAIN(CCAnimation*, m_pAnimation, Animation)
protected:
// 保存 切换到每个动画帧时 当前相对于本次循环的进度比例(表示为0~1.0之间的浮点数,0表示未开始,0.5表示进行到一半,1.0表示完成)
// 是控制动画播放的标志
std::vector<float>* m_pSplitTimes;
// 本次循环 当前要播放的下一帧序号。
int m_nNextFrame;
// 初始帧
CCSpriteFrame* m_pOrigFrame;
// 已执行的循环次数
unsigned int m_uExecutedLoops;
};
不论是用什么样的方法创建帧动画,本质的流程都是这样的(参考文章末尾图片):
CCSpriteFrame* spriteframe = CCSpriteFrame::create(...);
CCAnimationFrame* animationframe = new CCAnimationFrame;
animationframe->initWithSpriteFrame(spriteframe,...);
CCAnimation* animation = CCAnimation::create(...);
CCAction * action = CCAnimate::create(animation);
创建完成
二、帧动画的播放过程
重点介绍CCAnimate类的两个函数initWithAnimation和update函数。
1.initWithAnimation函数
在这个函数中重点注意m_pSplitTimes的赋值,因为在执行帧动画的函数update中m_pSplitTimes是播放帧动画的重要标志。
在initWithAnimation函数中,将每个动画帧对应的执行进度按对应顺序插入到m_pSplitTimes中
bool CCAnimate::initWithAnimation(CCAnimation *pAnimation)
{
CCAssert( pAnimation!=NULL, "Animate: argument Animation must be non-NULL"); // 取得每次执行序列的时长
float singleDuration = pAnimation->getDuration(); // 乘以循环次数做为当前动画总时长来进行初始化
if ( CCActionInterval::initWithDuration(singleDuration * pAnimation->getLoops() ) )
{
m_nNextFrame = ;
setAnimation(pAnimation);
m_pOrigFrame = NULL;
m_uExecutedLoops = ; // 设置容器大小
m_pSplitTimes->reserve(pAnimation->getFrames()->count()); float accumUnitsOfTime = ;
// 每帧时间
float newUnitOfTimeValue = singleDuration / pAnimation->getTotalDelayUnits(); CCArray* pFrames = pAnimation->getFrames();
CCARRAY_VERIFY_TYPE(pFrames, CCAnimationFrame*); CCObject* pObj = NULL;
CCARRAY_FOREACH(pFrames, pObj)
{
CCAnimationFrame* frame = (CCAnimationFrame*)pObj;
// 当前动画帧的进度(相对于每次循环的总时间) = 从开始到当前动画帧的总时间之和 / 每次循环的总时间
// 从开始到当前动画帧的总时间之和 = 从开始到当前动画帧的总帧数 * 每帧间隔时间
float value = (accumUnitsOfTime * newUnitOfTimeValue) / singleDuration;
accumUnitsOfTime += frame->getDelayUnits();
// 当前动画帧的进度到m_pSplitTimes
m_pSplitTimes->push_back(value);
}
return true;
}
return false;
}
2.update函数
在这个函数中利用initWithAnimation函数赋值过的m_pSplitTimes来控制帧动画播放。
// 帧动画的执行函数
// 参数t表示一次循环animation执行进度(哪次不确定,由update内部计算得知)
//(表示为0~1.0之间的浮点数,0表示未开始,0.5表示进行到一半,1.0表示完成)
void CCAnimate::update(float t)
{
// 计算循环是否够次数
if( t < 1.0f ) {
// 计算当前进度播放的循环数
t *= m_pAnimation->getLoops(); // 通过先取整再判断是否大于当前的已经循环次数来判断是否是新的循环,
// 如果是将下一帧置零,已经循环的次数加1
unsigned int loopNumber = (unsigned int)t;
if( loopNumber > m_uExecutedLoops ) {
m_nNextFrame = ;
m_uExecutedLoops++;
} // 对t进行浮点取模值,将其限制在0~1之间,
// 这样等于又转换成为了当前动画播放的进度值。
t = fmodf(t, 1.0f);
} // 取得动画的帧信息容器和动画帧个数
CCArray* frames = m_pAnimation->getFrames();
unsigned int numberOfFrames = frames->count();
// 精灵图片信息
CCSpriteFrame *frameToDisplay = NULL; // 找出要播放的帧图片设置为精灵要显示的图片。
// 方法:从下一帧开始到结束帧进行遍历,判断是否到了这一帧。
for( unsigned int i=m_nNextFrame; i < numberOfFrames; i++ ) {
// 取出循环中的当前动画帧的播放进度
float splitTime = m_pSplitTimes->at(i);
// 如果这一帧的进度小于当前动画的播放进度,即代表进入了这一帧。
if( splitTime <= t ) {
// 取得对应的动画帧信息。
CCAnimationFrame* frame = (CCAnimationFrame*)frames->objectAtIndex(i);
// 取得当前帧的精灵图片信息。
frameToDisplay = frame->getSpriteFrame();
// 这才是显示动画的关键,找到相应的精灵帧并设置为m_pTarget要显示的当前帧。
((CCSprite*)m_pTarget)->setDisplayFrame(frameToDisplay);
// 通过动画帧信息取得其附加的用户词典信息,这个词典存储的是用于需要通知的目标。
CCDictionary* dict = frame->getUserInfo();
if( dict )
{
// 忽略
}
// 帧数加一。
m_nNextFrame = i+; break;
}
}
}
三、最后用一张图来总结帧动画的创建和播放

欢迎大家学习、共享,如果文章中有错误或漏洞,请大家在评论区留言!!
cocos2dx2.0 帧动画的创建和播放过程 深入分析的更多相关文章
- 帧动画的创建方式 - xml方式
废话不多说,先看东西 创建帧动画1 - xml方式 帧动画的创建方式主要以下2种: * 用xml创建动画: * 用代码创建动画: 本文内容主要关注 xml文件 创建帧动画的方式 xml文件 ...
- 帧动画的创建方式 - 纯Java代码方式
废话不多说,先看东西 帧动画的创建方式主要以下2种: * 用xml创建动画: * 纯Java代码创建动画: 本文内容主要关注 纯java代码创建帧动画 的方式: 用xml创建帧动画:http:// ...
- Android中帧动画的创建
帧动画,实质上就是快速播放多张连接效果的图片,现在一般可用于下拉刷新时候的headView 实现步骤: 1.首先应该准备一组连接效果的图片 2.在res>drawable目录下创建xml文件,将 ...
- cocos2dx2.0 与cocos2dx3.1 创建线程不同方式总结
尽管内容是抄过来的.可是经过了我的验证.并且放在一起就清楚非常多了,cocos2dx版本号常常变化非常大.总会导致这样那样的问题. cocos2dx2.0 中 1. 头文件 #include < ...
- 创建帧动画1 - xml方式
废话不多说,先看东西 创建帧动画1 - xml方式 帧动画的创建方式主要以下2种: * 用xml创建动画: * 用代码创建动画: 本文内容主要关注 xml文件 创建帧动画的方式 xml文件 ...
- Android 学习笔记多媒体技术之 Drawable类+Tween(补间动画)+Frame(帧动画)
学习内容: 1.了解Drawable类的作用 2.如何使用Drawable... 3.了解Tween动画... 4.如何创建和使用Tween动画... 1.Drawable类... Drawabl ...
- cocos2dx帧动画
//帧动画的创建 //方式一,通过多张图片来创建 auto sprite1 = Sprite::create("grossini_dance_05.png"); sprite1-& ...
- Android帧动画实现,防OOM,比原生动画集节约超过十倍的资源
2015年项目接到一个需求,实现一个向导动画,这个动画一共六十张图片,当时使用的是全志A33的开发(512的内存),通过使用Android的动画集实现,效果特别卡顿,然后想到这样的方式来实现,效果非常 ...
- Android动画系列之帧动画和补间动画
原文首发于微信公众号:jzman-blog,欢迎关注交流! Android 提供三种动画:帧动画.补间动画和属性动画,本篇文章介绍帧动画以及补间动画的使用,属性动画的使用将在后面的文章中分享,那就来复 ...
随机推荐
- 32、SpringBoot-整合Dubbo
分布式应用 在分布式系统中,国内常用zookeeper+dubbo组合,而Spring Boot推荐使用全栈的Spring, Spring Boot+Spring Cloud. 分布式系统: Zook ...
- 项目所有的证书文件路径iOS
~/Library/MobileDevice/Provisioning Profiles
- FD.io社区中国行暨未来网络技术沙龙·南京站 会议小结
What is FD.io VPP? FD.io VPP(Fast Data Input/Output Vector Packet Processing)is a new network multi- ...
- cocos2d-x开发:服务端基础库封装
元旦前面几天都在忙着面试,随后的几天也就一直在做服务端基础库开发方面的工作.对于服务端开发,是很久之前的事情了.那时候我还在大学读书,一直都是在倒腾服务端开发方面的东西,毕业后参加公司工作就是一直从事 ...
- G1 GC日志:Application time: 0.8766273 seconds
启动日志一直循环: 1.159: Application time: 0.8766273 seconds 1.160: Total time for which application threads ...
- 数组的定义和使用,理解多维数组和Array类
数组的作用 在执行程序的过程中,通常会需要存储大量数据.如果只有少量数据,那么通过声明变量,存储到变量中即可.但当我们的数据是20个.40个甚至是100以上时,就意味着需要声明很多变量,这是不现实的, ...
- Vue中,给当前元素添加类名移除兄弟元素类名的方法
在Vue中,给当前元素添加类名移除兄弟元素类名的方法 今天在项目中需要做一个效果,点击对应的li改变当前的color,其他的li取消颜色,在jQuery中这很容易,由于之前已经引入了jQuery,所以 ...
- 初识shell
shell简介 在计算机科学中,Shell俗称壳(用来区别于核),Shell 是一个 C 语言编写的脚本语言,它是用户与 Linux 的桥梁,用户输入命令交给 Shell 处理, Shell 将相应的 ...
- XML中需要转义的字符
有的数据库表的字段名,对于某些数据库来讲,是属于关键字或者保留字来处理识别的,那么这个时候,需要对这样的字段名进行转义处理,一般在执行sql 语句脚本的情况,处理办法是在这个字段名外加上双引号就可以识 ...
- MongoDB基础教程
MongoDB 一.下载MongoDB数据库 1.进入MongoDB官网进行下载,网址:https://www.mongodb.com/. 2.下载完成后可进行安装,安装后,并有了MongoDB服务. ...