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 提供三种动画:帧动画.补间动画和属性动画,本篇文章介绍帧动画以及补间动画的使用,属性动画的使用将在后面的文章中分享,那就来复 ...
随机推荐
- `ECS弹性计算服务
云服务器(Elastic Compute Service 简称ECS)是一种简单高效,处理能力可弹性伸缩的计算服务.能快速构建更稳定.安全的应用,提升运维效率,降低IT成本. 云服务器ecs作用如下: ...
- ORACLE NLS_LENGTH_SEMANTICS 参数的用途
NLS_LENGTH_SEMANTICS参数是一个专为创建CHAR和VARCHAR2两种字符型的列时,指定使用的字节长度,还是使用字符长度的定义方式,有byte和char两种值,默认为byte. 当设 ...
- oracle 查看表空间以及剩余量
--1.查看表空间的名称及大小 SELECT t.tablespace_name, round(SUM(bytes / (1024 * 1024)), 0) ts_size FROM dba_tabl ...
- 安装Windows7步骤
我初次装Linux系统的时候,查过一些资料,然后也有网友教过我,这里做一个总结,和大家分享一下(U盘安装). 事实上我们平时电脑开机的时候,是有个启动顺序的,他并非直接进入我们的操作系统, ...
- 【原创】如何设置Virtual Box虚拟机CentOS7为静态IP地址
如何设置Virtual Box虚拟机CentOS7为静态IP地址 最近要搭建一个Kubernetes集群,需要设置虚拟机为静态IP地址不变.翻了一些资料,参差不齐,有些也比较过时了.自己实测总结了一下 ...
- MVC——MVP——MVVM
MVC什么样? 从这个图中可以清楚的看到: View:视图层——这里是用户与之交互的界面. Model:模型层——这里面主要就是业务数据,并把数据提供给视图层 Controller:控制器——他的主要 ...
- 不可变字符串String与可变字符串StringBuilder、StringBuffer使用详解
String字符串 char类型只能表示一个字符,而String可以表示字符串,也就是一个字符序列.但String不是基本类型,而是一个定义好的类,是一个引用类型.在Java中,可以将字符串直接量赋给 ...
- #leetcode刷题之路41-缺失的第一个正数
给定一个未排序的整数数组,找出其中没有出现的最小的正整数.示例 1:输入: [1,2,0]输出: 3示例 2:输入: [3,4,-1,1]输出: 2示例 3:输入: [7,8,9,11,12]输出: ...
- 『ACM C++』 PTA 天梯赛练习集L1 | 021-024
忙疯警告,这两天可能进度很慢,下午打了一下午训练赛,训练赛的题我就不拿过来的,pta就做了一点点,明天又是满课的一天,所以进度很慢啦~ -------------------------------- ...
- mysql的索引和执行计划
一.mysql的索引 索引是帮助mysql高效获取数据的数据结构.本质:索引是数据结构 1:索引分类 普通索引:一个索引只包含单个列,一个表可以有多个单列索引. 唯一索引:索引列的值必须唯一 ,但允许 ...