转自:http://blog.csdn.net/honghaier/article/details/8222401

序列帧动画主要有几个类:

CCSpriteFrame:精灵帧信息,序列帧动画是依靠多个精灵帧信息来显示相应的纹理图像,一个精灵帧信息包包含了所使用的纹理,对应纹理块的位置以及纹理块是否经过旋转和偏移,这些信息可以取得对应纹理中正确的纹理块区域做为精灵帧显示的图像。

CCAnimationFrame:序列帧动画单帧信息,它存储了对应的精灵帧信息。

CCAnimation:序列帧动画信息,它存储了所有的单帧信息,可以对单帧信息进行管理。

CCAnimate:序列帧动画处理类,它是真正完成动画表演的类。

先学习一下CCSpriteFrame:

#ifndef __SPRITE_CCSPRITE_FRAME_H__
#define __SPRITE_CCSPRITE_FRAME_H__
//相关头文件
#include "base_nodes/CCNode.h"
#include "CCProtocols.h"
#include "cocoa/CCObject.h"
#include "cocoa/CCGeometry.h"
//Cocos2d命名空间
NS_CC_BEGIN
//要用到的类
class CCTexture2D;
class CCZone; //精灵帧:精灵序列帧动画中的一帧。
class CC_DLL CCSpriteFrame : public CCObject
{
public:
  // pixel大小
//取得精灵帧的大小(像素单位)
  inline const CCRect& getRectInPixels(void) { return m_obRectInPixels; }
  //设置精灵帧的大小(像素单位)
  void setRectInPixels(const CCRect& rectInPixels);   // 旋转
//取得当前帧所用的纹理块是否旋转了90度
  inline bool isRotated(void) { return m_bRotated; }
  //设置当前帧所用的纹理块旋转90度
inline void setRotated(bool bRotated) { m_bRotated = bRotated; }

  // rect
//取得当前帧所用的纹理块在图集纹理的矩形(点单位)
inline const CCRect& getRect(void) { return m_obRect; }
//设置当前帧所用的纹理块在图集中的矩形(点单位)
void setRect(const CCRect& rect);

  // offset 像素单位
//取得当前帧所用的纹理块在图集中的位置(像素单位)
const CCPoint& getOffsetInPixels(void);
//设置当前帧所用的纹理块在图集中的位置(像素单位)
void setOffsetInPixels(const CCPoint& offsetInPixels);
  // offset 点单位
//取得纹理块在合并时去掉周围空白边后的锚点偏移(点单位).
  const CCPoint& getOffset(void);
  //设置纹理块在合并时去掉周围空白边后的锚点偏移(点单位).
void setOffset(const CCPoint& offsets);
  // originalSize 像素单位
//取得纹理块的原始大小(像素单位)。
inline const CCSize& getOriginalSizeInPixels(void) { return m_obOriginalSizeInPixels; }
//设置纹理块的原始大小(像素单位)。
inline void setOriginalSizeInPixels(const CCSize& sizeInPixels) { m_obOriginalSizeInPixels = sizeInPixels; }

  // originalSize 点单位
//取得纹理块的原始大小(点单位)。
inline const CCSize& getOriginalSize(void) { return m_obOriginalSize; }
//设置纹理块的原始大小(点单位)。
inline void setOriginalSize(const CCSize& sizeInPixels) { m_obOriginalSize = sizeInPixels; }

  // texture
//取得当前帧所使用的图集纹理
CCTexture2D* getTexture(void);
//设置当前帧所使用的图集纹理
   void setTexture(CCTexture2D* pobTexture); public:
//析构
  ~CCSpriteFrame(void);
  //创建一个当前实例的拷贝
virtual CCObject* copyWithZone(CCZone *pZone);
//从一个图集纹理中创建出一帧,内部调用对应createWithTexture函数实现,参一为图集纹理,参二为纹理块矩形。
CC_DEPRECATED_ATTRIBUTE static CCSpriteFrame* frameWithTexture(CCTexture2D* pobTexture, const CCRect& rect);
//从一张图集图片中创建出一帧,内部调用对应create函数实现,参一为图集图片名称,参二为纹理块矩形。
CC_DEPRECATED_ATTRIBUTE static CCSpriteFrame* frameWithTextureFilename(const char* filename, const CCRect& rect);
//从一个图集纹理中创建出一帧,内部调用对应createWithTexture函数实现,参一为图集纹理,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
CC_DEPRECATED_ATTRIBUTE static CCSpriteFrame* frameWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize);
//从一个张图集图片中创建出一帧,内部调用对应create函数实现,参一为图集图片名称,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
CC_DEPRECATED_ATTRIBUTE static CCSpriteFrame* frameWithTextureFilename(const char* filename, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize);
//从一张图片文件中以指定的矩形创建一个精灵帧。参一为图集图片名称,参二为对应纹理块的矩形。
static CCSpriteFrame* create(const char* filename, const CCRect& rect);
//从一个图集图片中创建出一帧,参一为图集图片名称,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
static CCSpriteFrame* create(const char* filename, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize);
//从一张图集纹理中以指定的矩形创建一个精灵帧。参一为图集纹理,参二为对应纹理块的矩形。
static CCSpriteFrame* createWithTexture(CCTexture2D* pobTexture, const CCRect& rect);
   //从一个图集纹理中创建出一帧,参一为图集纹理,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
static CCSpriteFrame* createWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize); public:
//初始化精灵帧:参一为图集纹理,参二为对应纹理块的矩形。
bool initWithTexture(CCTexture2D* pobTexture, const CCRect& rect);
//初始化精灵帧:参一为图集图片名称,参二为对应纹理块的矩形。
bool initWithTextureFilename(const char* filename, const CCRect& rect);
//初始化精灵帧:参一为图集纹理,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
bool initWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize);
//初始化精灵帧:参一为图集图片名称,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
bool initWithTextureFilename(const char* filename, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize); 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;
}; NS_CC_END #endif //__SPRITE_CCSPRITE_FRAME_H__

再来看CCSpriteFrame.cpp:

