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 提供三种动画:帧动画.补间动画和属性动画,本篇文章介绍帧动画以及补间动画的使用,属性动画的使用将在后面的文章中分享,那就来复 ...
随机推荐
- mvc4中viewbag viewdata 和 tempdata的区别
ViewBag 不再是字典的键值对结构,而是 dynamic 动态类型,它会在程序运行的时候动态解析. eg: ViewBag.NumberObjs = new string[] { "on ...
- leetcode 20 括号匹配
class Solution { public: bool isValid(string s) { stack<char> result; for(char c:s){ if(c == ' ...
- C/C++结构体字节对齐详解
结构体的sizeof先看一个结构体:struct S1{ char c; int i;}; sizeof(S1)在VC6中按默认设置得到的结果为8.我们先看看sizeof的定义——size ...
- 【noip 模拟赛curse,light,maze】 题解
2018.10.16 总结:考的不好 原因: 1.考的时候没状态,读题读不进去 2.考的时候不仔细,该得分没得到 T1:curse 1.咒语 (curse.pas/c/cpp) [题目描述] 亮亮梦到 ...
- java web 常识
model.addattribute()的作用: 1.往前台传数据可以传对象,List,通过el表达式${}获取,类似于request.setAttribute("sts",sts ...
- iOS 中系统与 SDK 版本检测
一.编译时检测 1. 判断 SDK 是否是某个版本或更高版本 ifdef __IPHONE_11_0 2.判断当前需要支持的最低版本 __IPHONE_OS_VERSION_MIN_REQUIRED ...
- web相关文件加载顺序
WEB相关文件的加载顺序 一. 1.启动一个WEB项目,WEB容器会先去读取它的配置文件web.xml,读取<context-param>和<listener>两个节点. ...
- vim内替换文件内容
几个常用的方法如下: :%s/foo/bar/g 把全部foo替换为bar,全局替换 :s/foo/bar/g 当前行替换foo为bar :%s/foo/bar/gc 替换每个foo为bar,但需要确 ...
- python 基础 切片 迭代 列表生成式
对list 进行切片 如列表 L = ['Adam', 'Lisa', 'Bart', 'Paul'] L[0:3] ['Adam', 'Lisa', 'Bart'] L[0:3]表示,从索引0开始取 ...
- 有关MySQL数据库命令
phpstudy使用最终端打开数据库 : 第一次打开默认的密码是:root. 进入后对数据可以进行增删查改. show databases; 是查看数据库的指令 注意:分号是数据库的结束符,没有加分 ...