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 提供三种动画:帧动画.补间动画和属性动画,本篇文章介绍帧动画以及补间动画的使用,属性动画的使用将在后面的文章中分享,那就来复 ...
随机推荐
- [luogu1979] 华容道
题面 先讲点无关的,这道题是真的恶心... 好了,第一眼看到这道题,肯定是准备暴搜的,但是想了一想,省选难度的题目不可能一上来就让你暴搜吧,于是开启了无穷无尽的分析,我们不妨设指定棋子叫做移动 ...
- WEB安全 魔术引号及注入类型
一.魔术引号 1. magic_quotes_gpc 变量 什么是魔术引号 Warning本特性已自 PHP 5.3.0 起废弃并将自 PHP 5.4.0 起移除.当打开时,所有的 '(单引号),&q ...
- [转]基于C#的开源GIS项目介绍之SharpMap篇
我是一个刚毕业的GIS本科毕业生,目前在杭州从事GIS软件应用开发.在项目开发中总感觉自己的编程水平还不够,于是想找些开源GIS小项目来研究研究,借以提高自己的编程能力和项目开发能力.在网上搜了一下“ ...
- sudo 启动tomcat报错没有java环境
报错: Cannot find ./catalina.shThe file is absent or does not have execute permissionThis file is need ...
- 使用supervior 监控 elasticsearch 进程
elasticsearch引擎在使用中可能会出现后台守护进程挂掉的情况,需要手动启动来恢复正常. 这时则可以引用supervior进程管理工具来监控elasticsearch进程状态,实现进程挂掉自动 ...
- MVC 当中 [ValidateAntiForgeryToken] 的作用
ValidateAntiForgeryToken 防止CSRF(跨网站请求伪造) 用途:防止CSRF(跨网站请求伪造). 用法:在View->Form表单中:<%:Html.AntiFo ...
- 安装Win7时删除系统保留的100M隐藏分区
原创文章,作者:lenbs,如若转载,请注明出处:https://www.smbinn.com/delwindows7100m.html 安装windows7新建磁盘分区时系统会自动创建100M的保留 ...
- android学习:Android上面部署Apache FTPServer
经过了几天的研究,终于Apache FTPServer在Android的配置和使用上有了一些心得,现在分享出来,提供给大家参考,说到这儿又不得不吐槽一下这要命的转载了,找Apache FTPServe ...
- android学习1:清晰详细android环境搭建,超简单
废话少说,今天是Android学习的开篇的博客,接下来将把自己学习android的各种问题和经历总结一下,其实之前已经自己学过半年了,但是因为开始时刚学的移动端开发还没有概念,当时总结工作又做的不好, ...
- vue面试题!!!
由于公司需要,需要把项目拆分,前端使用vue框架.最近面试vue总结的试题 1:mvvm框架是什么?它和其他框架的区别是什么? mvvm 全称model view viewModel,model数据模 ...