#include "textures/CCTextureCache.h"
#include "CCSpriteFrame.h"
#include "CCDirector.h" //使用Cocos2d命名空间
NS_CC_BEGIN //从一个图集纹理中创建出一帧,内部调用后面的createWithTexture函数实现,参一为图集纹理,参二为纹理块矩形。
CCSpriteFrame* CCSpriteFrame::frameWithTexture(CCTexture2D *pobTexture, const CCRect& rect)
{
return CCSpriteFrame::createWithTexture(pobTexture, rect);
}
//从一个图集纹理中创建出一帧,参一为图集纹理,参二为纹理块矩形。
CCSpriteFrame* CCSpriteFrame::createWithTexture(CCTexture2D *pobTexture, const CCRect& rect)
{
//新帧一个精灵帧,初始化完毕后交由内存管理器进行释放管理。
CCSpriteFrame *pSpriteFrame = new CCSpriteFrame();;
pSpriteFrame->initWithTexture(pobTexture, rect);
pSpriteFrame->autorelease();
//返回新创建的精灵帧。
return pSpriteFrame;
} //从一张图集图片中创建出一帧,内部调用后面的create函数实现,参一为图集图片名称,参二为纹理块矩形。
CCSpriteFrame* CCSpriteFrame::frameWithTextureFilename(const char* filename, const CCRect& rect)
{
return CCSpriteFrame::create(filename, rect);
}
//从一张图集图片中创建出一帧,参一为图集图片名称,参二为纹理块矩形。
CCSpriteFrame* CCSpriteFrame::create(const char* filename, const CCRect& rect)
{
  //新帧一个精灵帧,初始化完毕后交由内存管理器进行释放管理。
CCSpriteFrame *pSpriteFrame = new CCSpriteFrame();;
pSpriteFrame->initWithTextureFilename(filename, rect);
pSpriteFrame->autorelease();
//返回新创建的精灵帧。
return pSpriteFrame;
} //从一个图集纹理中创建出一帧,内部调用后面的createWithTexture函数实现,参一为图集纹理,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
CCSpriteFrame* CCSpriteFrame::frameWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize)
{
return CCSpriteFrame::createWithTexture(pobTexture, rect, rotated, offset, originalSize);
}
//从一个图集纹理中创建出一帧,参一为图集纹理,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。 CCSpriteFrame* CCSpriteFrame::createWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize)
{
  //新帧一个精灵帧,初始化完毕后交由内存管理器进行释放管理。
CCSpriteFrame *pSpriteFrame = new CCSpriteFrame();;
pSpriteFrame->initWithTexture(pobTexture, rect, rotated, offset, originalSize);
pSpriteFrame->autorelease();
//返回新创建的精灵帧。
return pSpriteFrame;
} //从一个张图集图片中创建出一帧,内部调用后面的create函数实现,参一为图集图片名称,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
CCSpriteFrame* CCSpriteFrame::frameWithTextureFilename(const char* filename, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize)
{
return CCSpriteFrame::create(filename, rect, rotated, offset, originalSize);
}
//从一个张图集图片中创建出一帧,参一为图集图片名称,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小。
CCSpriteFrame* CCSpriteFrame::create(const char* filename, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize)
{
  //新帧一个精灵帧,初始化完毕后交由内存管理器进行释放管理。
CCSpriteFrame *pSpriteFrame = new CCSpriteFrame();;
pSpriteFrame->initWithTextureFilename(filename, rect, rotated, offset, originalSize);
pSpriteFrame->autorelease();
//返回新创建的精灵帧。
return pSpriteFrame;
} //初始化精灵帧:参一为图集纹理,参二为对应纹理块的矩形。
bool CCSpriteFrame::initWithTexture(CCTexture2D* pobTexture, const CCRect& rect)
{
//将矩形参数转为当前设备分辨率下的像素单位的大小。
  CCRect rectInPixels = CC_RECT_POINTS_TO_PIXELS(rect);
  //调用参数更详细的初始化函数。
return initWithTexture(pobTexture, rectInPixels, false, CCPointZero, rectInPixels.size);
}
//初始化精灵帧:参一为图集图片名称,参二为对应纹理块的矩形。
bool CCSpriteFrame::initWithTextureFilename(const char* filename, const CCRect& rect)
{
//将矩形参数转为当前设备分辨率下的像素单位的大小。
  CCRect rectInPixels = CC_RECT_POINTS_TO_PIXELS( rect );
  //调用参数更详细的初始化函数。
return initWithTextureFilename(filename, rectInPixels, false, CCPointZero, rectInPixels.size);
}
//初始化精灵帧:参一为图集纹理,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉纹理块空白后所导致的锚点偏移,参五为纹理块的原始大小
bool CCSpriteFrame::initWithTexture(CCTexture2D* pobTexture, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize)
{
//保存图集纹理
m_pobTexture = pobTexture;
//占用纹理资源,对其引用计数器加1
if (pobTexture)
{
pobTexture->retain();
}
//保存像素单位的矩形大小
  m_obRectInPixels = rect;
  //保存点单位的矩形大小
  m_obRect = CC_RECT_PIXELS_TO_POINTS(rect);
  //保存像素单位的去掉纹理块空白后所导致的锚点偏移。
  m_obOffsetInPixels = offset;
  //保存点单位的去掉纹理块空白后所导致的锚点偏移。
  m_obOffset = CC_POINT_PIXELS_TO_POINTS( m_obOffsetInPixels );
  //保存像素单位的纹理块原始大小
  m_obOriginalSizeInPixels = originalSize;
  //保存点单位的纹理块原始大小
  m_obOriginalSize = CC_SIZE_PIXELS_TO_POINTS( m_obOriginalSizeInPixels );
  //保存纹理块是否旋转了90度。
m_bRotated = rotated; return true;
}
//初始化精灵帧:参一为图集图片名称,参二为对应纹理块的矩形,参三为矩形块是否旋转,参四为去掉空白后纹理块所导致的偏移,参五为纹理块的原始大小
bool CCSpriteFrame::initWithTextureFilename(const char* filename, const CCRect& rect, bool rotated, const CCPoint& offset, const CCSize& originalSize)
{
//图集纹理置空
  m_pobTexture = NULL;
  //保存图集图片名称。
  m_strTextureFilename = filename;
  //保存像素单位的矩形大小
  m_obRectInPixels = rect;
  //保存转换为点单位的矩形大小
  m_obRect = CC_RECT_PIXELS_TO_POINTS(rect);
  //保存像素单位的去掉纹理块空白后所导致的锚点偏移。
  m_obOffsetInPixels = offset;
  //保存转换为点单位的去掉纹理块空白后所导致的锚点偏移。
  m_obOffset = CC_POINT_PIXELS_TO_POINTS( m_obOffsetInPixels );
  //保存像素单位的纹理块原始大小
  m_obOriginalSizeInPixels = originalSize;
  //保存转换为点单位的纹理块原始大小
  m_obOriginalSize = CC_SIZE_PIXELS_TO_POINTS( m_obOriginalSizeInPixels );
  //保存纹理块是否旋转了90度。
m_bRotated = rotated; return true;
}
//析构
CCSpriteFrame::~CCSpriteFrame(void)
{
CCLOGINFO("cocos2d: deallocing %p", this);
CC_SAFE_RELEASE(m_pobTexture);
}
//创建一个当前实例的拷贝
CCObject* CCSpriteFrame::copyWithZone(CCZone *pZone)
{
  CC_UNUSED_PARAM(pZone);
  //新创一个CCSpriteFrame实例对象。
CCSpriteFrame *pCopy = new CCSpriteFrame();
//以当前实例的各属性值为参数对其进行初始化。
  pCopy->initWithTextureFilename(m_strTextureFilename.c_str(), m_obRectInPixels, m_bRotated, m_obOffsetInPixels, m_obOriginalSizeInPixels);
  //设置同样的纹理图集。
  pCopy->setTexture(m_pobTexture);
  //返回创建的CCSpriteFrame实例对象。
return pCopy;
}
//设置当前帧所用的纹理块在图集中的矩形
void CCSpriteFrame::setRect(const CCRect& rect)
{
  //保存点单位的矩形大小
  m_obRect = rect;
  //保存转换为像素单位的矩形大小
m_obRectInPixels = CC_RECT_POINTS_TO_PIXELS(m_obRect);
}
//设置当前帧所用的纹理块在图集中的矩形(像素单位)
void CCSpriteFrame::setRectInPixels(const CCRect& rectInPixels)
{
//保存像素单位的矩形大小
  m_obRectInPixels = rectInPixels;
  //保存转换为点单位的矩形大小
m_obRect = CC_RECT_PIXELS_TO_POINTS(rectInPixels);
}
//取得纹理块在合并时去掉周围空白边后的锚点偏移(点单位).
const CCPoint& CCSpriteFrame::getOffset(void)
{
return m_obOffset;
}
//设置纹理块在合并时去掉周围空白边后的锚点偏移(点单位).
void CCSpriteFrame::setOffset(const CCPoint& offsets)
{
//保存纹理块在合并时去掉周围空白边后的锚点偏移(点单位).
  m_obOffset = offsets;
  //保存转换为像素单位的纹理块在合并时去掉周围空白边后的锚点偏移。
m_obOffsetInPixels = CC_POINT_POINTS_TO_PIXELS( m_obOffset );
}
//取得纹理块在合并时去掉周围空白边后的锚点偏移(像素单位).
const CCPoint& CCSpriteFrame::getOffsetInPixels(void)
{
return m_obOffsetInPixels;
}
//设置纹理块在合并时去掉周围空白边后的锚点偏移(像素单位).
void CCSpriteFrame::setOffsetInPixels(const CCPoint& offsetInPixels)
{
//保存像素单位的纹理块在合并时去掉周围空白边后的锚点偏移。
  m_obOffsetInPixels = offsetInPixels;
  //保存转换为点单位的纹理块在合并时去掉周围空白边后的锚点偏移.
m_obOffset = CC_POINT_PIXELS_TO_POINTS( m_obOffsetInPixels );
}
//设置图集纹理
void CCSpriteFrame::setTexture(CCTexture2D * texture)
{
//删放旧图集纹理,使用新图集纹理。
if( m_pobTexture != texture ) {
CC_SAFE_RELEASE(m_pobTexture);
//对应CC_SAFE_RELEASE对引用计数器减一操作, CC_SAFE_RETAIN对引用计数器加一操作.
CC_SAFE_RETAIN(texture);
m_pobTexture = texture;
}
}
//取得图集纹理。
CCTexture2D* CCSpriteFrame::getTexture(void)
{
//如果纹理指针有效,直接返回。
if( m_pobTexture ) {
return m_pobTexture;
}
//否则查看纹理图片是否有效,如果有效,加载到纹理管理器中返回创建的纹理。
if( m_strTextureFilename.length() > ) {
return CCTextureCache::sharedTextureCache()->addImage(m_strTextureFilename.c_str());
}
// 如果都无效,返回NULL。
return NULL;
} NS_CC_END

现在来看CCAnimationFrame 和CCAnimation:

#ifndef __CC_ANIMATION_H__
#define __CC_ANIMATION_H__
//引入相关头文件。
#include "platform/CCPlatformConfig.h"
#include "cocoa/CCObject.h"
#include "cocoa/CCArray.h"
#include "cocoa/CCDictionary.h"
#include "cocoa/CCGeometry.h"
#include "CCSpriteFrame.h"
#include <string>
//使用Cocos2d命名空间。
NS_CC_BEGIN
//用到的类。
class CCTexture2D;
class CCSpriteFrame; //序列帧动画单帧:序列帧动画中的一帧。
class CC_DLL CCAnimationFrame : public CCObject
{
public:
//构造
CCAnimationFrame();
//析构
virtual ~CCAnimationFrame();
//创建一个当前实例的拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//初始化单帧:参一为精灵帧,参二为当前帧到下一帧的时间间隔?错,这里有问题,后面讲,参三为存储各帧所用的词典。
bool initWithSpriteFrame(CCSpriteFrame* spriteFrame, float delayUnits, CCDictionary* userInfo); //定义一个精灵帧成员指针变量m_pSpriteFrame,代表当前动画帧所对应的精灵帧。CC_SYNTHESIZE_RETAIN宏创建对变量的set 和 get 操作的函数,函数名分别为setSpriteFrame和getSpriteFrame, 相应的set函数会释放旧的指针变量,并将参数保存到指针变量,并自动的对其引用计数器加一。
CC_SYNTHESIZE_RETAIN(CCSpriteFrame*, m_pSpriteFrame, SpriteFrame) //定义一个float成员变量m_fDelayUnits,代表当前帧到下一帧的时间间隔?错,这个变量其实没有毛用处?看多了反而容易乱,先略过吧。最后统一分析。CC_SYNTHESIZE宏创建对变量的set 和 get 操作的函数,函数名分别为setDelayUnits和getDelayUnits。
CC_SYNTHESIZE(float, m_fDelayUnits, DelayUnits) //定义一个词典成员指针变量m_pUserInfo,CC_SYNTHESIZE_RETAIN宏创建对变量的set 和 get 操作的函数,函数名分别为set UserInfo和get UserInfo, 相应的set函数会释放旧的指针变量,并将参数保存到指针变量,并自动的对其引用计数器加一。
CC_SYNTHESIZE_RETAIN(CCDictionary*, m_pUserInfo, UserInfo)
}; //CCAnimation:序列帧动画类,管理所有动画中的CCAnimationFrame。
class CC_DLL CCAnimation : public CCObject
{
public:
//构造函数。
CCAnimation();
//析构函数。
~CCAnimation(void);
public:
//创建一个序列帧动画,内部调用create实现。
CC_DEPRECATED_ATTRIBUTE static CCAnimation* animation(void); //创建一个序列帧动画,内部调用createWithSpriteFrames实现。参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔。
CC_DEPRECATED_ATTRIBUTE static CCAnimation* animationWithSpriteFrames(CCArray* arrayOfSpriteFrameNames, float delay = 0.0f); //创建一个序列帧动画,内部调用相应create实现。参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔,参三为循环次数。
CC_DEPRECATED_ATTRIBUTE static CCAnimation* animationWithAnimationFrames(CCArray *arrayOfAnimationFrameNames, float delayPerUnit, unsigned int loops); //创建一个序列帧动画。
static CCAnimation* create(void); //创建一个序列帧动画,参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔。
static CCAnimation* createWithSpriteFrames(CCArray* arrayOfSpriteFrameNames, float delay = 0.0f); //创建一个序列帧动画。参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔,参三为循环次数。
static CCAnimation* create(CCArray *arrayOfAnimationFrameNames, float delayPerUnit, unsigned int loops); //新加一帧到序列帧动画中,参数为CCSpriteFrame指针。
void addSpriteFrame(CCSpriteFrame *pFrame); //新加一帧加入到序列帧动画中,参数为单帧图片名称。
void addSpriteFrameWithFileName(const char *pszFileName); //新加一帧加入到序列帧动画中,参一为图集纹理,参二为图集纹理中的图块矩形。
void addSpriteFrameWithTexture(CCTexture2D* pobTexture, const CCRect& rect); //初始化一个空白的动画。
bool init(); //初始化序列帧动画,参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔。
bool initWithSpriteFrames(CCArray *pFrames, float delay = 0.0f); //初始化序列帧动画,参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔,参三为循环次数。
bool initWithAnimationFrames(CCArray* arrayOfAnimationFrames, float delayPerUnit, unsigned int loops); //创建一个当前类的实例对象。
virtual CCObject* copyWithZone(CCZone* pZone); //定义一个float成员变量m_ fTotalDelayUnits,代表总帧数。CC_SYNTHESIZE_READONLY宏创建对变量的get 操作的函数,函数为getTotalDelayUnits。
CC_SYNTHESIZE_READONLY(float, m_fTotalDelayUnits, TotalDelayUnits) //定义一个float成员变量m_fDelayPerUnit,代表每两帧间的时间间隔,CC_SYNTHESIZE宏创建对变量的set 和 get 操作的函数,函数名分别为setDelayPerUnit和getDelayPerUnit。
CC_SYNTHESIZE(float, m_fDelayPerUnit, DelayPerUnit) //定义一个float成员变量m_fDuration,这个变量没用,不知作者为什么要加这个变量~。CC_SYNTHESIZE_READONLY宏创建对变量的get 操作的函数,函数为getDuration。
CC_PROPERTY_READONLY(float, m_fDuration, Duration) //定义一个词典成员指针变量m_pFrames,用于保存每个动画帧,CC_SYNTHESIZE_RETAIN宏创建对变量的set 和 get 操作的函数,函数名分别为setFrames和getFrames, 相应的set函数会释放旧的指针变量,并将参数保存到指针变量,并自动的对其引用计数器加一。
CC_SYNTHESIZE_RETAIN(CCArray*, m_pFrames, Frames) //定义一个bool成员变量m_bRestoreOriginalFrame,用于指定是否在动画结束后释放各帧。CC_SYNTHESIZE宏创建对变量的set 和 get 操作的函数,函数名分别为setRestoreOriginalFrame和getRestoreOriginalFrame。
CC_SYNTHESIZE(bool, m_bRestoreOriginalFrame, RestoreOriginalFrame) //定义一个unsigned int成员变量m_uLoops,代表循环播放次数。CC_SYNTHESIZE宏创建对变量的set 和 get 操作的函数,函数名分别为setLoops和getLoops。
CC_SYNTHESIZE(unsigned int, m_uLoops, Loops)
}; NS_CC_END #endif // __CC_ANIMATION_H__

再看CPP:

#include "CCAnimation.h"
#include "textures/CCTextureCache.h"
#include "textures/CCTexture2D.h"
#include "ccMacros.h"
#include "sprite_nodes/CCSpriteFrame.h"
#include "cocoa/CCZone.h"
//Cocos2d命名空间
NS_CC_BEGIN
//构造
CCAnimationFrame::CCAnimationFrame()
: m_pSpriteFrame(NULL)
, m_fDelayUnits(0.0f)
, m_pUserInfo(NULL)
{ }
//初始化单帧:参一为精灵帧,参二为当前帧到下一帧的时间间隔,参三为存储各帧所用的词典。
bool CCAnimationFrame::initWithSpriteFrame(CCSpriteFrame* spriteFrame, float delayUnits, CCDictionary* userInfo)
{
//设置为当前单帧所用的各成员变量。
setSpriteFrame(spriteFrame);
setDelayUnits(delayUnits);
setUserInfo(userInfo); return true;
}
//析构
CCAnimationFrame::~CCAnimationFrame()
{
CCLOGINFO( "cocos2d: deallocing %s", this);
//对占用的精灵帧和词典引用计数估减一操作。
CC_SAFE_RELEASE(m_pSpriteFrame);
CC_SAFE_RELEASE(m_pUserInfo);
}
//创建当前单帧的实例拷贝。
CCObject* CCAnimationFrame::copyWithZone(CCZone* pZone)
{
//定义拷贝类变量指针
CCZone* pNewZone = NULL;
//定义单帧类指针变量pCopy用于存储创建结果,置空。
CCAnimationFrame* pCopy = NULL;
//如果参数pZone有效且已经有内部产生的实例拷贝。
if(pZone && pZone->m_pCopyObject)
{
//直接取得拷贝返回给pCopy.
pCopy = (CCAnimationFrame*)(pZone->m_pCopyObject);
}
else
{
//如果参数pZone无值或者无内部产生的拷贝,重新生成单帧以及相应单帧的拷贝。
pCopy = new CCAnimationFrame();
pNewZone = new CCZone(pCopy);
}
//对pCopy进行初始化,注意相应成员变量也要调用copy以产生拷贝,并调用autorelease以交由内存管理器进行释放管理。 pCopy->initWithSpriteFrame((CCSpriteFrame*)m_pSpriteFrame->copy()->autorelease(),
m_fDelayUnits, m_pUserInfo != NULL ? (CCDictionary*)m_pUserInfo->copy()->autorelease() : NULL);
//释放pNewZone
CC_SAFE_DELETE(pNewZone);
//返回pCopy。
return pCopy;
} //创建动画
CCAnimation* CCAnimation::animation(void)
{
return CCAnimation::create();
}
//创建动画。
CCAnimation* CCAnimation::create(void)
{
//使用new创建一个动画,初始化并交由内存管理器进行释放管理。
CCAnimation *pAnimation = new CCAnimation();
pAnimation->init();
pAnimation->autorelease();
//返回创建成功的动画。
return pAnimation;
}
//创建一个序列帧动画,内部调用相应createWithSpriteFrames实现。参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔。
CCAnimation* CCAnimation::animationWithSpriteFrames(CCArray *frames, float delay/* = 0.0f*/)
{
return CCAnimation::createWithSpriteFrames(frames, delay);
}
//创建一个序列帧动画。参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔。 CCAnimation* CCAnimation::createWithSpriteFrames(CCArray *frames, float delay/* = 0.0f*/)
{
//使用new创建一个动画实例,初始化后交由内存管理器进行释放管理。
CCAnimation *pAnimation = new CCAnimation();
pAnimation->initWithSpriteFrames(frames, delay);
pAnimation->autorelease();
//返回创建的动画实例。
return pAnimation;
}
//创建一个序列帧动画,内部调用相应create实现。参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔,参三为循环次数。 CCAnimation* CCAnimation::animationWithAnimationFrames(CCArray* arrayOfAnimationFrameNames, float delayPerUnit, unsigned int loops)
{
return CCAnimation::create(arrayOfAnimationFrameNames, delayPerUnit, loops);
}
//创建一个序列帧动画,参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔,参三为循环次数。 CCAnimation* CCAnimation::create(CCArray* arrayOfAnimationFrameNames, float delayPerUnit, unsigned int loops)
{
//使用new创建一个动画实例,初始化后交由内存管理器进行释放管理。
CCAnimation *pAnimation = new CCAnimation();
pAnimation->initWithAnimationFrames(arrayOfAnimationFrameNames, delayPerUnit, loops);
pAnimation->autorelease();
//返回创建的动画实例。
return pAnimation;
}
//初始化一个空白的动画。
bool CCAnimation::init()
{
return initWithSpriteFrames(NULL, 0.0f);
}
//初始化序列帧动画,参数一为存储精灵帧的数组,参数二为动画的每一帧与下帧的时间间隔。
bool CCAnimation::initWithSpriteFrames(CCArray *pFrames, float delay/* = 0.0f*/)
{
//对pFrames是否是CCSpriteFrame指针数组进行检查。
CCARRAY_VERIFY_TYPE(pFrames, CCSpriteFrame*);
//将循环次数置1.
m_uLoops = ;
//保存每一帧与下一帧的时间间隔。
m_fDelayPerUnit = delay;
//创建一个CArray,返回它的地址给指针pTmpFrames。
CCArray* pTmpFrames = CCArray::create();
//将pTmpFrames设置为当前动画的帧数组指针。
setFrames(pTmpFrames);
//如果代表单帧数组的参数pFrames有值,遍历各帧存入pTmpFrames.
if (pFrames != NULL)
{
//定义临时变量pObj用来存储遍历时的元素。
CCObject* pObj = NULL;
//遍历pFrames,以pObj为每次循环的元素指针。
CCARRAY_FOREACH(pFrames, pObj)
{
//将pObj转为精灵帧指针。
CCSpriteFrame* frame = (CCSpriteFrame*)pObj;
//创建一个动画单帧,并将精灵单帧做为参数对其进行初始化。
CCAnimationFrame *animFrame = new CCAnimationFrame();
animFrame->initWithSpriteFrame(frame, , NULL);
//将初始化完成后的动画单帧放入动画帧容器。
m_pFrames->addObject(animFrame);
//对动画单帧的引用计数器减1,不会被释放的,因为上面一行代码中addObject对它的引用计数器内部会做加1操作。这样“该接手的加1,该放手的减1”完成了交接工作。
animFrame->release();
//动画帧数加一。
m_fTotalDelayUnits++;
}
} return true;
}
//初始化序列帧动画,参数一为存储单帧的数组,参数二为动画的每一帧与下帧的时间间隔,参数三为循环播放次数。
bool CCAnimation::initWithAnimationFrames(CCArray* arrayOfAnimationFrames, float delayPerUnit, unsigned int loops)
{
//对pFrames是否是CCSpriteFrame指针数组进行检查。
CCARRAY_VERIFY_TYPE(arrayOfAnimationFrames, CCAnimationFrame*);
//保存每一帧与下一帧的时间间隔。
m_fDelayPerUnit = delayPerUnit;
//保存循环次数
m_uLoops = loops;
//将arrayOfAnimationFrames设置为当前动画的帧数组指针。
setFrames(CCArray::createWithArray(arrayOfAnimationFrames));
//定义临时变量pObj用来存储遍历时的元素。
CCObject* pObj = NULL;
//遍历pFrames,以pObj为每次循环的元素指针。
CCARRAY_FOREACH(m_pFrames, pObj)
{
//将pObj转为动画单帧指针。
CCAnimationFrame* animFrame = (CCAnimationFrame*)pObj;
//这里写的有误,应该改成动画帧数加一,它加动画帧的相应函数干毛?
m_fTotalDelayUnits += animFrame->getDelayUnits();
}
//返回成功。
return true;
}
//构造
CCAnimation::CCAnimation()
: m_fTotalDelayUnits(0.0f)
, m_fDelayPerUnit(0.0f)
, m_fDuration(0.0f)
, m_pFrames(NULL)
, m_bRestoreOriginalFrame(false)
, m_uLoops()
{ }
//析构
CCAnimation::~CCAnimation(void)
{
CCLOGINFO("cocos2d, deallocing %p", this);
CC_SAFE_RELEASE(m_pFrames);
} //新加一帧到序列帧动画中,参数为CCSpriteFrame指针。&nbsp;
void CCAnimation::addSpriteFrame(CCSpriteFrame *pFrame)
{
//利用new新建一个动画帧.
CCAnimationFrame *animFrame = new CCAnimationFrame();
//使用精灵指参数对其进行初始化。
animFrame->initWithSpriteFrame(pFrame, 1.0f, NULL);
//将生成的动画帧放入动画帧容器
m_pFrames->addObject(animFrame);
//对动画单帧的引用计数器减1。(新建的animFrame,交给m_pFrames的addObject函数会对其引用计数器加1,后就要减1才对。交接也要保证引用计数的平衡)
animFrame->release();
//动画帧数加一。
m_fTotalDelayUnits++;
}
//新加一帧加入到序列帧动画中,参数为单帧图片名称。
void CCAnimation::addSpriteFrameWithFileName(const char *pszFileName)
{
//先由图片名称取得创建的纹理。
CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(pszFileName);
//定义临时矩形保存图片大小。
CCRect rect = CCRectZero;
rect.size = pTexture->getContentSize();
//由当前图片和对应大小创建出一个精灵帧 。
CCSpriteFrame *pFrame = CCSpriteFrame::createWithTexture(pTexture, rect);
//使用创建的精灵帧来调用上一个函数增加一帧动画。
addSpriteFrame(pFrame);
}
//新加一帧加入到序列帧动画中,参数一为图集纹理,参数二为对应的纹理块矩形。
void CCAnimation::addSpriteFrameWithTexture(CCTexture2D *pobTexture, const CCRect& rect)
{
//由当前图片和对应大小创建出一个精灵帧 。
CCSpriteFrame *pFrame = CCSpriteFrame::createWithTexture(pobTexture, rect);
//使用创建的精灵帧来增加一帧动画。
addSpriteFrame(pFrame);
}
//取得序列帧动画总时长。
float CCAnimation::getDuration(void)
{
//总时长 = 帧数x帧间隔时间。
return m_fTotalDelayUnits * m_fDelayPerUnit;
}
//创建当前序列帧动画实例的拷贝。
CCObject* CCAnimation::copyWithZone(CCZone* pZone)
{
//定义拷贝类变量指针
CCZone* pNewZone = NULL;
//定义序列帧动画类指针变量pCopy用于存储创建结果,置空。
CCAnimation* pCopy = NULL;
//如果参数pZone有效且已经有内部产生的实例拷贝。 if(pZone && pZone->m_pCopyObject)
{
//直接取得拷贝返回给pCopy.
pCopy = (CCAnimation*)(pZone->m_pCopyObject);
}
else
{
//如果参数pZone无值或者无内部产生的拷贝,重新生成单帧以及相应单帧的拷贝。
pCopy = new CCAnimation();
pNewZone = new CCZone(pCopy);
}
//初始化序列序动画。
pCopy->initWithAnimationFrames(m_pFrames, m_fDelayPerUnit, m_uLoops);
//设置相应变理。
pCopy->setRestoreOriginalFrame(m_bRestoreOriginalFrame);
//释放pNewZone.
CC_SAFE_DELETE(pNewZone);
return pCopy;
} NS_CC_END

最后我们看一下CCAnimate:

class CCTexture2D;
//序列帧动画
class CC_DLL CCAnimate : public CCActionInterval
{
public:
//构造与析构。
CCAnimate();
~CCAnimate(); //初始化动画。
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:
//保存每一帧要切换时的进度的容器指针,由动画信息结构指针取得。
std::vector<float>* m_pSplitTimes;
//当前要播放的下一帧序号。
int m_nNextFrame;
//各帧中保存的精灵信息。
CCSpriteFrame* m_pOrigFrame;
//循环次数。
unsigned int m_uExecutedLoops;
};
具体实现:
//创建一个序列帧动画,内部调用create实现。参数为动画信息结构。
CCAnimate* CCAnimate::actionWithAnimation(CCAnimation *pAnimation)
{
return CCAnimate::create(pAnimation);
}
//创建一个序列帧动画。
CCAnimate* CCAnimate::create(CCAnimation *pAnimation)
{
//使用new创建一个CCAnimate实例对象,初始化,交由内存管理器。
CCAnimate *pAnimate = new CCAnimate();
pAnimate->initWithAnimation(pAnimation);
pAnimate->autorelease();
//返回创建的实例对象。
return pAnimate;
}
//初始化序列动画。
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 = ;
//将参数pAnimation保存到动画信息结构指针变量m_pAnimation.
setAnimation(pAnimation);
m_pOrigFrame = NULL;
m_uExecutedLoops = ;
//设置容器大小。这里我认为应该写成resize而不是reserver!!!
m_pSplitTimes->reserve(pAnimation->getFrames()->count());
//初始化变量。
float accumUnitsOfTime = ;
//序列播放一轮的时间/
float newUnitOfTimeValue = singleDuration / pAnimation->getTotalDelayUnits();
//取得序列信息中的帧信息数组。
CCArray* pFrames = pAnimation->getFrames();
//判断pFrames是否是CCAnimationFrame指针类型,确保是。
CCARRAY_VERIFY_TYPE(pFrames, CCAnimationFrame*);
//定义临时变量pObj来遍历取得帧信息中的单帧信息。
CCObject* pObj = NULL;
CCARRAY_FOREACH(pFrames, pObj)
{
//取得单帧信息。
CCAnimationFrame* frame = (CCAnimationFrame*)pObj;
//计算播放当前单帧时的进度,这里又用到了单帧信息的接口getDelayUnits。后面讲一下。
float value = (accumUnitsOfTime * newUnitOfTimeValue) / singleDuration;
accumUnitsOfTime += frame->getDelayUnits();
//将当前单帧的进度存入容器。
m_pSplitTimes->push_back(value);
}
//返回成功。
return true;
}
//如果初始化失败,返回false。
return false;
}
//创建拷贝。
CCObject* CCAnimate::copyWithZone(CCZone *pZone)
{
CCZone* pNewZone = NULL;
CCAnimate* pCopy = NULL;
if(pZone && pZone->m_pCopyObject)
{
//in case of being called at sub class
pCopy = (CCAnimate*)(pZone->m_pCopyObject);
}
else
{
pCopy = new CCAnimate();
pZone = pNewZone = new CCZone(pCopy);
} CCActionInterval::copyWithZone(pZone); pCopy->initWithAnimation((CCAnimation*)m_pAnimation->copy()->autorelease()); CC_SAFE_DELETE(pNewZone);
return pCopy;
}
//构造,注意在这里申请了一个vector<float>容器,并将成员指针变量m_pSplitTimes指向它的。
CCAnimate::CCAnimate()
: m_pAnimation(NULL)
, m_pSplitTimes(new std::vector<float>)
, m_nNextFrame()
, m_pOrigFrame(NULL)
, m_uExecutedLoops()
{ }
//析构。
CCAnimate::~CCAnimate()
{
CC_SAFE_RELEASE(m_pAnimation);
CC_SAFE_RELEASE(m_pOrigFrame);
CC_SAFE_DELETE(m_pSplitTimes);
}
//设置演示当前序列动画的演员。
void CCAnimate::startWithTarget(CCNode *pTarget)
{
//先调用基类的相应函数。
CCActionInterval::startWithTarget(pTarget);
//序列帧动画必须是个精灵。
CCSprite *pSprite = (CCSprite*)(pTarget);
//释放上一个
CC_SAFE_RELEASE(m_pOrigFrame);
//如果有帧数据。
if (m_pAnimation->getRestoreOriginalFrame())
{
//取得精灵的帧信息。
m_pOrigFrame = pSprite->displayFrame();
//对帧信息占用,引用数加一。
m_pOrigFrame->retain();
}
m_nNextFrame = ;
m_uExecutedLoops = ;
}
//停止当前动画。
void CCAnimate::stop(void)
{
//如果动画有帧数据且有演员。
if (m_pAnimation->getRestoreOriginalFrame() && m_pTarget)
{
//设置演员显示当前帧。
((CCSprite*)(m_pTarget))->setDisplayFrame(m_pOrigFrame);
}
//停止当前动画。
CCActionInterval::stop();
}
//更新动画。
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循环。从下一帧开始到结束帧进行遍历,判断是否到了这一帧。
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();
//这才是显示动画的关键,找到相应的精灵帧并设置为演员要显示的当前帧。
((CCSprite*)m_pTarget)->setDisplayFrame(frameToDisplay);
//通过动画帧信息取得其附加的用户词典信息,这个词典存储的是用于需要通知的目标。
CCDictionary* dict = frame->getUserInfo();
if( dict )
{
//暂忽略了。
//TODO: [[NSNotificationCenter defaultCenter] postNotificationName:CCAnimationFrameDisplayedNotification object:target_ userInfo:dict];
}
//帧数加一。
m_nNextFrame = i+; break;
}
}
}
//创建一个反向播放的序列帧动画。
CCActionInterval* CCAnimate::reverse(void)
{
CCArray* pOldArray = m_pAnimation->getFrames();
CCArray* pNewArray = CCArray::createWithCapacity(pOldArray->count()); CCARRAY_VERIFY_TYPE(pOldArray, CCAnimationFrame*); if (pOldArray->count() > )
{
CCObject* pObj = NULL;
CCARRAY_FOREACH_REVERSE(pOldArray, pObj)
{
CCAnimationFrame* pElement = (CCAnimationFrame*)pObj;
if (! pElement)
{
break;
} pNewArray->addObject((CCAnimationFrame*)(pElement->copy()->autorelease()));
}
} CCAnimation *newAnim = CCAnimation::create(pNewArray, m_pAnimation->getDelayPerUnit(), m_pAnimation->getLoops());
newAnim->setRestoreOriginalFrame(m_pAnimation->getRestoreOriginalFrame());
return create(newAnim);
}

源码看完了,来看一个小示例 ,以ActionsTest为例,我将ActionAnimate做了稍许修改,只有一个演员演示一个14帧的序列帧动画。我们来看一下实际的动作生成过程。

void ActionAnimate::onEnter()
{
ActionsDemo::onEnter();
//创建一个演员,站在屏幕中央。
centerSprites();
//创建一个空白的序列帧动画信息。
CCAnimation* animation = CCAnimation::create();
//共有14帧,这里用for循环将对应的序列图加入到动画中。
for( int i=;i<;i++)
{
char szName[] = {};
sprintf(szName, "Images/grossini_dance_%02d.png", i);
animation->addSpriteFrameWithFileName(szName);
}
//设置每两帧间时间间隔为1秒。
animation->setDelayPerUnit(1.0f);
//设置动画结束后仍保留动画帧信息。
animation->setRestoreOriginalFrame(true);
//由这个动画信息创建一个序列帧动画。
CCAnimate* action = CCAnimate::create(animation);
//让演员演示这个动画。
m_grossini->runAction(action);
}

流程是先创建动画帧信息,然后由动画帧信息生成动画信息,最后由动画信息创建出序列帧动画供精灵演示。

这里面的关健函数是addSpriteFrameWithFileName,我们来看一下在调用它时的程序流程,当我们把图片名称赋给它后,它创建出纹理并调用createWithTexture函数来进行创建一个精灵单帧,初始化后使用这个精灵单帧信息创建一帧动画放到动画信息容器中。

void CCAnimation::addSpriteFrameWithFileName(const char *pszFileName)
{
CCTexture2D *pTexture = CCTextureCache::sharedTextureCache()->addImage(pszFileName);
CCRect rect = CCRectZero;
rect.size = pTexture->getContentSize();
CCSpriteFrame *pFrame = CCSpriteFrame::createWithTexture(pTexture, rect);
addSpriteFrame(pFrame);
}

在createWithTexture函数中,传入的是纹理和纹理大小。其内部实现了创建精灵帧并初始化的功能。

CCSpriteFrame* CCSpriteFrame::createWithTexture(CCTexture2D *pobTexture, const CCRect& rect)
{
CCSpriteFrame *pSpriteFrame = new CCSpriteFrame();;
pSpriteFrame->initWithTexture(pobTexture, rect);
pSpriteFrame->autorelease(); return pSpriteFrame;
}

这里的关帧是initWithTexture函数,传入的是纹理和纹理大小。

bool CCSpriteFrame::initWithTexture(CCTexture2D* pobTexture, const CCRect& rect)
{
CCRect rectInPixels = CC_RECT_POINTS_TO_PIXELS(rect);
return initWithTexture(pobTexture, rectInPixels, false, CCPointZero, rectInPixels.size);
}

我们看,此函数内部以不旋转,不偏移,原始大小为当前大小等参数来进行了初始化精灵单帧的处理。这样做说明使用的就是单图集的纹理。

如果我们使用的是图集纹理,需要在调用addSpriteFrameWithFileName函数时加上相应的纹理块的相关设置参数。

最后,我来解答一下CCAnimationFrame类中的成员变量m_fDelayUnits的。这个变量其实是无用的,在整个动画处理过程中它出现过二次。一次是CCAnimation::initWithAnimationFrames函数中

m_fTotalDelayUnits+= animFrame->getDelayUnits();

另一次是CCAnimate::initWithAnimation函数中在for循环中的

float value = (accumUnitsOfTime* newUnitOfTimeValue) / singleDuration;
accumUnitsOfTime+= frame->getDelayUnits();

先看第一次,我们知道m_fTotalDelayUnits代表的是帧的数量,其实对于单帧来说,它本身只有一帧,也就是说animFrame->getDelayUnits()的结果应该是1,所以m_fTotalDelayUnits += animFrame->getDelayUnits();应该改为m_fTotalDelayUnits ++;就好了。第二次中也一样,frame->getDelayUnits();也应该为一,因为float value =(accumUnitsOfTime * newUnitOfTimeValue) / singleDuration;这一句是用来进算当前帧在整个动画播放中的进度,float newUnitOfTimeValue = singleDuration /pAnimation->getTotalDelayUnits();这一句中singleDuration代表动画的时长,pAnimation->getTotalDelayUnits()代表总帧数,那newUnitOfTimeValue即是每两帧间的时间时间隔。既然newUnitOfTimeValue的意义是每两帧间的时间时间隔,则accumUnitsOfTime应该代表的就是当前遍历到第几帧了,它是帧索引。所以我认为CCAnimationFrame类中的成员变量m_fDelayUnits本身没有必要存在,就是1,这个变量的存在反而会影响到大家对于动画的理解,如果说CCAnimationFrame本身又支持存储多个精灵帧,那倒是需要一个变量来代表精灵帧的数量,但目前看并不是。

cocos2d-x 2.0 序列帧动画 深入分析的更多相关文章

  1. cocos2dx2.0 帧动画的创建和播放过程 深入分析

    一.帧动画的创建过程帧动画的实现有四个不可或缺的类,如下:1.CCSpriteFrame:精灵帧信息.存储帧动画的每一帧的纹理基本信息. class CC_DLL CCSpriteFrame : pu ...

  2. 时光煮雨 Unity3D实现2D人物动画① UGUI&Native2D序列帧动画

    系列目录 [Unity3D基础]让物体动起来①--基于UGUI的鼠标点击移动 [Unity3D基础]让物体动起来②--UGUI鼠标点击逐帧移动 时光煮雨 Unity3D让物体动起来③—UGUI DoT ...

  3. iOS-动画效果(首尾式动画,代码快动画,核心动画,序列帧动画)

    一.各个动画的优缺点 1.首尾动画:如果只是修改空间的属性,使用首尾动画比较方便,如果在动画结束后做后续处理,就不是那么方面了. 2.核心动画:有点在于对后续的处理方便. 3.块动画: (1)在实际的 ...

  4. 《Android开发艺术探索》读书笔记 (7) 第7章 Android动画深入分析

    本节和<Android群英传>中的第七章Android动画机制与使用技巧有关系,建议先阅读该章的总结 第7章 Android动画深入分析 7.1 View动画 (1)android动画分为 ...

  5. [Cocos2d-x v3.x]序列帧动画

      简单介绍 Cocos2d-x中.动画的详细内容是依靠精灵显示出来的,为了显示动态图片,我们须要不停切换精灵显示的内容.通过把静态的精灵变为动画播放器从而实现动画效果. 动画由帧组成,每一帧都是一个 ...

  6. Unity3d的序列帧动画

    马上这星期就要过去了,为了完成每星期写一篇博客的目标,熬夜也要写完. 最近项目中用到了很多序列帧动画,之前看教程也接触过序列帧动画,但当时没用到,就没仔细研究,这次就借着这个机会好好总结一下序列帧动画 ...

  7. (二)plist的使用和序列帧动画

    六.plist的使用方法: iOS的程序在安装在手机上以后会把全部资源文件集成在一个文件夹中,这种文件集合称为bundle,对于一般的工程,只有一个bundle,即mainbundle,因此可以通过b ...

  8. iOS开发基础-序列帧动画之Tom猫

    新建一个Single View Application,向该工程中导入Tom猫的图片资源,本示例演示Tom猫喝牛奶的动作.图片的名字为 drink_00.jpg.drink_01.jpg.....dr ...

  9. (转)NGUI系列教程七(序列帧动画UITexture 和 UIsprit)

    NGUI系列教程七(序列帧动画)   今天我给大家讲一下如何使用NGUI做序列帧动画.本节主要包括两方面内容,分别是使用UIspirit和使用UITexture 做序列帧动画.废话不说了,下面开始.还 ...

随机推荐

  1. ExtJs之Ext.core.DomHelper.append

    <!DOCTYPE html> <html> <head> <title>ExtJs</title> <meta http-equiv ...

  2. NodeJS路径的小问题

    今天从新过了一边node的基础知识,自己写了一个小例子: foo.js exports.setSome = function (x) {return x }; saveData.js /** * Cr ...

  3. Node 出现 uncaughtException 之后的优雅退出方案

    Node 的异步特性是它最大的魅力,但是在带来便利的同时也带来了不少麻烦和坑,错误捕获就是一个.由于 Node 的异步特性,导致我们无法使用 try/catch 来捕获回调函数中的异常,例如: try ...

  4. 深入理解Windows X64调试

    随着64位操作系统的普及,都开始大力进军x64,X64下的调试机制也发生了改变,与x86相比,添加了许多自己的新特性,之前学习了Windows x64的调试机制,这里本着“拿来主义”的原则与大家分享. ...

  5. php脚本的执行过程(编译与执行相分离)

    php脚本的执行过程(编译与执行相分离) 深入理解PHP代码的执行的过程 PHP程序的执行流程 Apache + PHP 的并发访问

  6. java Process的waitFor()

    java Process的waitFor() 在编写Java程序时,有时候我们需要调用其他的诸如exe,shell这样的程序或脚本.在Java中提供了两种方法来启动其他程序: (1) 使用Runtim ...

  7. libevent 定时器timer

    libevent是一个基于事件触发的网络库,memcached底层也是使用libevent库. 总体来说,libevent有下面一些特点和优势:* 事件驱动,高性能:* 轻量级,专注于网络: * 跨平 ...

  8. Hadoop2.2.0 安装笔记

    在Youtube上找到靠谱的教程:http://www.youtube.com/watch?v=WN2tJk_oL6E 同时把作者的教程下载下来放在百度云盘上了:http://pan.baidu.co ...

  9. IRQ和FIQ中断的区别【转】

    转自:http://blog.csdn.net/michaelcao1980/article/details/19542039 FIQ和IRQ是两种不同类型的中断,ARM为了支持这两种不同的中断,提供 ...

  10. YTU 2609: A改错题--学生信息的输入和输出

    2609: A改错题--学生信息的输入和输出 时间限制: 1 Sec  内存限制: 128 MB 提交: 238  解决: 157 题目描述 注:本题只需要提交标记为修改部分之间的代码,请按照C++方 ...