存档

2012年12月 的存档

Rotated Clipping Node in Cocos2d

2012年12月28日 没有评论

I’m using the clipping node here: http://www.learn-cocos2d.com/2011/01/cocos2d-gem-clippingnode

ClippingNode.h

#import "cocos2d.h"
@interface ClippingNode : CCNode {
    CGRect clippingRegionInNodeCoordinates;
    CGRect clippingRegion;
}
@property (nonatomic) CGRect clippingRegion;
@end

ClippingNode.m

#import "ClippingNode.h"

@interface ClippingNode (PrivateMethods)
-(void) deviceOrientationChanged:(NSNotification*)notification;
@end

@implementation ClippingNode
-(CGRect) clippingRegion {
    return clippingRegionInNodeCoordinates;
}

-(void) setClippingRegion:(CGRect)region {

    // keep the original region coordinates in case the user wants them back unchanged
    clippingRegionInNodeCoordinates = region;
    self.position = clippingRegionInNodeCoordinates.origin;
    self.contentSize = clippingRegionInNodeCoordinates.size;

    // convert to retina coordinates if needed
    region = CC_RECT_POINTS_TO_PIXELS(region);

    // respect scaling
    clippingRegion = CGRectMake(region.origin.x * scaleX_, region.origin.y * scaleY_,
                            region.size.width * scaleX_, region.size.height * scaleY_);
}

-(void) setScale:(float)newScale {
    [super setScale:newScale];
    // re-adjust the clipping region according to the current scale factor
    [self setClippingRegion:clippingRegionInNodeCoordinates];
}

-(void) deviceOrientationChanged:(NSNotification*)notification {
    // re-adjust the clipping region according to the current orientation
    [self setClippingRegion:clippingRegionInNodeCoordinates];
}

-(void) visit {

    glEnable(GL_SCISSOR_TEST);
    CGPoint worldPosition = [self convertToWorldSpace:CGPointZero];
    const CGFloat s = [[CCDirector sharedDirector] contentScaleFactor];
    glScissor((clippingRegion.origin.x) + (worldPosition.x*s), (clippingRegion.origin.y) + (worldPosition.y*s),
          (clippingRegion.size.width), (clippingRegion.size.height));

    [super visit];

    glDisable(GL_SCISSOR_TEST);

}
@end

However, I need to clip a rotated CCNode. Any idea on how I could accomplish such a task?

Replace the visit method in the class ClippingNode by this

-(void) visit
{

    float rotationAngle = 15;

    glPushMatrix();

    CCRenderTexture* renderTexture = [[CCRenderTexture renderTextureWithWidth:512 height:512] retain];

    glEnable(GL_SCISSOR_TEST);
    glScissor(0, 0, clippingRegion.size.width, clippingRegion.size.height);

    [renderTexture begin];

    glPushMatrix();
    glRotatef(rotationAngle, 0, 0, 1);
    glTranslatef(-clippingRegion.origin.x, -clippingRegion.origin.y, 0);

    [super visit];

    glPopMatrix();

    [renderTexture end];

    glDisable(GL_SCISSOR_TEST);

    renderTexture.sprite.position = CGPointMake(clippingRegion.origin.x , clippingRegion.origin.y);
    renderTexture.sprite.anchorPoint = CGPointMake(0, 1);
    renderTexture.sprite.rotation = rotationAngle;
    [renderTexture.sprite visit];

    [renderTexture release];

    glPopMatrix();
}

Basically it creates a texture where to render the ClippingNode contents

Then translate the scene so that the origin in the clipping region is now at (0,0)

Rotate the entire scene by rotationAngle

Enable the scissor

Render the scene

Translate, rotate, and render the sprite containing the texture

Rotated Clipping Node in Cocos2d

It only needs CCRenderTexture to finish the job. Any suggestion will be greatly appreciated.

ClippingNode.h

#import "cocos2d.h"
@interface ClippingNode : CCNode
@property (nonatomic, assign) CGSize clippingSize;
@end

ClippingNode.m

#import "ClippingNode.h"
@interface ClippingNode()
@property (nonatomic, strong) CCRenderTexture * renderTexture;
@property (nonatomic, strong) CCSprite * clippedSprite;
@end


@implementation ClippingNode
@synthesize renderTexture;
@synthesize clippedSprite;
@synthesize clippingSize;

- (void) setClippingSize:(CGSize)newClippingSize {

    //assignment
    clippingSize = newClippingSize;

    //set contentSize
    self.contentSize = clippingSize;

    //configure renderTexture
    self.renderTexture = [CCRenderTexture renderTextureWithWidth:clippingSize.width height:clippingSize.height];
    renderTexture.contentSize = CGSizeMake(clippingSize.width, clippingSize.height);

    //configure the renderTexture sprite
    self.clippedSprite = [CCSprite spriteWithTexture:renderTexture.sprite.texture];
    clippedSprite.position = self.position;
    clippedSprite.rotation = rotation_;
    clippedSprite.scaleY = -1;
}

- (void)visit {
    [renderTexture beginWithClear:0 g:0 b:0 a:1];
    [super visit];
    [renderTexture end];

    [clippedSprite visit];
}

@end

Usage:

CCSprite * spriteImage = ...;
spriteImage.position = ccp(0,0);
spriteImage.anchorPoint = ccp(0.5,0.5);

//configure clipping Node
self.clippingNode = [ClippingNode node];
clippingNode.position = ccp(size.width * 0.5f, size.height * 0.5f);
clippingNode.anchorPoint = ccp(0.5f, 0.5f);
clippingNode.rotation = -10.0f;

//configure clipping region
[clippingNode setClippingSize:CGSizeMult(spriteImage.boundingBox.size, 1.5f)];

//add content to the clipping node
[clippingNode addChild:spriteImage]
分类: cocos2d, stackoverflow精选 标签:

Cocos2d-x 2.0 网格动画深入分析

2012年12月28日 没有评论

[Cocos2d-x相关教程来源于红孩儿的游戏编程之路CSDN博客地址:http://blog.csdn.net/honghaier]

红孩儿Cocos2d-X学习园地QQ2群:44208467 加群写:Cocos2d-x 
红孩儿Cocos2d-X学习园地QQ群:249941957 [暂满]加群写:Cocos2d-x 

本章为我的Cocos2d-x教程一书初稿。望各位看官多提建议!

Cocos2d-x 2.0 网格动画深入分析

另:本章所用Cocos2d-x版本为:

cocos2d-2.0-x-2.0.2 @ Aug 30 2012

http://cn.cocos2d-x.org/download

        写在前面:请各位大大在转载博文时注明来源,红孩儿每天熬夜写博实属不易,但屡有一些同学拿来主义,把本博的文章去头掐尾,抹掉作者,然后赤裸裸的改成自已的 " 原创  ",实在令人气愤。在此特声明:本博博文,欢迎您收藏,转载,如果有需要,也可以借用段落或插图,请您经我同意,我不是一个刻板吝啬的人。但如果直接剽窃,我将奋起反击!

       

        在TestCpp中的EffectsTest示例中展示了一些屏幕特效,它是将屏幕划分为多个格子,并对这些格子进行了动画处理从而产生出相应的屏幕特效。今天我们来学习一下这些动画。

主要是涉及到以下几个文件:

CCGrid.h /cpp :网格数据及渲染,包括基本网格数据和3D网格数据,这是数据的基础。

CCActionGrid.h /cpp :网格基本动画,这是动画的基础。

CCActionGrid3D.h/cpp: 3D网格基本动画,这是3D网格动画的基础。

CCActionTiledGrid.h / cpp :网格衍生动画,这是最终的特效实现。

咱们首先来看 关于网格数据及渲染的文件:CCGrid.h  

#ifndef __EFFECTS_CCGRID_H__
#define __EFFECTS_CCGRID_H__


#include "cocoa/CCObject.h"
#include "base_nodes/CCNode.h"
#include "CCCamera.h"
#include "ccTypes.h"
#include "textures/CCTexture2D.h"
#include "CCDirector.h"
#include "kazmath/mat4.h"

//使用Cocos2d命名空间
NS_CC_BEGIN

//当前.h文件要用到以下三个类的指针。

class CCTexture2D;
class CCGrabber;
class CCGLProgram;

//网格基类。由CCObject派生。
class CC_DLL CCGridBase : public CCObject
{
public:
	//析构
    virtual ~CCGridBase(void);

    //是否激活状态。
inline bool isActive(void) { return m_bActive; }
//设置为激活状态。
    void setActive(bool bActive);

    //取得
    inline int getReuseGrid(void) { return m_nReuseGrid; }
    inline void setReuseGrid(int nReuseGrid) { m_nReuseGrid = nReuseGrid; }

    //取得网格的大小。
inline const ccGridSize& getGridSize(void) { return m_sGridSize; }
//设置网格的大小。
    inline void setGridSize(const ccGridSize& gridSize) { m_sGridSize = gridSize; }

    //取得每个格子占用的图像点数。即图像大于与格子大小的比值。
    inline const CCPoint& getStep(void) { return m_obStep; }
    inline void setStep(const CCPoint& step) { m_obStep = step; }

    //取得纹理是否上下反转
inline bool isTextureFlipped(void) { return m_bIsTextureFlipped; }
//设置纹理是否上下反转。
    void setTextureFlipped(bool bFlipped);

	//初始化网格,参一为网格大小,参二为对应的纹理,参三为设置纹理是否反转。
bool initWithSize(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped);
////初始化网格,参数为网格大小。
    bool initWithSize(const ccGridSize& gridSize);
	
	//在渲染之前要做的处理。
void beforeDraw(void);
//在渲染之后要做的处理。
void afterDraw(CCNode *pTarget);
//渲染处理
virtual void blit(void);
//还原到原顶点位置
virtual void reuse(void);
//计算顶点缓冲
    virtual void calculateVertexPoints(void);

public:
    //详细创建函数,参一为网格大小,参二为对应的纹理,参三为设置纹理是否反转。内部调用create实现。
CC_DEPRECATED_ATTRIBUTE static CCGridBase* gridWithSize(const ccGridSize& gridSize, CCTexture2D *texture, bool flipped);
    
//简单创建函数,参数为网格大小。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCGridBase* gridWithSize(const ccGridSize& gridSize);

    //对应详细创建函数的create实现。
    static CCGridBase* create(const ccGridSize& gridSize, CCTexture2D *texture, bool flipped);
//对应简单创建函数的create实现。
static CCGridBase* create(const ccGridSize& gridSize);

	//设置2D投影矩阵。
    void set2DProjection(void);

protected:
	//是否被激活。
    bool m_bActive;
int  m_nReuseGrid;
//格子大小
ccGridSize m_sGridSize;
//所用纹理
CCTexture2D *m_pTexture;
//每格的图像点数
CCPoint m_obStep;
//将屏幕画面渲染到纹理的处理器。
CCGrabber *m_pGrabber;
//纹理是否上下反转。
bool m_bIsTextureFlipped;
//Shader代码片段指针。
CCGLProgram* m_pShaderProgram;
//投影方式
    ccDirectorProjection m_directorProjection;
};

对应CPP:
//简单创建函数,参一为网格大小,参二为对应的纹理,参三为设置纹理是否反转。内部调用create实现。CCGridBase* CCGridBase::gridWithSize(const ccGridSize& gridSize)
{
    return CCGridBase::create(gridSize);
}

//对应简单创建函数的create实现。
CCGridBase* CCGridBase::create(const ccGridSize& gridSize)
{
	//先new出一个当前类实例。
    CCGridBase *pGridBase = new CCGridBase();
	//如果成功
    if (pGridBase)
{
	 //进行初始化。
        if (pGridBase->initWithSize(gridSize))
        {
			 //如果初始化成功交由内存管理器进行管理。
            pGridBase->autorelease();
        }
        else
        {
			 //如果失败释放并置空。
            CC_SAFE_RELEASE_NULL(pGridBase);
        }
    }
	//如果成功返回创建的类实例,否则反回NULL。
    return pGridBase;
}

//详细创建函数,参数为网格大小。内部调用create实现。
CCGridBase* CCGridBase::gridWithSize(const ccGridSize& gridSize, CCTexture2D *texture, bool flipped)
{
    return CCGridBase::create(gridSize, texture, flipped);
}
//对应详细创建函数的create实现。
CCGridBase* CCGridBase::create(const ccGridSize& gridSize, CCTexture2D *texture, bool flipped)
{
	//先new出一个当前类实例。
    CCGridBase *pGridBase = new CCGridBase();
	//如果成功
    if (pGridBase)
    {	//进行初始化。
        if (pGridBase->initWithSize(gridSize, texture, flipped))
        {   //如果初始化成功交由内存管理器进行管理。
            pGridBase->autorelease();
        }
        else
        {  //如果失败释放并置空。
            CC_SAFE_RELEASE_NULL(pGridBase);
        }
    }
	//如果成功返回创建的类实例,否则反回NULL。
    return pGridBase;
}
//初始化函数。
bool CCGridBase::initWithSize(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped)
{
    bool bRet = true;
	//未激活。
    m_bActive = false;
m_nReuseGrid = 0;
//保存格子大小。
    m_sGridSize = gridSize;
	//保存纹理。
m_pTexture = pTexture;
//占用纹理,对其引用计数器加一操作。
CC_SAFE_RETAIN(m_pTexture);
//保存是否进行纹理反转的变量。
    m_bIsTextureFlipped = bFlipped;
	//取得纹理中的图像大小。
const CCSize& texSize = m_pTexture->getContentSize();
//计算出一个格子所占的纹理寻址长度。
    m_obStep.x = texSize.width / m_sGridSize.x;
    m_obStep.y = texSize.height / m_sGridSize.y;
	//新建一个屏幕图像获取器,这家伙是干嘛的?其实就是一个获取屏幕图像的类,可以将屏幕上渲染出的图像输出到一张指定的纹理中,类似DX中的RTT。

    m_pGrabber = new CCGrabber();
    if (m_pGrabber)
{
	 //将纹理设置为输出纹理。
        m_pGrabber->grab(m_pTexture);
    }
    else
{
	 //如果图像获取器创建失败,做下返回值处理。
        bRet = false;
    }
    //取得对应的Shader代码片段。
m_pShaderProgram = CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTexture);
//计算所要用到的顶点数据并创建顶点缓冲区。
    calculateVertexPoints();

    return bRet;
}

//初始化。
bool CCGridBase::initWithSize(const ccGridSize& gridSize)
{
	//取得设备指针,并通过它取得屏幕大小。
    CCDirector *pDirector = CCDirector::sharedDirector();
    CCSize s = pDirector->getWinSizeInPixels();
    //计算相应大小对应的2次幂大小。
    unsigned long POTWide = ccNextPOT((unsigned int)s.width);
    unsigned long POTHigh = ccNextPOT((unsigned int)s.height);

    // 使用ARGB8888格式。
    CCTexture2DPixelFormat format = kCCTexture2DPixelFormat_RGBA8888;
	//创建相应的像素绘冲区。
    void *data = calloc((int)(POTWide * POTHigh * 4), 1);
    if (! data)
    {
        CCLOG("cocos2d: CCGrid: not enough memory.");
        this->release();
        return false;
}

	//创建一个纹理。
CCTexture2D *pTexture = new CCTexture2D();
//使用像素数据初始化纹理。
    pTexture->initWithData(data, format, POTWide, POTHigh, s);
    //释放像素数据。
    free(data);
	//如果失败,返回false。
    if (! pTexture)
    {
        CCLOG("cocos2d: CCGrid: error creating texture");
        delete this;
        return false;
    }
	//使用创建的纹理初始化
    initWithSize(gridSize, pTexture, false);
	//释放纹理。
pTexture->release();

    return true;
}

//析构。
CCGridBase::~CCGridBase(void)
{
    CCLOGINFO("cocos2d: deallocing %p", this);
//释放纹理。
CC_SAFE_RELEASE(m_pTexture);
//释放屏幕
    CC_SAFE_RELEASE(m_pGrabber);
}

//设置激活。
void CCGridBase::setActive(bool bActive)
{
	//保存激活设置
    m_bActive = bActive;
    if (! bActive)
{
	 //如果未激活,复原投影矩阵。
        CCDirector *pDirector = CCDirector::sharedDirector();
        ccDirectorProjection proj = pDirector->getProjection();
        pDirector->setProjection(proj);
    }
}
//设置纹理反转。
void CCGridBase::setTextureFlipped(bool bFlipped)
{
	//如果参数与原设置不同,更新设置并计算顶点缓冲。
    if (m_bIsTextureFlipped != bFlipped)
    {
        m_bIsTextureFlipped = bFlipped;
        calculateVertexPoints();
    }
}

//设置2D投影。
void CCGridBase::set2DProjection()
{
	//取得窗口大小
    CCDirector *director = CCDirector::sharedDirector();
    CCSize    size = director->getWinSizeInPixels();
	//重新设置视口大小
glViewport(0, 0, (GLsizei)(size.width * CC_CONTENT_SCALE_FACTOR()), (GLsizei)(size.height * CC_CONTENT_SCALE_FACTOR()) );
//开始设置投影矩阵。
kmGLMatrixMode(KM_GL_PROJECTION);
//先将投影矩阵单位化。
    kmGLLoadIdentity();
	//创建一个矩阵变量。
kmMat4 orthoMatrix;
//通过参数生成出投影矩阵变量的值,此处使用的是正交投影矩阵。
kmMat4OrthographicProjection(&orthoMatrix, 0, size.width * CC_CONTENT_SCALE_FACTOR(), 0, size.height * CC_CONTENT_SCALE_FACTOR(), -1, 1);
//将原单位化矩阵与正交投影矩阵相乘,当然还是正交投影矩阵了,做为投影矩阵的结果。
    kmGLMultMatrix( &orthoMatrix );
	//下面开始设置模型观察矩阵。
kmGLMatrixMode(KM_GL_MODELVIEW);
//将矩阵单位化。
    kmGLLoadIdentity();

	//设置投影矩阵。
    ccSetProjectionMatrixDirty();
}

//在开始渲染前的处理。
void CCGridBase::beforeDraw(void)
{
    // 先取得当前的投影矩阵保存到变量中
    CCDirector *director = CCDirector::sharedDirector();
    m_directorProjection = director->getProjection();

    // 设置新的投影矩阵。
set2DProjection();
// 设置开启屏幕渲染到纹理。
    m_pGrabber->beforeRender(m_pTexture);
}

//在渲染结束后的处理。
void CCGridBase::afterDraw(cocos2d::CCNode *pTarget)
{
	//设置完成屏幕渲染到纹理。
    m_pGrabber->afterRender(m_pTexture);

    //恢复原投影矩阵。
    CCDirector *director = CCDirector::sharedDirector();
    director->setProjection(m_directorProjection);
	//
    if (pTarget->getCamera()->isDirty())
{
	 //取得演示的锚点做为摄像机的矩阵转换中心点。
        const CCPoint& offset = pTarget->getAnchorPointInPoints();

		//注意:下面三句的意义是对摄像机进行矩阵变换,这个矩阵变换是相对于自身中心点位置,俗称自身矩阵变换。
        //先将当前模型矩阵偏移到这个中心点。
        kmGLTranslatef(offset.x, offset.y, 0);
		 //进行本地矩阵的转换
        pTarget->getCamera()->locate();
		 //恢复原位置。
        kmGLTranslatef(-offset.x, -offset.y, 0);
		
    }
	//设置使用纹理。
    ccGLBindTexture2D(m_pTexture->getName());

    // restore projection for default FBO .fixed bug #543 #544
//TODO:         CCDirector::sharedDirector()->setProjection(CCDirector::sharedDirector()->getProjection());
//TODO:         CCDirector::sharedDirector()->applyOrientation();
	//进行渲染
    blit();
}

//进行渲染
void CCGridBase::blit(void)
{
    CCAssert(0, "");
}

//还原到原来顶点位置。
void CCGridBase::reuse(void)
{
    CCAssert(0, "");
}

//计算顶点缓冲区。
void CCGridBase::calculateVertexPoints(void)
{
    CCAssert(0, "");
}



//3D网格类,派生于格子基类,
class CC_DLL CCGrid3D : public CCGridBase
{
public:
	//构造
CCGrid3D();
//析构
    ~CCGrid3D(void);

    //返回对应位置的顶点。
    ccVertex3F vertex(const ccGridSize& pos);
    //返回对应位置的原始顶点。
    ccVertex3F originalVertex(const ccGridSize& pos);
    //设置对应位置的顶点。
    void setVertex(const ccGridSize& pos, const ccVertex3F& vertex);
	//重载基类的函数。
	//渲染。
virtual void blit(void);
//还原到原来顶点位置
virtual void reuse(void);
//计算顶点缓冲。
    virtual void calculateVertexPoints(void);

public:
    //静态函数:详细参数的创建3D网格,参一为格子大小,参二为纹理指针,参三为是否进行纹理反转,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCGrid3D* gridWithSize(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped);
    //静态函数:简单参数的创建3D网格,参数为格子大小,内部调用create实现。

    CC_DEPRECATED_ATTRIBUTE static CCGrid3D* gridWithSize(const ccGridSize& gridSize);
    
    //详细参数的创建3D网格
    static CCGrid3D* create(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped);
    //简单参数的创建3D网格
    static CCGrid3D* create(const ccGridSize& gridSize);
    
protected:
	//顶点缓冲指针_纹理UV
GLvoid *m_pTexCoordinates;
//顶点缓冲指针_位置
GLvoid *m_pVertices;
//原始顶点缓冲指针_位置
GLvoid *m_pOriginalVertices;
//索引缓冲指针
    GLushort *m_pIndices;
};

对应CPP:
//静态函数:详细参数的创建3D网格,参一为格子大小,参二为纹理指针,参三为是否进行纹理反转,内部调用create实现。
CCGrid3D* CCGrid3D::gridWithSize(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped)
{
    return CCGrid3D::create(gridSize, pTexture, bFlipped);
}
//上面的create实现
CCGrid3D* CCGrid3D::create(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped)
{
	//先new出一个当前类实例
    CCGrid3D *pRet= new CCGrid3D();
	//如果成功
    if (pRet)
{
	//初始化并交由内存管理器进行引用计数器的管理
        if (pRet->initWithSize(gridSize, pTexture, bFlipped))
        {
            pRet->autorelease();
        }
        else
        {	//如果失败,则释放并置空。
            delete pRet;
            pRet = NULL;
        }
    }
	//返回结果。
    return pRet;
}
//简单参数的创建3D网格,内部调用create实现。
CCGrid3D* CCGrid3D::gridWithSize(const ccGridSize& gridSize)
{
    return CCGrid3D::create(gridSize);
}
//上面函数的create实现。
CCGrid3D* CCGrid3D::create(const ccGridSize& gridSize)
{	//先new出一个当前类实例
    CCGrid3D *pRet= new CCGrid3D();
	//如果成功
    if (pRet)
{	
//初始化并交由内存管理器进行引用计数器的管理
        if (pRet->initWithSize(gridSize))
        {
            pRet->autorelease();
        }
        else
        {	//如果失败,则释放并置空。
            delete pRet;
            pRet = NULL;
        }
    }
//返回结果。
    return pRet;
}

//构造
CCGrid3D::CCGrid3D()
    : m_pTexCoordinates(NULL)
    , m_pVertices(NULL)
    , m_pOriginalVertices(NULL)
    , m_pIndices(NULL)
{

}
//析构
CCGrid3D::~CCGrid3D(void)
{
	//释放各缓冲区
    CC_SAFE_FREE(m_pTexCoordinates);
    CC_SAFE_FREE(m_pVertices);
    CC_SAFE_FREE(m_pIndices);
    CC_SAFE_FREE(m_pOriginalVertices);
}
//进行渲染处理
void CCGrid3D::blit(void)
{
	//计算格子的数量
    int n = m_sGridSize.x * m_sGridSize.y;

    //设置渲染顶点的格式
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );
//开启使用Shader
m_pShaderProgram->use();
//设置Shader中的 顶点矩阵,其值 = 投影矩阵X模型矩阵X观察矩阵的结果,用于在Shader中进行顶点的最终位置计算。
    m_pShaderProgram->setUniformForModelViewProjectionMatrix();;


    //顶点缓冲中位置属性的指定。
    glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, 0, m_pVertices);

    //顶点缓冲中纹理贴图UV属性的指定。
    glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, m_pTexCoordinates);

	//绘制三角形,每个格子两个三角形,使用GL_TRIANGLES方式进行绘制,则每个格子需要6个顶点。所以顶点数为n*6,渲染时按照索引绘冲m_pIndices所指定的三角形顶点索引来进行绘制。
glDrawElements(GL_TRIANGLES, (GLsizei) n*6, GL_UNSIGNED_SHORT, m_pIndices);
//增加一次DP统计值。
    CC_INCREMENT_GL_DRAWS(1);
}
//计算顶点缓冲数据
void CCGrid3D::calculateVertexPoints(void)
{
	//取得纹理的宽高。
    float width = (float)m_pTexture->getPixelsWide();
float height = (float)m_pTexture->getPixelsHigh();
//取得纹理中图像区域的高度。
    float imageH = m_pTexture->getContentSizeInPixels().height;

	//定义临时变量。
int x, y, i;
//如果相应的顶点缓冲数据有值,先释放干净并置空。
    CC_SAFE_FREE(m_pVertices);
    CC_SAFE_FREE(m_pOriginalVertices);
    CC_SAFE_FREE(m_pTexCoordinates);
    CC_SAFE_FREE(m_pIndices);
	//计算总顶点数,每一行的顶点数为格子列数+1,每一列的顶点数为格子行数+1。
    unsigned int numOfPoints = (m_sGridSize.x+1) * (m_sGridSize.y+1);
	//为相应的顶点缓冲区申请相应大小的内存。
	//m_pVertices中存入的是顶点位置,使用ccVertex3F来存储。所申请的内存大小即为顶点数乘以ccVertex3F的字节数大小。
m_pVertices = malloc(numOfPoints * sizeof(ccVertex3F));
//同上。
m_pOriginalVertices = malloc(numOfPoints * sizeof(ccVertex3F));
//纹理UV使用ccVertex2F来存储。
m_pTexCoordinates = malloc(numOfPoints * sizeof(ccVertex2F));
//索引缓冲m_pIndices使用GLushort来存储绘制三角形所用的顶点的索引值,因为每个面3个索引,一个格子就需要6个索引。
    m_pIndices = (GLushort*)malloc(m_sGridSize.x * m_sGridSize.y * sizeof(GLushort) * 6);
	
	//为了方便填充数据,将缓冲区地址转换成相应的指针变量。
    GLfloat *vertArray = (GLfloat*)m_pVertices;
    GLfloat *texArray = (GLfloat*)m_pTexCoordinates;
    GLushort *idxArray = m_pIndices;

	//双循环遍历每个格子。
    for (x = 0; x < m_sGridSize.x; ++x)
    {
        for (y = 0; y < m_sGridSize.y; ++y)
        {
			 //取得格子索引。
            int idx = (y * m_sGridSize.x) + x;

			 //取得格子的左上角和右下角在图像中的相应位置。m_obStep是每个格子占用的图像点数。
            GLfloat x1 = x * m_obStep.x;
            GLfloat x2 = x1 + m_obStep.x;
            GLfloat y1 = y * m_obStep.y;
            GLfloat y2= y1 + m_obStep.y;

			 //取得格子的四个顶点的索引。
            GLushort a = (GLushort)(x * (m_sGridSize.y + 1) + y);
            GLushort b = (GLushort)((x + 1) * (m_sGridSize.y + 1) + y);
            GLushort c = (GLushort)((x + 1) * (m_sGridSize.y + 1) + (y + 1));
            GLushort d = (GLushort)(x * (m_sGridSize.y + 1) + (y + 1));

			 //按照三角形的绘制方式将格子顶点的索引组成两个三角形的顶点索引。
            GLushort tempidx[6] = {a, b, d, b, c, d};

			 //填充到相应的索引缓冲中。
            memcpy(&idxArray[6*idx], tempidx, 6*sizeof(GLushort));

			  //格子四个顶点的位置。
            int l1[4] = {a*3, b*3, c*3, d*3};
            ccVertex3F e = {x1, y1, 0};
            ccVertex3F f = {x2, y1, 0};
            ccVertex3F g = {x2, y2, 0};
            ccVertex3F h = {x1, y2, 0};

            ccVertex3F l2[4] = {e, f, g, h};

            int tex1[4] = {a*2, b*2, c*2, d*2};
            CCPoint tex2[4] = {ccp(x1, y1), ccp(x2, y1), ccp(x2, y2), ccp(x1, y2)};
			 //遍历放入相应的顶点位置和纹理UV中。
            for (i = 0; i < 4; ++i)
            {
				  //顶点的x,y,z
                vertArray[l1[i]] = l2[i].x;
                vertArray[l1[i] + 1] = l2[i].y;
                vertArray[l1[i] + 2] = l2[i].z;

				  //纹理U值
                texArray[tex1[i]] = tex2[i].x / width;
				  //纹理V值
                if (m_bIsTextureFlipped)
                {
					  //上下反转
                    texArray[tex1[i] + 1] = (imageH - tex2[i].y) / height;
                }
                else
                {
					  //正常
                    texArray[tex1[i] + 1] = tex2[i].y / height;
                }
            }
        }
    }
	//将顶点位置数据填充到保存原始顶点位置的内存中。
    memcpy(m_pOriginalVertices, m_pVertices, (m_sGridSize.x+1) * (m_sGridSize.y+1) * sizeof(ccVertex3F));
}
//返回对应网格位置的顶点。
ccVertex3F CCGrid3D::vertex(const ccGridSize& pos)
{
	//通过网格位置计算出起始顶点的索引。
int index = (pos.x * (m_sGridSize.y+1) + pos.y) * 3;
//为方便获取顶点数据,将顶点缓冲地址转换为相应的指针变量。
    float *vertArray = (float*)m_pVertices;
	//通过索引取得相应的顶点x,y,z。
    ccVertex3F vert = {vertArray[index], vertArray[index+1], vertArray[index+2]};
	//返回顶点
    return vert;
}
//返回网格对应位置的原始顶点。
ccVertex3F CCGrid3D::originalVertex(const ccGridSize& pos)
{
	//通过格子位置计算出起始顶点的索引。
    int index = (pos.x * (m_sGridSize.y+1) + pos.y) * 3;
 //为方便获取顶点数据,将顶点缓冲地址转换为相应的指针变量。
float *vertArray = (float*)m_pOriginalVertices;
	//通过索引取得相应的顶点x,y,z。
    ccVertex3F vert = {vertArray[index], vertArray[index+1], vertArray[index+2]};
	//返回顶点
    return vert;
}
//设置对应网格位置的顶点。
void CCGrid3D::setVertex(const ccGridSize& pos, const ccVertex3F& vertex)
{	//通过格子位置计算出起始顶点的索引。
int index = (pos.x * (m_sGridSize.y + 1) + pos.y) * 3;
//为方便获取顶点数据,将顶点缓冲地址转换为相应的指针变量。
float *vertArray = (float*)m_pVertices;
设置对应索引位置的顶点的x,y,z。
    vertArray[index] = vertex.x;
    vertArray[index+1] = vertex.y;
    vertArray[index+2] = vertex.z;
}
//还原原来位置。
void CCGrid3D::reuse(void)
{
	//如果还原格子的变量大于0。
    if (m_nReuseGrid > 0)
{
	 //将原始顶点位置拷贝到顶点缓冲中。
        memcpy(m_pOriginalVertices, m_pVertices, (m_sGridSize.x+1) * (m_sGridSize.y+1) * sizeof(ccVertex3F));
		//还原格子的变量做减1操作。
        --m_nReuseGrid;
    }
}

//这也是一个网格类,但它在网格的每个位置点存的不是一个顶点,而是一个四边形格子。
class CC_DLL CCTiledGrid3D : public CCGridBase
{
public:
	//构造
CCTiledGrid3D();
//析构
    ~CCTiledGrid3D(void);

    //返回相应位置的格子数据
    ccQuad3 tile(const ccGridSize& pos);
    //返回原始位置的格子数据。
    ccQuad3 originalTile(const ccGridSize& pos);
    //设置相应位置的格子数据。
    void setTile(const ccGridSize& pos, const ccQuad3& coords);
	//重载相应基类函数。
    virtual void blit(void);
    virtual void reuse(void);
    virtual void calculateVertexPoints(void);

public:
	//静态函数:创建一个当前类的实例。参一为格子大小,参二为对应的纹理,参三为是否进行纹理反转。内部调用create实现。
CC_DEPRECATED_ATTRIBUTE static CCTiledGrid3D* gridWithSize(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped);
//上面函数的简化版本。
    CC_DEPRECATED_ATTRIBUTE static CCTiledGrid3D* gridWithSize(const ccGridSize& gridSize);
    //对应创建函数的实现。
    static CCTiledGrid3D* create(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped);
    //对应创建函数的实现。
    static CCTiledGrid3D* create(const ccGridSize& gridSize);
    
protected:
	//所要用到的顶点数据缓冲区。
    GLvoid *m_pTexCoordinates;
    GLvoid *m_pVertices;
    GLvoid *m_pOriginalVertices;
    GLushort *m_pIndices;
};

对应CPP:
//构造函数。
CCTiledGrid3D::CCTiledGrid3D()
    : m_pTexCoordinates(NULL)
    , m_pVertices(NULL)
    , m_pOriginalVertices(NULL)
    , m_pIndices(NULL)
{

}
//析构函数。
CCTiledGrid3D::~CCTiledGrid3D(void)
{
	//释放各顶点所用的数据缓冲区。
    CC_SAFE_FREE(m_pTexCoordinates);
    CC_SAFE_FREE(m_pVertices);
    CC_SAFE_FREE(m_pOriginalVertices);
    CC_SAFE_FREE(m_pIndices);
}
//静态函数:创建一个当前类的实例。参一为格子大小,参二为对应的纹理,参三为是否进行纹理反转。内部调用create实现。

CCTiledGrid3D* CCTiledGrid3D::gridWithSize(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped)
{
    return CCTiledGrid3D::create(gridSize, pTexture, bFlipped);
}
//上面函数的具体实现。
CCTiledGrid3D* CCTiledGrid3D::create(const ccGridSize& gridSize, CCTexture2D *pTexture, bool bFlipped)
{
	//先用new创建一个当前类的实例。
    CCTiledGrid3D *pRet= new CCTiledGrid3D();
	//如果成功。
    if (pRet)
{
	//进行初始化并交由内存管理器进行引用计数器的管理。
        if (pRet->initWithSize(gridSize, pTexture, bFlipped))
        {
            pRet->autorelease();
        }
        else
        {
			 //如果失败,释放new出来的实例指针并置空。
            delete pRet;
            pRet = NULL;
        }
    }
	//返回实例指针。
    return pRet;
}

//静态函数:创建一个当前类的实例。简化版本。
CCTiledGrid3D* CCTiledGrid3D::gridWithSize(const ccGridSize& gridSize)
{
    return CCTiledGrid3D::create(gridSize);
}
//上面函数的具体实现。
CCTiledGrid3D* CCTiledGrid3D::create(const ccGridSize& gridSize)
{	
//先用new创建一个当前类的实例。
    CCTiledGrid3D *pRet= new CCTiledGrid3D();

    if (pRet)
{
	/进行初始化并交由内存管理器进行引用计数器的管理。
        if (pRet->initWithSize(gridSize))
        {
            pRet->autorelease();
        }
        else
        {
			//如果失败,释放new出来的实例指针并置空。
            delete pRet;
            pRet = NULL;
        }
    }
	//返回实例指针。
    return pRet;
}
//实际渲染处理。
void CCTiledGrid3D::blit(void)
{
	//取得格子的数量。
    int n = m_sGridSize.x * m_sGridSize.y;

    //开启使用shader片段
m_pShaderProgram->use();
//设置Shader中的 顶点矩阵,其值 = 投影矩阵X模型矩阵X观察矩阵的结果,用于在Shader中进行顶点的最终位置计算。
    m_pShaderProgram->setUniformForModelViewProjectionMatrix();

    
//设置顶点缓冲的结构,由位置和纹理坐构构成。
ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );
    //顶点缓冲中位置属性的指定       glVertexAttribPointer(kCCVertexAttrib_Position, 3, GL_FLOAT, GL_FALSE, 0, m_pVertices);
    //纹理坐标通道
    glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, m_pTexCoordinates);
//绘制图形
    glDrawElements(GL_TRIANGLES, (GLsizei)n*6, GL_UNSIGNED_SHORT, m_pIndices);
	//更新DP统计
    CC_INCREMENT_GL_DRAWS(1);
}

//计算顶点缓冲的数据
void CCTiledGrid3D::calculateVertexPoints(void)
{
	//取得纹理的宽高
    float width = (float)m_pTexture->getPixelsWide();
float height = (float)m_pTexture->getPixelsHigh();
//取得纹理中图像区域的高度。
    float imageH = m_pTexture->getContentSizeInPixels().height;
    //定义临时变量。
    int numQuads = m_sGridSize.x * m_sGridSize.y;
//如果相应的顶点缓冲数据有值,先释放干净并置空。
 CC_SAFE_FREE(m_pVertices);
    CC_SAFE_FREE(m_pOriginalVertices);
    CC_SAFE_FREE(m_pTexCoordinates);
    CC_SAFE_FREE(m_pIndices);
//为相应的顶点缓冲区申请相应大小的内存。
    m_pVertices = malloc(numQuads*4*sizeof(ccVertex3F));
    m_pOriginalVertices = malloc(numQuads*4*sizeof(ccVertex3F));
    m_pTexCoordinates = malloc(numQuads*4*sizeof(ccVertex2F));
    m_pIndices = (GLushort*)malloc(numQuads*6*sizeof(GLushort));
	//为了方便填充数据,将缓冲区地址转换成相应的指针变量。
    GLfloat *vertArray = (GLfloat*)m_pVertices;
    GLfloat *texArray = (GLfloat*)m_pTexCoordinates;
    GLushort *idxArray = m_pIndices;
    
    int x, y;
    
   //双循环遍历每个格子。
    for (x = 0; x < m_sGridSize.x; ++x)
    {
        for (y = 0; y < m_sGridSize.y; ++y)
        {
			 //取得格子的左上角和右下角在图像中的位置。
            float x1 = x * m_obStep.x;
            float x2 = x1 + m_obStep.x;
            float y1 = y * m_obStep.y;
            float y2 = y1 + m_obStep.y;
            //填充数据
            *vertArray++ = x1;
            *vertArray++ = y1;
            *vertArray++ = 0;
            *vertArray++ = x2;
            *vertArray++ = y1;
            *vertArray++ = 0;
            *vertArray++ = x1;
            *vertArray++ = y2;
            *vertArray++ = 0;
            *vertArray++ = x2;
            *vertArray++ = y2;
            *vertArray++ = 0;
            
            float newY1 = y1;
            float newY2 = y2;
            //如果纹理V值上下反转,则做下处理。
            if (m_bIsTextureFlipped) 
            {
                newY1 = imageH - y1;
                newY2 = imageH - y2;
            }
			 //填充数据。
            *texArray++ = x1 / width;
            *texArray++ = newY1 / height;
            *texArray++ = x2 / width;
            *texArray++ = newY1 / height;
            *texArray++ = x1 / width;
            *texArray++ = newY2 / height;
            *texArray++ = x2 / width;
            *texArray++ = newY2 / height;
        }
    }
    //索引缓冲数据填充。
    for (x = 0; x < numQuads; x++)
    {
        idxArray[x*6+0] = (GLushort)(x * 4 + 0);
        idxArray[x*6+1] = (GLushort)(x * 4 + 1);
        idxArray[x*6+2] = (GLushort)(x * 4 + 2);
        
        idxArray[x*6+3] = (GLushort)(x * 4 + 1);
        idxArray[x*6+4] = (GLushort)(x * 4 + 2);
        idxArray[x*6+5] = (GLushort)(x * 4 + 3);
    }
    //填充原始位置顶点缓冲
    memcpy(m_pOriginalVertices, m_pVertices, numQuads * 12 * sizeof(GLfloat));
}

 //设置相应位置的格子数据。
void CCTiledGrid3D::setTile(const ccGridSize& pos, const ccQuad3& coords)
{
	//先计算出对应格子的顶点索引
int idx = (m_sGridSize.y * pos.x + pos.y) * 4 * 3;
//为了方便填充数据,将缓冲区地址转换成相应的指针变量。
float *vertArray = (float*)m_pVertices;
//填充对应的数据
    memcpy(&vertArray[idx], &coords, sizeof(ccQuad3));
}
//返回原始位置的格子数据。
ccQuad3 CCTiledGrid3D::originalTile(const ccGridSize& pos)
{
	//先计算出对应格子的顶点索引
    int idx = (m_sGridSize.y * pos.x + pos.y) * 4 * 3;
//为了方便取得数据,将缓冲区地址转换成相应的指针变量。
float *vertArray = (float*)m_pOriginalVertices;
	//定义变量值做为返回结果。
ccQuad3 ret;
//由索引取得数据填充到返回值中。
    memcpy(&ret, &vertArray[idx], sizeof(ccQuad3));

    return ret;
}
//返回相应位置的格子数据
ccQuad3 CCTiledGrid3D::tile(const ccGridSize& pos)
{
	//先计算出对应格子的顶点索引
int idx = (m_sGridSize.y * pos.x + pos.y) * 4 * 3;
//为了方便取得数据,将缓冲区地址转换成相应的指针变量。
    float *vertArray = (float*)m_pVertices;
	//定义变量值做为返回结果。
ccQuad3 ret;
//由索引取得数据填充到返回值中。
    memcpy(&ret, &vertArray[idx], sizeof(ccQuad3));

    return ret;
}
//恢复为原始顶点
void CCTiledGrid3D::reuse(void)
{
	//如果还原格子的变量大于0。
    if (m_nReuseGrid > 0)
    {
        int numQuads = m_sGridSize.x * m_sGridSize.y;
		//将原始顶点位置拷贝到顶点缓冲中。
        memcpy(m_pOriginalVertices, m_pVertices, numQuads * 12 * sizeof(GLfloat));
//还原格子的变量做减1操作。
        --m_nReuseGrid;
    }
}

上面讲的是网格的的数据和渲染基类CCGridBase及其派生CCGrid3DCCTiledGrid3DCCGridBase的关键是处理了将屏幕渲染到纹理这个功能。

它有两个重要的函数:

//在渲染之前要做的处理。

voidbeforeDraw(void);

//在渲染之后要做的处理。

voidafterDraw(CCNode *pTarget);

我们来看一下这两个函数是在哪里调用的。

经过搜索,我们可以在CCNode.h中发现这一句:

    /** A CCGrid object that is used when applying effects */

    CC_PROPERTY(CCGridBase *, m_pGrid, Grid)

即每个CCNode有一个CCGridBase类型的成员指针变量。在其cpp的visit中发现了要找的东西。

void CCNode::visit()
{
    if (!m_bIsVisible)
    {
        return;
    }
     kmGLPushMatrix();

     //如果m_pGrid有值并且被激活则开启渲染到纹理。
     if (m_pGrid && m_pGrid->isActive())
     {
         m_pGrid->beforeDraw();
 }

 //相应结点的渲染处理。
 …
    //如果m_pGrid有值并且被激活则关闭渲染到纹理,这样当前结点上所有绘制的图像都被输出到m_pGrid中对应的纹理中了。
     if (m_pGrid && m_pGrid->isActive())
     {
         m_pGrid->afterDraw(this);
    }
 
    kmGLPopMatrix();
}

CCGrid3D是一个基本的网格渲染类,他内部有所需要的顶点缓冲区。可以实现带纹理贴图的网格渲染功能。

CCTiledGrid3D比较有趣,它与CCGrid3D的不同之处是它的网格不是由一个个顶点构成,而是由一个个四边形构成,CCGrid3D所表现的是网格各顶点的动画,而CCTiledGrid3D是表现每个格子中的四边形的动画。

OK,下面我们来看一下操控网格数据表现一些基本动画的类。

打开CCActionGrid.h:

#ifndef __ACTION_CCGRID_ACTION_H__
#define __ACTION_CCGRID_ACTION_H__

#include "CCActionInterval.h"
#include "CCActionInstant.h"
//使用Cocos2d命名空间
NS_CC_BEGIN
//用到CCGridBase类的指针。
class CCGridBase;
//网格动画基类
class CC_DLL CCGridAction : public CCActionInterval
{
public:
	//产生一个当前类的实例拷贝
virtual CCObject* copyWithZone(CCZone* pZone);
//设定演示当前动画的演员。
virtual void startWithTarget(CCNode *pTarget);
//创建一个反向播放的动画。
    virtual CCActionInterval* reverse(void);
    //初始化网格的大小和动画的时长。
    virtual bool initWithSize(const ccGridSize& gridSize, float duration);
    //返回网格
    virtual CCGridBase* getGrid(void);

public:
    //静态创建函数。参数一为格子大小,参数二为动画时长,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCGridAction* actionWithSize(const ccGridSize& gridSize, float duration);
    //同上
    static CCGridAction* create(const ccGridSize& gridSize, float duration);
protected:
	//格子大小。
    ccGridSize m_sGridSize;
};

对应CPP:
//静态创建函数。参数一为格子大小,参数二为动画时长,内部调用create实现。
CCGridAction* CCGridAction::actionWithSize(const ccGridSize& gridSize, float duration)
{
    return CCGridAction::create(gridSize, duration);
}
//同上
CCGridAction* CCGridAction::create(const ccGridSize& gridSize, float duration)
{
	//先new出一个CCGridAction
    CCGridAction *pAction = new CCGridAction();
    if (pAction)
{
	//初始化并放入内存管理器中。
        if (pAction->initWithSize(gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {
			 //如果初始化失败,释放并置空。
            CC_SAFE_DELETE(pAction);
        }
    }
	//返回创建的实例指针,当然,也可能返回NULL。
    return pAction;
}
//初始化函数。
bool CCGridAction::initWithSize(const ccGridSize& gridSize, float duration)
{
	//调用时间动画基类的初始化函数保存动画时长。
    if (CCActionInterval::initWithDuration(duration))
{
	//保存格子大小。
        m_sGridSize = gridSize;

        return true;
    }

    return false;
}
//设置演示当前动画的演员,注意这个演员是什么?不是精灵,而是
void CCGridAction::startWithTarget(CCNode *pTarget)
{
	//调用时间动画基类的相应函数。
    CCActionInterval::startWithTarget(pTarget);
	//取得网格数据类。
    CCGridBase *newgrid = this->getGrid();

    CCNode *t = m_pTarget;
    //取得演员的对应网格数据。
CCGridBase *targetGrid = t->getGrid();
	//有效性判断,如果演员有网格数据并且已经填充了数据。
    if (targetGrid && targetGrid->getReuseGrid() > 0)
{
	//如果网格数据被激活并且其格子大小与本类实例的网格大小相同。
        if (targetGrid->isActive() && targetGrid->getGridSize().x == m_sGridSize.x
            && targetGrid->getGridSize().y == m_sGridSize.y /*&& dynamic_cast<CCGridBase*>(targetGrid) != NULL*/)
        {
			 //演员的网格数据恢复为原始数据。
            targetGrid->reuse();
        }
        else
        {
            CCAssert(0, "");
        }
    }
    else
{
	//如果演员没有创建网格数据或者网格数据已经恢复为原始顶点。

	 //如果演员的网格数据有效并且是激活状态。
        if (targetGrid && targetGrid->isActive())
        {
			 //将其设为未激活。
            targetGrid->setActive(false);
        }
		 //将当前类实例的网格数据设置给演员之后激活。
        t->setGrid(newgrid);
        t->getGrid()->setActive(true);
    }
}
//纯虚函数:取得网格。做为基类没做任何处理。
CCGridBase* CCGridAction::getGrid(void)
{
    // Abstract class needs implementation
    CCAssert(0, "");

    return NULL;
}
//创建一个反向播放的动画。
CCActionInterval* CCGridAction::reverse(void)
{
    return CCReverseTime::create(this);
}
//创建一个当前类实例的拷贝。
CCObject* CCGridAction::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
CCGridAction* pCopy = NULL;
//如果pZone有效且已有拷贝数据。
    if(pZone && pZone->m_pCopyObject) 
    {
        //直接取用
        pCopy = (CCGridAction*)(pZone->m_pCopyObject);
    }
    else
{
	//否则新建一个当前类实例并设为pNewZone的拷贝数据。
        pCopy = new CCGridAction();
        pZone = pNewZone = new CCZone(pCopy);
    }
	//调用基类的相应函数。
    CCActionInterval::copyWithZone(pZone);
	//初始化拷贝
    pCopy->initWithSize(m_sGridSize, m_fDuration);
    //释放临时变量
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}


//3D网格动画基类
class CC_DLL CCGrid3DAction : public CCGridAction
{
public:
    //取得网格数据。
    virtual CCGridBase* getGrid(void);
    //返回对应网格位置的顶点。
    ccVertex3F vertex(const ccGridSize& pos);
    //返回对应网格位置的原始顶点。
    ccVertex3F originalVertex(const ccGridSize& pos);
    //设置对应网格位置的顶点。
    void setVertex(const ccGridSize& pos, const ccVertex3F& vertex);

public:
    //静态创建函数:参一为格子大小,参二为动画时长,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCGrid3DAction* actionWithSize(const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCGrid3DAction* create(const ccGridSize& gridSize, float duration);
};

对应CPP:
//取得网格数据。
CCGridBase* CCGrid3DAction::getGrid(void)
{
	//创建一个对应大小的3D网格数据。
    return CCGrid3D::create(m_sGridSize);
}
//返回对应网格位置的顶点。
ccVertex3F CCGrid3DAction::vertex(const ccGridSize& pos)
{
	//取得演员的网格数据,调用网格数据的相应函数。
    CCGrid3D *g = (CCGrid3D*)m_pTarget->getGrid();
    return g->vertex(pos);
}
//返回对应网格位置的原始顶点。
ccVertex3F CCGrid3DAction::originalVertex(const ccGridSize& pos)
{
	//取得演员的网格数据,调用网格数据的相应函数。
    CCGrid3D *g = (CCGrid3D*)m_pTarget->getGrid();
    return g->originalVertex(pos);
}
//设置对应网格位置的顶点。
void CCGrid3DAction::setVertex(const ccGridSize& pos, const ccVertex3F& vertex)
{
	//取得演员的网格数据,调用网格数据的相应函数。
    CCGrid3D *g = (CCGrid3D*)m_pTarget->getGrid();
    g->setVertex(pos, vertex);
}


//派生于CCGridAction的3D格子动画类。
class CC_DLL CCTiledGrid3DAction : public CCGridAction
{
public:
    //返回对应位置的格子顶点数据。
    ccQuad3 tile(const ccGridSize& pos);
    //返回对应位置的原始格子顶点数据。
    ccQuad3 originalTile(const ccGridSize& pos);
    //设置对应位置的格子数据。
    void setTile(const ccGridSize& pos, const ccQuad3& coords);

    //返回网格数据。
    virtual CCGridBase* getGrid(void);

public:
    //静态创建函数:参一为格子大小,参二为动画时长,内部调用creat来实现。
    CC_DEPRECATED_ATTRIBUTE static CCTiledGrid3DAction* actionWithSize(const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCTiledGrid3DAction* create(const ccGridSize& gridSize, float duration);
};
//取得网格数据。
CCGridBase* CCTiledGrid3DAction::getGrid(void)
{
    return CCTiledGrid3D::create(m_sGridSize);
}
//返回对应位置的格子顶点数据。
ccQuad3 CCTiledGrid3DAction::tile(const ccGridSize& pos)
{
	//取得演员的网格数据,调用网格数据的相应函数。
    CCTiledGrid3D *g = (CCTiledGrid3D*)m_pTarget->getGrid();
    return g->tile(pos);
}
//返回对应位置的原始格子顶点数据。
ccQuad3 CCTiledGrid3DAction::originalTile(const ccGridSize& pos)
{
	//取得演员的网格数据,调用网格数据的相应函数。
    CCTiledGrid3D *g = (CCTiledGrid3D*)m_pTarget->getGrid();
    return g->originalTile(pos);
}
//设置对应位置的格子数据。

void CCTiledGrid3DAction::setTile(const ccGridSize& pos, const ccQuad3& coords)
{
	//取得演员的网格数据,调用网格数据的相应函数。
    CCTiledGrid3D *g = (CCTiledGrid3D*)m_pTarget->getGrid();
    return g->setTile(pos, coords);
}

//网格所用的变速动画基类:先加速再减速。
class CC_DLL CCAccelDeccelAmplitude : public CCActionInterval
{
public:
	//析构
    virtual ~CCAccelDeccelAmplitude(void);
    //初始化
    bool initWithAction(CCAction *pAction, float duration);
	//设置演示动画的演员。
virtual void startWithTarget(CCNode *pTarget);
//更新动画。
virtual void update(float time);
//创建一个当前类的反向动画实例。
    virtual CCActionInterval* reverse(void);

    //取得速率
    inline float getRate(void) { return m_fRate; }
    //设置速率
    inline void setRate(float fRate) { m_fRate = fRate; }

public:
    //静态创建函数:参一为动画实例指针,参二为动画时长,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCAccelDeccelAmplitude* actionWithAction(CCAction *pAction, float duration);
    //上面函数的create实现。
    static CCAccelDeccelAmplitude* create(CCAction *pAction, float duration);

protected:
	//速率
float m_fRate;
//所控制的时间动画。
    CCActionInterval *m_pOther;
};

对应CPP:
//静态创建函数:参一为动画实例指针,参二为动画时长,内部调用create实现。
CCAccelDeccelAmplitude* CCAccelDeccelAmplitude::actionWithAction(CCAction *pAction, float duration)
{
    return CCAccelDeccelAmplitude::create(pAction, duration);
}
//上面函数的create实现。
CCAccelDeccelAmplitude* CCAccelDeccelAmplitude::create(CCAction *pAction, float duration)
{
	//先new出一个当前类的实例。
    CCAccelDeccelAmplitude *pRet = new CCAccelDeccelAmplitude();
    if (pRet)
{
	//初始化并交由内存管理器去进行引用计数器的管理。
        if (pRet->initWithAction(pAction, duration))
        {
            pRet->autorelease();
        }
        else
        {
			 //如果失败,释放并置空。
            CC_SAFE_DELETE(pRet);
        }
    }
	//返回创建的当前类实例,当然可能为NULL。
    return pRet;
}
//初始化处理。
bool CCAccelDeccelAmplitude::initWithAction(CCAction *pAction, float duration)
{
	//调用基类的初始化函数。
    if (CCActionInterval::initWithDuration(duration))
{
	//保存相应的变量值,占用控制的动画故对其引用计数加一。
        m_fRate = 1.0f;
        m_pOther = (CCActionInterval*)(pAction);
        pAction->retain();

        return true;
    }

    return false;
}
//析构
CCAccelDeccelAmplitude::~CCAccelDeccelAmplitude(void)
{
	//不再占用控制的时间动画,对其引用计数器减一。
    CC_SAFE_RELEASE(m_pOther);
}
//设置演示当前动画的演员。
void CCAccelDeccelAmplitude::startWithTarget(CCNode *pTarget)
{
	//先调用基类的相应函数。
CCActionInterval::startWithTarget(pTarget);
//设置控制动画使用此演员。
    m_pOther->startWithTarget(pTarget);
}
//更新动画。
void CCAccelDeccelAmplitude::update(float time)
{
	//创建一个f值变为进度的2倍。
    float f = time * 2;
	//如果动画时间大于一半,让进度由1再变为0。
    if (f > 1)
    {
        f -= 1;
        f = 1 - f;
    }
	//使用powf处理来形成一个变速曲线公式来达到变速目的。
    ((CCAccelDeccelAmplitude*)(m_pOther))->setAmplitudeRate(powf(f, m_fRate));
}
//创建当前类的反向动画实例。
CCActionInterval* CCAccelDeccelAmplitude::reverse(void)
{
    return CCAccelDeccelAmplitude::create(m_pOther->reverse(), m_fDuration);
}


//网格所用的变速动画基类:加速动画。
class CC_DLL CCAccelAmplitude : public CCActionInterval
{
public:
	//析构
    ~CCAccelAmplitude(void);
    //初始化处理。
    bool initWithAction(CCAction *pAction, float duration);

    //取得速率
    inline float getRate(void) { return m_fRate; }
    //设置速率
    inline void setRate(float fRate) { m_fRate = fRate; }
	//设置演示当前动画的演员。
virtual void startWithTarget(CCNode *pTarget);
//更新动画
virtual void update(float time);
//创建一个当前动画的反向动画实例。
    virtual CCActionInterval* reverse(void);

public:
    //静态创建函数:参一为一个时间动画,参二为时长。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCAccelAmplitude* actionWithAction(CCAction *pAction, float duration);
    //上面函数的create实现。
    static CCAccelAmplitude* create(CCAction *pAction, float duration);
protected:
	//速率
float m_fRate;
//控制动画。
    CCActionInterval *m_pOther;
};

对应CPP:
//静态创建函数:参一为一个时间动画,参二为时长。内部调用create实现。
CCAccelAmplitude* CCAccelAmplitude::actionWithAction(CCAction *pAction, float duration)
{
    return CCAccelAmplitude::create(pAction, duration);
}
//上面函数的create实现。
CCAccelAmplitude* CCAccelAmplitude::create(CCAction *pAction, float duration)
{
	//创建三部曲,new,初始化,autorelease,一个不少。
    CCAccelAmplitude *pRet = new CCAccelAmplitude();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, duration))
        {
            pRet->autorelease();
        }
        else
        {
			 //当然,要有失败处理。
            CC_SAFE_DELETE(pRet);
        }
    }

    return pRet;
}
//初始化
bool CCAccelAmplitude::initWithAction(CCAction *pAction, float duration)
{
	//先调用基类的初始化函数。
    if (CCActionInterval::initWithDuration(duration))
{
	//速率设为1.0。
        m_fRate = 1.0f;
		//保存动画。占用对其引用计数加一。
        m_pOther = (CCActionInterval*)(pAction);
        pAction->retain();

        return true;
    }

    return false;
}
//析构函数。
CCAccelAmplitude::~CCAccelAmplitude(void)
{
	//不占用,对其引用计数减一。
    CC_SAFE_DELETE(m_pOther);
}
//设置演示当前动画的演员。
void CCAccelAmplitude::startWithTarget(CCNode *pTarget)
{
	//调用基类的相应函数。
CCActionInterval::startWithTarget(pTarget);
//设置控制动画使用此演员。
    m_pOther->startWithTarget(pTarget);
}
//动画更新处理。
void CCAccelAmplitude::update(float time)
{
	//创建变速曲线来设置控制动画的速率。
((CCAccelAmplitude*)(m_pOther))->setAmplitudeRate(powf(time, m_fRate));
//更新控制动画。
    m_pOther->update(time);
}
//创建一个当前类的反向动画实例。
CCActionInterval* CCAccelAmplitude::reverse(void)
{
    return CCAccelAmplitude::create(m_pOther->reverse(), m_fDuration);
}

//网格所用的变速动画基类:减速动画。
class CC_DLL CCDeccelAmplitude : public CCActionInterval
{
public:
	//析构函数。
    ~CCDeccelAmplitude(void);
    //初始化
    bool initWithAction(CCAction *pAction, float duration);

    //取得速率
    inline float getRate(void) { return m_fRate; }
    //设置速率
    inline void setRate(float fRate) { m_fRate = fRate; }
	
	//设置演示当前动画的演员。
virtual void startWithTarget(CCNode *pTarget);
//更新处理。
virtual void update(float time);
//创建一个当前类的反向播放的实例。
    virtual CCActionInterval* reverse(void);

public:
    //静态创建函数,参一为一个动画,参二为动画时长。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCDeccelAmplitude* actionWithAction(CCAction *pAction, float duration);
    //上面的create实现。
    static CCDeccelAmplitude* create(CCAction *pAction, float duration);

protected:
	//速率
float m_fRate;
//控制动画。
    CCActionInterval *m_pOther;
};

对应CPP:
//静态创建函数,参一为一个动画,参二为动画时长。内部调用create实现。
CCDeccelAmplitude* CCDeccelAmplitude::actionWithAction(CCAction *pAction, float duration)
{
    return CCDeccelAmplitude::create(pAction, duration);
}
//上面的create实现。
CCDeccelAmplitude* CCDeccelAmplitude::create(CCAction *pAction, float duration)
{
	//new, initWithAction, autorelease三部曲,当然别忘了失败处理。

    CCDeccelAmplitude *pRet = new CCDeccelAmplitude();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, duration))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_DELETE(pRet);
        }
    }

    return pRet;
}

//初始化处理。
bool CCDeccelAmplitude::initWithAction(CCAction *pAction, float duration)
{
	//先调用基类的初始化处理。
    if (CCActionInterval::initWithDuration(duration))
{
	//速率置1。
        m_fRate = 1.0f;
		//占用控制动画,对其引用计数器加一。
        m_pOther = (CCActionInterval*)(pAction);
        pAction->retain();

        return true;
    }

    return false;
}
//析构
CCDeccelAmplitude::~CCDeccelAmplitude(void)
{
	//不再占用控制动画,对其引用计数器减一。
    CC_SAFE_RELEASE(m_pOther);
}
//设置演示当前动画的演员。
void CCDeccelAmplitude::startWithTarget(CCNode *pTarget)
{
	//调用基类的相应函数。
CCActionInterval::startWithTarget(pTarget);
//调用控制动画的相应函数。
    m_pOther->startWithTarget(pTarget);
}
//更新动画。
void CCDeccelAmplitude::update(float time)
{
	//与加速动画有什么不同?很容易明白。
    ((CCDeccelAmplitude*)(m_pOther))->setAmplitudeRate(powf((1 - time), m_fRate));
    m_pOther->update(time);
}
//创建一个当前类的反向动画实例。
CCActionInterval* CCDeccelAmplitude::reverse(void)
{
    return CCDeccelAmplitude::create(m_pOther->reverse(), m_fDuration);
}

//停止网格动画。
class CC_DLL CCStopGrid : public CCActionInstant
{
public:
	//设置演示该动画的演员。
    virtual void startWithTarget(CCNode *pTarget);

public:
    //静态函数:创建一个当前类的实例动画,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCStopGrid* action(void);
    //上面的create实现。
    static CCStopGrid* create(void);
};
对应CPP:
//设置演示当前动画的演员。
void CCStopGrid::startWithTarget(CCNode *pTarget)
{
	//调用基类的相应函数。
    CCActionInstant::startWithTarget(pTarget);
	//取得演员所用的网格数据。
    CCGridBase *pGrid = m_pTarget->getGrid();
    if (pGrid && pGrid->isActive())
{
	//如果是激活状态,取消激活。
        pGrid->setActive(false);
    }
}
//静态函数:创建一个当前类的实例动画,内部调用create实现。
CCStopGrid* CCStopGrid::action(void)
{
    return CCStopGrid::create();
}
//上面的create实现。
CCStopGrid* CCStopGrid::create(void)
{
    CCStopGrid* pAction = new CCStopGrid();
    pAction->autorelease();

    return pAction;
}

//恢复网格动画。
class CC_DLL CCReuseGrid : public CCActionInstant
{
public:
    //初始化
    bool initWithTimes(int times);
	//设置演示当前动画的演员。
    virtual void startWithTarget(CCNode *pTarget);

public:
    //静态函数:创建一个当前类的实例。参数为,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCReuseGrid* actionWithTimes(int times);
    //上面函数的create实现。
    static CCReuseGrid* create(int times);
protected:
	//
    int m_nTimes;
};

对应CPP:
//
CCReuseGrid* CCReuseGrid::actionWithTimes(int times)
{
    return CCReuseGrid::create(times);
}
//上面函数的create实现。
CCReuseGrid* CCReuseGrid::create(int times)
{
	//先new出一个当前类的实例。
    CCReuseGrid *pAction = new CCReuseGrid();
    if (pAction)
{
	//进行初始化,成功后交由内存管理器进行引用计数器的管理。
        if (pAction->initWithTimes(times))
        {
            pAction->autorelease();
        }
        else
        {
			 //初始化失败则释放并置空。
            CC_SAFE_DELETE(pAction);
        }
    }
	//返回创建的动画实例,当然,也可能为NULL。
    return pAction;
}

//初始化。
bool CCReuseGrid::initWithTimes(int times)
{
    m_nTimes = times;

    return true;
}
//设置演示当前动画的演员。
void CCReuseGrid::startWithTarget(CCNode *pTarget)
{
	//调用基类的相应函数。
    CCActionInstant::startWithTarget(pTarget);
	//如果演员有正在使用的网格动画。
    if (m_pTarget->getGrid() && m_pTarget->getGrid()->isActive())
    {
//取得这个网格动画并激活。     m_pTarget->getGrid()->setReuseGrid(m_pTarget->getGrid()->getReuseGrid() + m_nTimes);
    }
}

 

有了网格基本动画,我们再来看一下3D网格基本动画

CCActionGrid3D.h/cpp:

#include "CCActionGrid.h"

NS_CC_BEGIN
//波浪动画
class CC_DLL CCWaves3D : public CCGrid3DAction

public:
	//取得和设置振幅
    inline float getAmplitude(void) { return m_fAmplitude; }
    inline void setAmplitude(float fAmplitude) { m_fAmplitude = fAmplitude; }
	//取得和设置频率
    inline float getAmplitudeRate(void) { return m_fAmplitudeRate; }
    inline void setAmplitudeRate(float fAmplitudeRate) { m_fAmplitudeRate = fAmplitudeRate; }

    //初始化
    bool initWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration);

	//产生一个实例的拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//动画更新。
    virtual void update(float time);

public:
    //创建一个波浪动画,参一为波浪动画摇动的次数,参二为波浪的振幅,参三为格子的大小,参四为动画时长。    CC_DEPRECATED_ATTRIBUTE static CCWaves3D* actionWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCWaves3D* create(int wav, float amp, const ccGridSize& gridSize, float duration);
protected:
	//波浪摇动的次数。
    int m_nWaves;
	//摇动的振幅。
    float m_fAmplitude;
	//摇动的频率。
    float m_fAmplitudeRate;
};

CPP实现:

//创建一个波浪动画,参一为波浪动画摇动的次数,参二为波浪的振幅,参三为格子的大小,参四为动画时长。
CCWaves3D* CCWaves3D::actionWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration)
{
    return CCWaves3D::create(wav, amp, gridSize, duration);
}
//上面的create实现。
CCWaves3D* CCWaves3D::create(int wav, float amp, const ccGridSize& gridSize, float duration)
{
	//new,初始化,autorelease,失败处理。
    CCWaves3D *pAction = new CCWaves3D();

    if (pAction)
    {
        if (pAction->initWithWaves(wav, amp, gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;    
}
//初始化。
bool CCWaves3D::initWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration)
{
	//先调用基类的初始化函数。
    if (CCGrid3DAction::initWithSize(gridSize, duration))
    {
		 //保存相应的参数。
        m_nWaves = wav;
        m_fAmplitude = amp;
        m_fAmplitudeRate = 1.0f;
        return true;
    }

    return false;
}
//产生一个当前类的实例。
CCObject* CCWaves3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCWaves3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCWaves3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCWaves3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCGrid3DAction::copyWithZone(pZone);


    pCopy->initWithWaves(m_nWaves, m_fAmplitude, m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCWaves3D::update(float time)
{
	//双循环遍历格子。
    int i, j;
    for (i = 0; i < m_sGridSize.x + 1; ++i)
    {
        for (j = 0; j < m_sGridSize.y + 1; ++j)
        {
			 //取出当前格子原始顶点,对z值进行sin曲线的变化加值。形成来回摇动的效果。
            ccVertex3F v = originalVertex(ccg(i ,j));
            v.z += (sinf((float)M_PI * time * m_nWaves * 2 + (v.y+v.x) * .01f) * m_fAmplitude * m_fAmplitudeRate);
            CCLog("v.z offset is %f/n", (sinf((float)M_PI * time * m_nWaves * 2 + (v.y+v.x) * .01f) * m_fAmplitude * m_fAmplitudeRate));
			 //将顶点设置到格子中。
            setVertex(ccg(i, j), v);
        }
    }
}

对应图:

Cocos2d-x 2.0 网格动画深入分析

//绕X轴翻转。
class CC_DLL CCFlipX3D : public CCGrid3DAction
{
public:
    //初始化动画。
bool initWithDuration(float duration);
//初始化格子大小。
virtual bool initWithSize(const ccGridSize& gridSize, float duration);
//产生一个当前类的实例拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//动画更新。
    virtual void update(float time);

public:
    //创建一个绕X轴翻转的3D网格动画。参数为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCFlipX3D* actionWithDuration(float duration);
    //上面的create实现。
    static CCFlipX3D* create(float duration);
};

对应的CPP实现:

//创建一个绕X轴翻转的3D网格动画。参数为动画时长。CCFlipX3D::actionWithDuration(float duration)
{
    return CCFlipX3D::create(duration);
}
//上面的create实现。
CCFlipX3D* CCFlipX3D::create(float duration)
{
//new ,初始化, autorelease,失败处理。
    CCFlipX3D *pAction = new CCFlipX3D();

    if (pAction)
    {
        if (pAction->initWithSize(ccg(1, 1), duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//初始化动画。
bool CCFlipX3D::initWithDuration(float duration)
{
    return CCGrid3DAction::initWithSize(ccg(1, 1), duration);
}
//初始化格子大小。
bool CCFlipX3D::initWithSize(const ccGridSize& gridSize, float duration)
{
    if (gridSize.x != 1 || gridSize.y != 1)
    {
        // Grid size must be (1,1)
        CCAssert(0, "Grid size must be (1,1)");

        return false;
    }

    return CCGrid3DAction::initWithSize(gridSize, duration);
}
//产生一个当前类的实例拷贝。
CCObject* CCFlipX3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCFlipX3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCFlipX3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCFlipX3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCGrid3DAction::copyWithZone(pZone);

    pCopy->initWithSize(m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//动画更新。
void CCFlipX3D::update(float time)
{
    //角度,从0~180变化。
    float angle = (float)M_PI * time; // 180 degrees
    //计算其sin值
    float mz = sinf(angle);
    //对基除2后计算cos值。
    angle = angle / 2.0f; // x calculates degrees from 0 to 90
    float mx = cosf(angle);
    //定义临时变量。
    ccVertex3F v0, v1, v, diff;
    //
    v0 = originalVertex(ccg(1, 1));
    v1 = originalVertex(ccg(0, 0));
    //
    float    x0 = v0.x;
    float    x1 = v1.x;
    float x;
    ccGridSize    a, b, c, d;
    //
    if ( x0 > x1 )
    {
        // Normal Grid
        a = ccg(0,0);
        b = ccg(0,1);
        c = ccg(1,0);
        d = ccg(1,1);
        x = x0;
    }
    else
    {
        // Reversed Grid
        c = ccg(0,0);
        d = ccg(0,1);
        a = ccg(1,0);
        b = ccg(1,1);
        x = x1;
    }
    //
    diff.x = ( x - x * mx );
    diff.z = fabsf( floorf( (x * mz) / 4.0f ) );
    //取得左下角顶点,设置X和Z值。
    v = originalVertex(a);
    v.x = diff.x;
    v.z += diff.z;
    setVertex(a, v);
    //取得左上角顶点。计算X和Z值。
    v = originalVertex(b);
    v.x = diff.x;
    v.z += diff.z;
    setVertex(b, v);
    //取得右下角顶点。计算X和Z值。
    v = originalVertex(c);
    v.x -= diff.x;
    v.z -= diff.z;
    setVertex(c, v);
    //取得右上角顶点。计算X和Z值。
    v = originalVertex(d);
    v.x -= diff.x;
    v.z -= diff.z;
    setVertex(d, v);
}

对应图:

Cocos2d-x 2.0 网格动画深入分析

//绕Y轴反转的3D网格动画。
class CC_DLL CCFlipY3D : public CCFlipX3D
{
public:
	//动画更新。
    virtual void update(float time);
	//产生一个当前类的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
    //创建一个绕Y轴反转的3D网格动画,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCFlipY3D* actionWithDuration(float duration);
    //上面的create实现。
    static CCFlipY3D* create(float duration);
};
对应CPP实现:
//创建一个绕Y轴反转的3D网格动画,内部调用create实现。
CCFlipY3D* CCFlipY3D::actionWithDuration(float duration)
{
    return CCFlipY3D::create(duration);
}
//上面的create实现。
CCFlipY3D* CCFlipY3D::create(float duration)
{
//new ,初始化, autorelease,失败处理。
    CCFlipY3D *pAction = new CCFlipY3D();

    if (pAction)
    {
        if (pAction->initWithSize(ccg(1, 1), duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//产生一个当前类的实例拷贝。
CCObject* CCFlipY3D::copyWithZone(CCZone* pZone)
{
    CCZone* pNewZone = NULL;
    CCFlipY3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCFlipY3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCFlipY3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCFlipX3D::copyWithZone(pZone);

    pCopy->initWithSize(m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//动画更新。
void CCFlipY3D::update(float time)
{
//角度从0~180
float angle = (float)M_PI * time; // 180 degrees
//对其进行sin计算。
float mz = sinf( angle );
//对其做除2计算。
angle = angle / 2.0f;     // x calculates degrees from 0 to 90
//对其进行cos计算。
    float my = cosf(angle);
    
    ccVertex3F    v0, v1, v, diff;
    
    v0 = originalVertex(ccg(1, 1));
    v1 = originalVertex(ccg(0, 0));
    
    float    y0 = v0.y;
    float    y1 = v1.y;
    float y;
    ccGridSize    a, b, c, d;
    
    if (y0 > y1)
    {
        // Normal Grid
        a = ccg(0,0);
        b = ccg(0,1);
        c = ccg(1,0);
        d = ccg(1,1);
        y = y0;
    }
    else
    {
        // Reversed Grid
        b = ccg(0,0);
        a = ccg(0,1);
        d = ccg(1,0);
        c = ccg(1,1);
        y = y1;
    }
    
    diff.y = y - y * my;
    diff.z = fabsf(floorf((y * mz) / 4.0f));
    
    // bottom-left
    v = originalVertex(a);
    v.y = diff.y;
    v.z += diff.z;
    setVertex(a, v);
    
    // upper-left
    v = originalVertex(b);
    v.y -= diff.y;
    v.z -= diff.z;
    setVertex(b, v);
    
    // bottom-right
    v = originalVertex(c);
    v.y = diff.y;
    v.z += diff.z;
    setVertex(c, v);
    
    // upper-right
    v = originalVertex(d);
    v.y -= diff.y;
    v.z -= diff.z;
    setVertex(d, v);
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//球体3D网格动画。
class CC_DLL CCLens3D : public CCGrid3DAction
{
public:
    //
    inline float getLensEffect(void) { return m_fLensEffect; }
    //
    inline void setLensEffect(float fLensEffect) { m_fLensEffect = fLensEffect; }
    //设置中心位置。
    inline const CCPoint& getPosition(void) { return m_position; }
    void setPosition(const CCPoint& position);

    //初始化。
bool initWithPosition(const CCPoint& pos, float r, const ccGridSize& gridSize, float duration);
//创建一个当前类的实例拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//动画更新。
    virtual void update(float time);

public:
    //创建一个球体的3D网格动画。参一为中心点位置,参二为半径,参三为格子大小,参四为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCLens3D* actionWithPosition(const CCPoint& pos, float r, const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCLens3D* create(const CCPoint& pos, float r, const ccGridSize& gridSize, float duration);
protected:
    //球体的中心位置。
    CCPoint m_position;
	//球体的半径。
    float m_fRadius;
    //效果公式的参数。
    float m_fLensEffect;
	//这个命名本意是使用脏矩形,即相同的矩形没有改变就不要重新更新。但可惜它在使用时的true与false应该反过来。这里可以理解成是否更新中心点位置,需要重新计算。
    bool    m_bDirty;
};

对应的CPP:
//创建一个球体的3D网格动画。参一为中心点位置,参二为半径,参三为格子大小,参四为动画时长。
CCLens3D* CCLens3D::actionWithPosition(const CCPoint& pos, float r, const ccGridSize& gridSize, float duration)
{
    return CCLens3D::create(pos, r, gridSize, duration);
}
//上面的create实现。
CCLens3D* CCLens3D::create(const CCPoint& pos, float r, const ccGridSize& gridSize, float duration)
{
	//new,初始化,autorelease,失败处理。
    CCLens3D *pAction = new CCLens3D();

    if (pAction)
    {
        if (pAction->initWithPosition(pos, r, gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//初始化。
bool CCLens3D::initWithPosition(const CCPoint& pos, float r, const ccGridSize& gridSize, float duration)
{
	//先调用基类的相应函数。
    if (CCGrid3DAction::initWithSize(gridSize, duration))
{
	//保存参数到成员变量。
        m_position = ccp(-1, -1);
        setPosition(pos);
        m_fRadius = r;
        m_fLensEffect = 0.7f;
        //设置需要重新计算。
        m_bDirty = true;

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝。
CCObject* CCLens3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCLens3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCLens3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCLens3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCGrid3DAction::copyWithZone(pZone);

    pCopy->initWithPosition(m_position, m_fRadius, m_sGridSize, m_fDuration);
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//设置球体的中心位置。
void CCLens3D::setPosition(const CCPoint& pos)
{
    if( !pos.equals(m_position))
    {//位置有更新,则设置需要重新计算。
        m_position = pos;
        m_bDirty = true;
    }
}
//动画更新。
void CCLens3D::update(float time)
{
CC_UNUSED_PARAM(time);
//如果需要重新计算。
    if (m_bDirty)
    {
        int i, j;
        //双循环遍历格子。
        for (i = 0; i < m_sGridSize.x + 1; ++i)
        {
            for (j = 0; j < m_sGridSize.y + 1; ++j)
            {
                //取出格子对应的顶点。
                ccVertex3F v = originalVertex(ccg(i, j));
               //计算格子顶点与中心点的差。
                CCPoint vect = ccpSub(m_position, ccp(v.x, v.y));
                //计算格子顶点与中心点的距离。
                float r = ccpLength(vect);
                //如果距离在半径内。
                if (r < m_fRadius)
                {
                    r = m_fRadius - r;
                    float pre_log = r / m_fRadius;
                    if ( pre_log == 0 ) 
                    {
                        pre_log = 0.001f;
                    }
                    //通过一些函数来取得相应的顶点影响值。
                    float l = logf(pre_log) * m_fLensEffect;
                    float new_r = expf( l ) * m_fRadius;
                    //如果不是中心点,就进行位置的更新。
                    if (ccpLength(vect) > 0)
                    {
                        vect = ccpNormalize(vect);
                        CCPoint new_vect = ccpMult(vect, new_r);
                        v.z += ccpLength(new_vect) * m_fLensEffect;
                    }
                }
                //设置格子的新顶点。
                setVertex(ccg(i, j), v);
            }
        }
        
        m_bDirty = false;
    }
}

对应图:

Cocos2d-x 2.0 网格动画深入分析

//涟漪3D网格特效。
class CC_DLL CCRipple3D : public CCGrid3DAction
{
public:
    //取得和设置中心位置。
    inline const CCPoint& getPosition(void) { return m_position; }
    void setPosition(const CCPoint& position);
	//取得和设置振幅。
    inline float getAmplitude(void) { return m_fAmplitude; }
    inline void setAmplitude(float fAmplitude) { m_fAmplitude = fAmplitude; }
	//取得和设置频率。
    inline float getAmplitudeRate(void) { return m_fAmplitudeRate; }
    inline void setAmplitudeRate(float fAmplitudeRate) { m_fAmplitudeRate = fAmplitudeRate; }

    //初始化位置。
bool initWithPosition(const CCPoint& pos, float r, int wav, float amp, 
        const ccGridSize& gridSize, float duration);
    virtual CCObject* copyWithZone(CCZone* pZone);
    virtual void update(float time);

public:
    //创建一个涟漪3D网格特效。参一为中心位置,参二为半径,参三为振幅,参四为格子大小,参五为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCRipple3D* actionWithPosition(const CCPoint& pos, float r, int wav, float amp, 
        const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCRipple3D* create(const CCPoint& pos, float r, int wav, float amp, 
        const ccGridSize& gridSize, float duration);
protected:
    //中心位置。
CCPoint m_position;
//半径。
float m_fRadius;
//振动次数。
int m_nWaves;
//振幅。
float m_fAmplitude;
//振动频率。
    float m_fAmplitudeRate;
};
CPP实现:
//创建一个涟漪3D网格特效。
CCRipple3D* CCRipple3D::actionWithPosition(const CCPoint& pos, float r, int wav, float amp, const ccGridSize& gridSize, float duration)
{
    return CCRipple3D::create(pos, r, wav, amp, gridSize, duration);
}
//上面的create实现。
CCRipple3D* CCRipple3D::create(const CCPoint& pos, float r, int wav, float amp, const ccGridSize& gridSize, float duration)
{
//先new出一个当前类的实例。
    CCRipple3D *pAction = new CCRipple3D();
//如果成功。
    if (pAction)
{
//进行初始化。
        if (pAction->initWithPosition(pos, r, wav, amp, gridSize, duration))
        {	//如果初始化成功,交由内存管理器进行引用计数管理。
            pAction->autorelease();
        }
        else
        {	//如果失败,释放并置空。
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}

//初始化。
bool CCRipple3D::initWithPosition(const CCPoint& pos, float r, int wav, float amp, const ccGridSize& gridSize, float duration)
{
//先调用基类的初始化处理。
    if (CCGrid3DAction::initWithSize(gridSize, duration))
{
//设置中心点位置。
        setPosition(pos);
        //将参数保存到成员变量中。
        m_fRadius = r;
        m_nWaves = wav;
        m_fAmplitude = amp;
        m_fAmplitudeRate = 1.0f;

        return true;
    }

    return false;
}
//设置中心点位置。
void CCRipple3D::setPosition(const CCPoint& position)
{
    m_position = position;
}
//产生一个当前类的实例拷贝。
CCObject* CCRipple3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCRipple3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject)
    {
        //in case of being called at sub class
        pCopy = (CCRipple3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCRipple3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCGrid3DAction::copyWithZone(pZone);

    pCopy->initWithPosition(m_position, m_fRadius, m_nWaves, m_fAmplitude, m_sGridSize, m_fDuration);
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画处理。
void CCRipple3D::update(float time)
{
    int i, j;
//双循环遍历每个格子。
    for (i = 0; i < (m_sGridSize.x+1); ++i)
    {
        for (j = 0; j < (m_sGridSize.y+1); ++j)
        {
            //取得格子的原始顶点。
            ccVertex3F v = originalVertex(ccg(i, j));
            //计算顶点与中心点的位置之差。
            CCPoint vect = ccpSub(m_position, ccp(v.x,v.y));
            //计算出顶点与中心点的距离。
            float r = ccpLength(vect);
            //如果在半径范围内。通过距离做为参数按照sin曲线公式计算出相应的Z值偏移。
            if (r < m_fRadius)
            {   
                r = m_fRadius - r;
                float rate = powf(r / m_fRadius, 2);
                v.z += (sinf( time*(float)M_PI * m_nWaves * 2 + r * 0.1f) * m_fAmplitude * m_fAmplitudeRate * rate);
            }
            //将偏移后的顶点设置给格子。
            setVertex(ccg(i, j), v);
        }
    }
}
效果图:

Cocos2d-x 2.0 网格动画深入分析

//3D摇动的网格动画。
class CC_DLL CCShaky3D : public CCGrid3DAction
{
public:
    //初始化。
bool initWithRange(int range, bool shakeZ, const ccGridSize& gridSize, float duration);
//产生一个实例的拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//更新动画。
    virtual void update(float time);

public:
    //创建一个3D摇动的网格动画。参一是随机范围,参二指定是否在Z值上摇动,参三为格子大小,参四为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCShaky3D* actionWithRange(int range, bool shakeZ, const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCShaky3D* create(int range, bool shakeZ, const ccGridSize& gridSize, float duration);
protected:
    //随机范围。
    int m_nRandrange;
    //是否在Z值上摇动。
    bool m_bShakeZ;
};
//创建一个3D摇动的网格动画。参一是随机范围,参二指定是否在Z值上摇动,参三为格子大小,参四为动画时长。
CCShaky3D* CCShaky3D::actionWithRange(int range, bool shakeZ, const ccGridSize& gridSize, float duration)
{
    return CCShaky3D::create(range, shakeZ, gridSize, duration);
}
//上面的create实现。
CCShaky3D* CCShaky3D::create(int range, bool shakeZ, const ccGridSize& gridSize, float duration)
{
//先new出一个当前类的实例,
    CCShaky3D *pAction = new CCShaky3D();

    if (pAction)
{
//如果成功,对其进行初始化。
        if (pAction->initWithRange(range, shakeZ, gridSize, duration))
        {
 //如果初始化成功,交由内存管理器进行引用计数的管理。
            pAction->autorelease();
        }
        else
        {   
            //如果失败,释放并置空。
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}

//初始化。
bool CCShaky3D::initWithRange(int range, bool shakeZ, const ccGridSize& gridSize, float duration)
{
//先调用基类的初始化函数。
    if (CCGrid3DAction::initWithSize(gridSize, duration))
{
        //如果成功,保存参数到成员变量中。
        m_nRandrange = range;
        m_bShakeZ = shakeZ;

        return true;
    }

    return false;
}
//产生一个当前类的实例。
CCObject* CCShaky3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCShaky3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject)
    {
        //in case of being called at sub class
        pCopy = (CCShaky3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCShaky3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCGrid3DAction::copyWithZone(pZone);

    pCopy->initWithRange(m_nRandrange, m_bShakeZ, m_sGridSize, m_fDuration);
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//动画更新。
void CCShaky3D::update(float time)
{
    CC_UNUSED_PARAM(time);
    int i, j;
    //双循环遍历所有格子。
    for (i = 0; i < (m_sGridSize.x+1); ++i)
    {
        for (j = 0; j < (m_sGridSize.y+1); ++j)
        {
            //取得格子的原始顶点。
            ccVertex3F v = originalVertex(ccg(i ,j));
            //对顶点的x,y进行随机的的加成。
            v.x += (rand() % (m_nRandrange*2)) - m_nRandrange;
            v.y += (rand() % (m_nRandrange*2)) - m_nRandrange;
            //如果需要Z值的摇动,对顶点的z进行随机的的加成。
            if (m_bShakeZ)
            {
                v.z += (rand() % (m_nRandrange*2)) - m_nRandrange;
            }
            //将顶点设置到相应格子中。
            setVertex(ccg(i, j), v);
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//流体效果的3D网格动画。
class CC_DLL CCLiquid : public CCGrid3DAction
{
public:
    //取得和设置振幅。
    inline float getAmplitude(void) { return m_fAmplitude; }
    inline void setAmplitude(float fAmplitude) { m_fAmplitude = fAmplitude; }
    //取得和设置频率。
    inline float getAmplitudeRate(void) { return m_fAmplitudeRate; }
    inline void setAmplitudeRate(float fAmplitudeRate) { m_fAmplitudeRate = fAmplitudeRate; }

//初始化
    bool initWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration);
    //产生一个当前类的实例。
    virtual CCObject* copyWithZone(CCZone* pZone);
    //更新动画。
    virtual void update(float time);

public:
//创建一个流体效果的3D网格动画。参一为动画的次数,参二为振幅,参三为格子大小,参四为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCLiquid* actionWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCLiquid* create(int wav, float amp, const ccGridSize& gridSize, float duration);
protected:
    //动画的次数。
    int m_nWaves;
    //振幅。
    float m_fAmplitude;
    //频率。
    float m_fAmplitudeRate;
};
对应的CPP:
//创建一个流体效果的3D网格动画。参一为动画的次数,参二为振幅,参三为格子大小,参四为动画时长。
CCLiquid* CCLiquid::actionWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration)
{
    return CCLiquid::create(wav, amp, gridSize, duration);
}
//上面的create实现。
CCLiquid* CCLiquid::create(int wav, float amp, const ccGridSize& gridSize, float duration)
{
    //先new出一个当前类的实例动画。
    CCLiquid *pAction = new CCLiquid();
    if (pAction)
    {
        //如果成功,进行初始化。
        if (pAction->initWithWaves(wav, amp, gridSize, duration))
        {
            //初始化成功交由内存管理器进行引用计数器的管理。
            pAction->autorelease();
        }
        else
        {
            //如果失败,释放并置空。
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}

//初始化
bool CCLiquid::initWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration)
{
    //先调用基类的初始化函数。
    if (CCGrid3DAction::initWithSize(gridSize, duration))
    {
        //将相应的参数保存到成员变量中。
        m_nWaves = wav;
        m_fAmplitude = amp;
        m_fAmplitudeRate = 1.0f;

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝。
CCObject* CCLiquid::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCLiquid* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCLiquid*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCLiquid();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCGrid3DAction::copyWithZone(pZone);

    pCopy->initWithWaves(m_nWaves, m_fAmplitude, m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//动画更新。
void CCLiquid::update(float time)
{
    int i, j;
    //双循环遍历所有的格子。
    for (i = 1; i < m_sGridSize.x; ++i)
    {
        for (j = 1; j < m_sGridSize.y; ++j)
        {
            //取出格子的原始顶点位置。
            ccVertex3F v = originalVertex(ccg(i, j));
            //设置顶点的x,y值。
            v.x = (v.x + (sinf(time * (float)M_PI * m_nWaves * 2 + v.x * .01f) * m_fAmplitude * m_fAmplitudeRate));
            v.y = (v.y + (sinf(time * (float)M_PI * m_nWaves * 2 + v.y * .01f) * m_fAmplitude * m_fAmplitudeRate));
            //将顶点数据设置给相应格子。
            setVertex(ccg(i, j), v);
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//波浪效果的网格动画,与CCWaves3D的区别是少了Z值的变化。
class CC_DLL CCWaves : public CCGrid3DAction
{
public:
    //设置振幅。
    inline float getAmplitude(void) { return m_fAmplitude; }
    inline void setAmplitude(float fAmplitude) { m_fAmplitude = fAmplitude; }
    //设置频率。
    inline float getAmplitudeRate(void) { return m_fAmplitudeRate; }
    inline void setAmplitudeRate(float fAmplitudeRate) { m_fAmplitudeRate = fAmplitudeRate; }

    //初始化。
    bool initWithWaves(int wav, float amp, bool h, bool v, const ccGridSize& gridSize,
        float duration);
    //产生一个当前类的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);
    //更新动画。
    virtual void update(float time);

public:
    //创建一个波浪效果的网格动画,参一为波浪的次数,参二为振幅,参三为是否进行横向运动,参四为是否进行竖向运动,参五为格子大小,参六为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCWaves* actionWithWaves(int wav, float amp, bool h, bool v, const ccGridSize& gridSize,
         float duration);

    //上面的create实现。
    static CCWaves* create(int wav, float amp, bool h, bool v, const ccGridSize& gridSize,
        float duration);
protected:
    //波浪次数。
    int m_nWaves;
    //振幅。
    float m_fAmplitude;
    //频率。
    float m_fAmplitudeRate;
    //竖向
    bool m_bVertical;
    //横向。
    bool m_bHorizontal;
};

//创建一个波浪效果的网格动画,参一为波浪的次数,参二为振幅,参三为是否进行横向运动,参四为是否进行竖向运动,参五为格子大小,参六为动画时长。
CCWaves* CCWaves::actionWithWaves(int wav, float amp, bool h, bool v, const ccGridSize& gridSize, float duration)
{
    return CCWaves::create(wav, amp, h, v, gridSize, duration);
}
//上面的create实现。
CCWaves* CCWaves::create(int wav, float amp, bool h, bool v, const ccGridSize& gridSize, float duration)
{
   //先new出一个当前类的实例。
    CCWaves *pAction = new CCWaves();
    //如果成功。
    if (pAction)
    {  //进行初始化。
        if (pAction->initWithWaves(wav, amp, h, v, gridSize, duration))
        {  //初始化成功,则交给内存管理器进行引用计数器的管理。
            pAction->autorelease();
        }
        else
        {
            //否则释放并置空。
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//初始化。
bool CCWaves::initWithWaves(int wav, float amp, bool h, bool v, const ccGridSize& gridSize, float duration)
{
    if (CCGrid3DAction::initWithSize(gridSize, duration))
    {
        m_nWaves = wav;
        m_fAmplitude = amp;
        m_fAmplitudeRate = 1.0f;
        m_bHorizontal = h;
        m_bVertical = v;

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝。
CCObject* CCWaves::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCWaves* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCWaves*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCWaves();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCGrid3DAction::copyWithZone(pZone);

    pCopy->initWithWaves(m_nWaves, m_fAmplitude, m_bHorizontal, m_bVertical, m_sGridSize, m_fDuration);
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//动画更新。
void CCWaves::update(float time)
{
    int i, j;
    //双循环遍历所有格子。
    for (i = 0; i < m_sGridSize.x + 1; ++i)
    {
        for (j = 0; j < m_sGridSize.y + 1; ++j)
        {
            //取得对应格子的顶点。
            ccVertex3F v = originalVertex(ccg(i, j));
            //如果进行横向运动。
            if (m_bVertical)
            {
               //计算X值。
                v.x = (v.x + (sinf(time * (float)M_PI * m_nWaves * 2 + v.y * .01f) * m_fAmplitude * m_fAmplitudeRate));
            }
            //如果进行竖向运动。
            if (m_bHorizontal)
            {   //计算Y值。
                v.y = (v.y + (sinf(time * (float)M_PI * m_nWaves * 2 + v.x * .01f) * m_fAmplitude * m_fAmplitudeRate));
            }
            //将顶点数据设置到相应格子中。
            setVertex(ccg(i, j), v);
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//盘旋扭曲效果的3D网格动画。
class CC_DLL CCTwirl : public CCGrid3DAction
{
public:
    //取得中心位置。
    inline const CCPoint& getPosition(void) { return m_position; }
    //设置中心位置。
    void setPosition(const CCPoint& position);
    //取得振幅。
    inline float getAmplitude(void) { return m_fAmplitude; }
    //设置振幅。
    inline void setAmplitude(float fAmplitude) { m_fAmplitude = fAmplitude; }
    //取得和设置频率。
    inline float getAmplitudeRate(void) { return m_fAmplitudeRate; }
    inline void setAmplitudeRate(float fAmplitudeRate) { m_fAmplitudeRate = fAmplitudeRate; }

    //初始化。
    bool initWithPosition(const CCPoint& pos, int t, float amp, const ccGridSize& gridSize,
        float duration);
    //产生一个当前类的实例拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//更新动画。
    virtual void update(float time);

public:
    //创建一个盘旋扭曲效果的3D网格动画。参一为中心位置,参二为盘旋扭曲的次数,参三为振幅,参四为格子大小,参五为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCTwirl* actionWithPosition(CCPoint pos, int t, float amp, const ccGridSize& gridSize,
         float duration);
    //上面的create实现。
    static CCTwirl* create(CCPoint pos, int t, float amp, const ccGridSize& gridSize,
        float duration);
protected:
    //中心点位置。
    CCPoint m_position;
    //盘旋扭曲的次数。
    int m_nTwirls;
    //振幅。
    float m_fAmplitude;
    //频率。
    float m_fAmplitudeRate;
}; 
//创建一个盘旋扭曲效果的3D网格动画。参一为中心位置,参二为盘旋扭曲的次数,参三为振幅,参四为格子大小,参五为动画时长。
CCTwirl* CCTwirl::actionWithPosition(CCPoint pos, int t, float amp, const ccGridSize& gridSize, float duration)
{
    return CCTwirl::create(pos, t, amp, gridSize, duration);
}
//上面的create实现。
CCTwirl* CCTwirl::create(CCPoint pos, int t, float amp, const ccGridSize& gridSize, float duration)
{
    //先new出一个当前类的实例。
    CCTwirl *pAction = new CCTwirl();

    if (pAction)
{
    //进行初始化。
        if (pAction->initWithPosition(pos, t, amp, gridSize, duration))
        {
            //成功则交由内存管理器进行引用计数器管理。
            pAction->autorelease();
        }
        else
        {   //失败则释放并置空。
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}

//初始化。
bool CCTwirl::initWithPosition(const CCPoint& pos, int t, float amp, const ccGridSize& gridSize, float duration)
{
    if (CCGrid3DAction::initWithSize(gridSize, duration))
    {
        setPosition(pos);
        m_nTwirls = t;
        m_fAmplitude = amp;
        m_fAmplitudeRate = 1.0f;

        return true;
    }

    return false;
}
//设置中心点位置。
void CCTwirl::setPosition(const CCPoint& position)
{
    m_position = position;
}
//产生一个当前类的实例拷贝。
CCObject* CCTwirl::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCTwirl* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject)
    {
        //in case of being called at sub class
        pCopy = (CCTwirl*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCTwirl();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCGrid3DAction::copyWithZone(pZone);


    pCopy->initWithPosition(m_position, m_nTwirls, m_fAmplitude, m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCTwirl::update(float time)
{
int i, j;
//将动画的中心点位置保存到点c中。
    CCPoint    c = m_position;
    //双循环遍历每个格子。
    for (i = 0; i < (m_sGridSize.x+1); ++i)
    {
        for (j = 0; j < (m_sGridSize.y+1); ++j)
        {
            //取得对应格子的顶点。
            ccVertex3F v = originalVertex(ccg(i ,j));
            //取得当前格子与格子中心位置的差。
            CCPoint    avg = ccp(i-(m_sGridSize.x/2.0f), j-(m_sGridSize.y/2.0f));
            //计算当前格子与中心点位置的距离。
            float r = ccpLength(avg);
            //计算振幅。
            float amp = 0.1f * m_fAmplitude * m_fAmplitudeRate;
            //使用cos公式来计算出曲线变化值。
            float a = r * cosf( (float)M_PI/2.0f + time * (float)M_PI * m_nTwirls * 2 ) * amp;
            //计算出一个偏移。
            CCPoint d = ccp(
                sinf(a) * (v.y-c.y) + cosf(a) * (v.x-c.x),
                cosf(a) * (v.y-c.y) - sinf(a) * (v.x-c.x));
            //当前顶点位置为动画中心点位置加上偏移。
            v.x = c.x + d.x;
            v.y = c.y + d.y;
            //将顶点设置给相应的格子。
            setVertex(ccg(i ,j), v);
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

    上面讲的是操控网格数据表现一些基本动画的类。下面我们来看一下由这些基本动画的类衍生出来的复杂动画。

 

打开CCActionTiledGrid.h:

#ifndef __ACTION_CCTILEDGRID_ACTION_H__
#define __ACTION_CCTILEDGRID_ACTION_H__

#include "CCActionGrid.h"
//使用Cocos2d命名空间
NS_CC_BEGIN

//摇动的3D格子动画。
class CC_DLL CCShakyTiles3D : public CCTiledGrid3DAction
{
public:
//初始化,参数一为范围大小,参数2为是否在Z值上摇动,参数3为格子的大小,参数4为动画的持续时间。
    bool initWithRange(int nRange, bool bShakeZ, const ccGridSize& gridSize,
        float duration);
	//创建一个当前类的实例拷贝
virtual CCObject* copyWithZone(CCZone* pZone);
//更新动画。
    virtual void update(float time);

public:
    //静态函数:创建一个摇动的3D格子动画。参一为范围大小,参数2为是否在Z值上摇动,参数3为格子的大小,参数4为动画的持续时间。内部调用create实现。

    CC_DEPRECATED_ATTRIBUTE static CCShakyTiles3D* actionWithRange(int nRange, bool bShakeZ, const ccGridSize& gridSize, float duration);

    //上面的create实现。
    static CCShakyTiles3D* create(int nRange, bool bShakeZ, const ccGridSize& gridSize, float duration);

protected:
	//随机范围。
int m_nRandrange;
//是否在Z值上摇动
    bool m_bShakeZ;
};
struct Tile
{
    CCPoint    position;
    CCPoint    startPosition;
    ccGridSize    delta;
};

//静态函数:创建一个摇动的3D格子动画。参一为范围大小,参数2为是否在Z值上摇动,参数3为格子的大小,参数4为动画的持续时间。内部调用create实现。
CCShakyTiles3D* CCShakyTiles3D::actionWithRange(int nRange, bool bShakeZ,const ccGridSize& gridSize, float duration)
{
    return CCShakyTiles3D::create(nRange, bShakeZ, gridSize, duration);    
}
//上面的create实现。
CCShakyTiles3D* CCShakyTiles3D::create(int nRange, bool bShakeZ,const ccGridSize& gridSize, float duration)
{
	//先new出一个当前类的实例。
    CCShakyTiles3D *pAction = new CCShakyTiles3D();
	//如果成功。初始化并交由内存管理器进行引用计数管理。
    if (pAction)
    {
        if (pAction->initWithRange(nRange, bShakeZ, gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {	//失败处理。
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }
	//返回结果。
    return pAction;    
}

//初始化。
bool CCShakyTiles3D::initWithRange(int nRange, bool bShakeZ, const ccGridSize& gridSize, float duration)
{
	//先调用基类的相应函数。
    if (CCTiledGrid3DAction::initWithSize(gridSize, duration))
{
	//保存相应的值到成员变量。
        m_nRandrange = nRange;
        m_bShakeZ = bShakeZ;

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝。讲的太多,略过。
CCObject* CCShakyTiles3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCShakyTiles3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCShakyTiles3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCShakyTiles3D();
        pZone = pNewZone = new CCZone(pCopy);
    }
    
    CCTiledGrid3DAction::copyWithZone(pZone);

    pCopy->initWithRange(m_nRandrange, m_bShakeZ, m_sGridSize, m_fDuration);
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCShakyTiles3D::update(float time)
{
    CC_UNUSED_PARAM(time);
    int i, j;
	//双循环遍历每个格子。
    for (i = 0; i < m_sGridSize.x; ++i)
    {
        for (j = 0; j < m_sGridSize.y; ++j)
        {
			//取得格子的位置。
            ccQuad3 coords = originalTile(ccg(i, j));

            // 计算格子四个顶点的X坐标。
            coords.bl.x += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
            coords.br.x += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
            coords.tl.x += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
            coords.tr.x += ( rand() % (m_nRandrange*2) ) - m_nRandrange;

            // 计算格子四个顶点的Y坐标。
            coords.bl.y += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
            coords.br.y += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
            coords.tl.y += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
            coords.tr.y += ( rand() % (m_nRandrange*2) ) - m_nRandrange;

			 // 是否在Z轴上摇动。
            if (m_bShakeZ)
            {
				  //如果摇动在四个顶点的Z值上有随机的加成。
                coords.bl.z += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.br.z += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.tl.z += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.tr.z += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
            }
            //重新设置格子的顶点。
            setTile(ccg(i, j), coords);
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//随机抖动效果的3D网格动画。
class CC_DLL CCShatteredTiles3D : public CCTiledGrid3DAction
{
public:
    //初始化函数。
    bool initWithRange(int nRange, bool bShatterZ, const ccGridSize& gridSize, float duration);
	//创建一个当前类的实例拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//更新动画。
    virtual void update(float time);

public:
    //静态函数:创建一个当前类的实例 。参一为范围,参数为是否在Z抽上震动,参三为格子大小,参四为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCShatteredTiles3D* actionWithRange(int nRange, bool bShatterZ, const ccGridSize& gridSize,
        float duration);

    //上面的create实现。
    static CCShatteredTiles3D* create(int nRange, bool bShatterZ, const ccGridSize& gridSize,
        float duration);
protected:
	//随机范围
int m_nRandrange;
//区分第一次渲染所用。
bool m_bOnce;
//是否在Z抽上震动。
    bool m_bShatterZ;
};

//静态函数:创建一个当前类的实例 。参一为范围,参数为是否在Z抽上震动,参三为格子大小,参四为动画时长。
CCShatteredTiles3D* CCShatteredTiles3D::actionWithRange(int nRange, bool bShatterZ, const ccGridSize& gridSize, float duration)
{
    return CCShatteredTiles3D::create(nRange, bShatterZ, gridSize, duration);    
}
//上面的create实现。
CCShatteredTiles3D* CCShatteredTiles3D::create(int nRange, bool bShatterZ, const ccGridSize& gridSize, float duration)
{
	//new,初始化,autorelease,失败处理一条龙!

    CCShatteredTiles3D *pAction = new CCShatteredTiles3D();

    if (pAction)
    {
        if (pAction->initWithRange(nRange, bShatterZ, gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }
	//返在回结果。
    return pAction;    
}

//初始化。
bool CCShatteredTiles3D::initWithRange(int nRange, bool bShatterZ, const ccGridSize& gridSize,  float duration)
{
	//先调用基类的初始化处理。
    if (CCTiledGrid3DAction::initWithSize(gridSize, duration))
{
	//设置标记提示在更新动理时指明是第一次进行更新。
        m_bOnce = false;
		//将相应的参数值保存到成员变量中。
        m_nRandrange = nRange;
        m_bShatterZ = bShatterZ;

        return true;
    }

    return false;
}
//产生一个当前类的实例。
CCObject* CCShatteredTiles3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCShatteredTiles3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject)
    {
        pCopy = (CCShatteredTiles3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCShatteredTiles3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    //copy super class's member
    CCTiledGrid3DAction::copyWithZone(pZone);

    pCopy->initWithRange(m_nRandrange, m_bShatterZ, m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCShatteredTiles3D::update(float time)
{
    CC_UNUSED_PARAM(time);
    int i, j;
	//如果是第一次渲染。
    if (m_bOnce == false)
{
	 //双循环遍历格子。
        for (i = 0; i < m_sGridSize.x; ++i)
        {
            for (j = 0; j < m_sGridSize.y; ++j)
            {
				  //取得格子的坐标。
                ccQuad3 coords = originalTile(ccg(i ,j));
                
                // 计算格子四个顶点的X坐标。
                coords.bl.x += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.br.x += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.tl.x += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.tr.x += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                
                // 计算格子四个顶点的Y坐标。
                coords.bl.y += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.br.y += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.tl.y += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                coords.tr.y += ( rand() % (m_nRandrange*2) ) - m_nRandrange;

                if (m_bShatterZ) 
                {
                    coords.bl.z += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                    coords.br.z += ( rand() % (m_nRandrange*2) ) - m_nRandrange;                
                    coords.tl.z += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                    coords.tr.z += ( rand() % (m_nRandrange*2) ) - m_nRandrange;
                }
                //重新设置格子的顶点。
                setTile(ccg(i, j), coords);
            }
        }
        //设置不是第一次更新。
        m_bOnce = true;
    }
}
struct Tile;
对应图:

Cocos2d-x 2.0 网格动画深入分析

//重新排列格子效果的3D网格动画。
class CC_DLL CCShuffleTiles : public CCTiledGrid3DAction
{
public:
	//析构
    ~CCShuffleTiles(void);
    //初始化函数。
bool initWithSeed(int s, const ccGridSize& gridSize, float duration);
//重新排列处理
void shuffle(int *pArray, unsigned int nLen);
//取得
ccGridSize getDelta(const ccGridSize& pos);
//
    void placeTile(const ccGridSize& pos, Tile *t);
	//重载基类的相应函数。
    virtual void startWithTarget(CCNode *pTarget);
    virtual void update(float time);
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
    //创建一个重新排列格子的动画:参一为,参二为格子大小,参三为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCShuffleTiles* actionWithSeed(int s, const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCShuffleTiles* create(int s, const ccGridSize& gridSize, float duration);
protected:
	//
    int             m_nSeed;
    unsigned int m_nTilesCount;
    int             *m_pTilesOrder;
    Tile         *m_pTiles;
};

//创建一个重新排列格子的动画:参一为,参二为格子大小,参三为动画时长。
CCShuffleTiles* CCShuffleTiles::actionWithSeed(int s, const ccGridSize& gridSize, float duration)
{
    return CCShuffleTiles::create(s, gridSize, duration);    
}
//上面的create实现。
CCShuffleTiles* CCShuffleTiles::create(int s, const ccGridSize& gridSize, float duration)
{
	//new ,初始化,autorelease,失败处理一条龙!
    CCShuffleTiles *pAction = new CCShuffleTiles();

    if (pAction)
    {
        if (pAction->initWithSeed(s, gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;    
}
//初始化处理。
bool CCShuffleTiles::initWithSeed(int s, const ccGridSize& gridSize, float duration)
{
	//先调用基类的相应函数。
    if (CCTiledGrid3DAction::initWithSize(gridSize, duration))
{
	//将参数值保存到成员变量中。
        m_nSeed = s;
        m_pTilesOrder = NULL;
        m_pTiles = NULL;

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝。
CCObject* CCShuffleTiles::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCShuffleTiles* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject)
    {
        pCopy = (CCShuffleTiles*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCShuffleTiles();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCTiledGrid3DAction::copyWithZone(pZone);

    pCopy->initWithSeed(m_nSeed, m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//析构。
CCShuffleTiles::~CCShuffleTiles(void)
{
	//释放申请的内存。
    CC_SAFE_DELETE_ARRAY(m_pTilesOrder);
    CC_SAFE_DELETE_ARRAY(m_pTiles);
}
//重新随机排列处理。
void CCShuffleTiles::shuffle(int *pArray, unsigned int nLen)
{
	//定义临时变量,并循环进行随机排列。
    int i;
    for( i = nLen - 1; i >= 0; i-- )
    {
        unsigned int j = rand() % (i+1);
		 //随机交换
        int v = pArray[i];
        pArray[i] = pArray[j];
        pArray[j] = v;
    }
}
//取得
ccGridSize CCShuffleTiles::getDelta(const ccGridSize& pos)
{
    CCPoint    pos2;
	//计算格子的位置索引 
    unsigned int idx = pos.x * m_sGridSize.y + pos.y;
	//取出
    pos2.x = (float)(m_pTilesOrder[idx] / (int)m_sGridSize.y);
    pos2.y = (float)(m_pTilesOrder[idx] % (int)m_sGridSize.y);
	//
    return ccg((int)(pos2.x - pos.x), (int)(pos2.y - pos.y));
}
//替换指定格子中的数据
void CCShuffleTiles::placeTile(const ccGridSize& pos, Tile *t)
{
	//取得对应格子大小的原始顶点数据
    ccQuad3 coords = originalTile(pos);
	//取得演员所用格子数据中格子的间隔。
CCPoint step = m_pTarget->getGrid()->getStep();

//计算出对应位置。
    coords.bl.x += (int)(t->position.x * step.x);
    coords.bl.y += (int)(t->position.y * step.y);

    coords.br.x += (int)(t->position.x * step.x);
    coords.br.y += (int)(t->position.y * step.y);

    coords.tl.x += (int)(t->position.x * step.x);
    coords.tl.y += (int)(t->position.y * step.y);

    coords.tr.x += (int)(t->position.x * step.x);
    coords.tr.y += (int)(t->position.y * step.y);
	//设置对应格子的数据。
    setTile(pos, coords);
}

//设置演示当前动画的演员。
void CCShuffleTiles::startWithTarget(CCNode *pTarget)
{
	//调用基类的相应函数。
    CCTiledGrid3DAction::startWithTarget(pTarget);

	//如果m_nSeed有效,则做为随机种子。
    if (m_nSeed != -1)
    {
        srand(m_nSeed);
    }
	//创建索引数组m_pTilesOrder
    m_nTilesCount = m_sGridSize.x * m_sGridSize.y;
    m_pTilesOrder = new int[m_nTilesCount];
    int i, j;
    unsigned int k;
    //将顺序索引填充到m_pTilesOrder
    for (k = 0; k < m_nTilesCount; ++k)
    {
        m_pTilesOrder[k] = k;
    }
	//对顺序索引数组进行重新随机排序。
    shuffle(m_pTilesOrder, m_nTilesCount);
	//创建格子数据。
    m_pTiles = (struct Tile *)new Tile[m_nTilesCount];
    Tile *tileArray = (Tile*) m_pTiles;

	//双循环遍历,通过结构指针设置相应格子的数据。
    for (i = 0; i < m_sGridSize.x; ++i)
    {
        for (j = 0; j < m_sGridSize.y; ++j)
        {
            tileArray->position = ccp((float)i, (float)j);
            tileArray->startPosition = ccp((float)i, (float)j);
            tileArray->delta = getDelta(ccg(i, j));
            ++tileArray;
        }
    }
}
//更新动画。
void CCShuffleTiles::update(float time)
{
    int i, j;
	//取得格子的数据指针。
    Tile *tileArray = (Tile*)m_pTiles;
	//双循环遍历。
    for (i = 0; i < m_sGridSize.x; ++i)
    {
        for (j = 0; j < m_sGridSize.y; ++j)
        {
			 //重新计算格子位置。
            tileArray->position = ccpMult(ccp((float)tileArray->delta.x, (float)tileArray->delta.y), time);
			  //将指针数据填充到对应格子。
            placeTile(ccg(i, j), tileArray);
            ++tileArray;
        }
    }
}

对应图:

Cocos2d-x 2.0 网格动画深入分析

//从右上角开始渐隐格子的动画。
class CC_DLL CCFadeOutTRTiles : public CCTiledGrid3DAction
{
public:
	//为了检测是否满足相应条件的函数。
virtual float testFunc(const ccGridSize& pos, float time);
//开启格子。
void turnOnTile(const ccGridSize& pos);
//关闭格子。
void turnOffTile(const ccGridSize& pos);
//跟据距离转换格子。
virtual void transformTile(const ccGridSize& pos, float distance);
//更新动画。
    virtual void update(float time);

public:
    //静态函数:创建一个从右上角渐隐格子的动画。参一为格子大小,参二为。
    CC_DEPRECATED_ATTRIBUTE static CCFadeOutTRTiles* actionWithSize(const ccGridSize& gridSize, float time);

    //上面的create实现。
    static CCFadeOutTRTiles* create(const ccGridSize& gridSize, float time);
};
//静态函数:创建一个从右上角渐隐格子的动画。参一为格子大小,参二为。
CCFadeOutTRTiles* CCFadeOutTRTiles::actionWithSize(const ccGridSize& gridSize, float time)
{
    return CCFadeOutTRTiles::create( gridSize, time);    
}
//上面的create实现。
CCFadeOutTRTiles* CCFadeOutTRTiles::create(const ccGridSize& gridSize, float time)
{
	//new,初始化,autorelease,失败处理一条龙!
    CCFadeOutTRTiles *pAction = new CCFadeOutTRTiles();

    if (pAction)
    {
        if (pAction->initWithSize(gridSize, time))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;    
}
//为了检测是否满足相应条件的函数。
float CCFadeOutTRTiles::testFunc(const ccGridSize& pos, float time)
{
	//计算出格子的位置。
CCPoint n = ccpMult(ccp((float)m_sGridSize.x, (float)m_sGridSize.y), time);
//为了后面powf中的除法避免除零而做的判断。
    if ((n.x + n.y) == 0.0f)
    {
        return 1.0f;
    }
	//计算出一个powf处理后的值。
    return powf((pos.x + pos.y) / (n.x + n.y), 6);
}
//开启格子。
void CCFadeOutTRTiles::turnOnTile(const ccGridSize& pos)
{
	//设置格子位置为原始数据。
    setTile(pos, originalTile(pos));
}

//关闭格子。
void CCFadeOutTRTiles::turnOffTile(const ccGridSize& pos)
{
	//定义一个新的顶点数据,都清零后设置为对应格子的顶点数据。
    ccQuad3 coords;
    memset(&coords, 0, sizeof(ccQuad3));
    setTile(pos, coords);
}
//跟据距离转换格子。
void CCFadeOutTRTiles::transformTile(const ccGridSize& pos, float distance)
{
	//取得对应格子的顶点数据。
ccQuad3 coords = originalTile(pos);
//取得每个像素所占的图像大小。
    CCPoint step = m_pTarget->getGrid()->getStep();
	//通过距离进行位置的重新计算。
    coords.bl.x += (step.x / 2) * (1.0f - distance);
    coords.bl.y += (step.y / 2) * (1.0f - distance);

    coords.br.x -= (step.x / 2) * (1.0f - distance);
    coords.br.y += (step.y / 2) * (1.0f - distance);

    coords.tl.x += (step.x / 2) * (1.0f - distance);
    coords.tl.y -= (step.y / 2) * (1.0f - distance);

    coords.tr.x -= (step.x / 2) * (1.0f - distance);
    coords.tr.y -= (step.y / 2) * (1.0f - distance);
	//用新数据设置对应格子的顶点数据。
    setTile(pos, coords);
}
//更新动画。
void CCFadeOutTRTiles::update(float time)
{
    int i, j;
	//双循环遍历。
    for (i = 0; i < m_sGridSize.x; ++i)
    {
        for (j = 0; j < m_sGridSize.y; ++j)
        {
			 //为了检测是否满足相应条件的函数,返回距离值。
            float distance = testFunc(ccg(i, j), time);
            if ( distance == 0 )
            {
				 //如果距离为0,关闭格子。
                turnOffTile(ccg(i, j));
            } else 
            if (distance < 1)
            {
				  //如果距离在0~1间,进行格子的转换处理。
                transformTile(ccg(i, j), distance);
            }
            else
            {
				 //如果距离大于等于1,开启格子。
                turnOnTile(ccg(i, j));
            }
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//从左下角渐隐格子的动画。
class CC_DLL CCFadeOutBLTiles : public CCFadeOutTRTiles
{
public:
	//检测是否满足相应条件的函数
    virtual float testFunc(const ccGridSize& pos, float time);

public:
    //静态函数:创建一个从左下角渐隐格子的动画。参一为格子大小,参二为。
    CC_DEPRECATED_ATTRIBUTE static CCFadeOutBLTiles* actionWithSize(const ccGridSize& gridSize, float time);

//上面的create实现。
    static CCFadeOutBLTiles* create(const ccGridSize& gridSize, float time);
};
// //静态函数:创建一个从左下角渐隐格子的动画。参一为格子大小,参二为。

CCFadeOutBLTiles* CCFadeOutBLTiles::actionWithSize(const ccGridSize& gridSize, float time)
{
    return CCFadeOutBLTiles::create(gridSize, time);
}
//上面的create实现。
CCFadeOutBLTiles* CCFadeOutBLTiles::create(const ccGridSize& gridSize, float time)
{
	//new ,初始化,autorelease,失败处理一条龙!
    CCFadeOutBLTiles *pAction = new CCFadeOutBLTiles();

    if (pAction)
    {
        if (pAction->initWithSize(gridSize, time))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//检测是否满足相应条件的函数
float CCFadeOutBLTiles::testFunc(const ccGridSize& pos, float time)
{
	//计算出格子的位置。
CCPoint n = ccpMult(ccp((float)m_sGridSize.x, (float)m_sGridSize.y), (1.0f - time));
//为了后面powf中的除法避免除零而做的判断。

    if ((pos.x + pos.y) == 0)
    {
        return 1.0f;
    }
	//计算出一个powf处理后的值。

    return powf((n.x + n.y) / (pos.x + pos.y), 6);
}
//向上部渐隐格子的动画。
class CC_DLL CCFadeOutUpTiles : public CCFadeOutTRTiles
{
public:
	//检测是否满足相应条件的函数
virtual float testFunc(const ccGridSize& pos, float time);
//跟据距离转换格子。
    virtual void transformTile(const ccGridSize& pos, float distance);

public:
//静态函数:创建一个从上部渐隐格子的动画。参一为格子大小,参二为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCFadeOutUpTiles* actionWithSize(const ccGridSize& gridSize, float time);
    //上面的create实现。
    static CCFadeOutUpTiles* create(const ccGridSize& gridSize, float time);

};
//静态函数:创建一个从上部渐隐格子的动画。参一为格子大小,参二为动画时长。

CCFadeOutUpTiles* CCFadeOutUpTiles::actionWithSize(const ccGridSize& gridSize, float time)
{
    return CCFadeOutUpTiles::create(gridSize, time);
}
//上面的create实现。
CCFadeOutUpTiles* CCFadeOutUpTiles::create(const ccGridSize& gridSize, float time)
{
	//new ,初始化,autorelease,失败处理一条龙!

    CCFadeOutUpTiles *pAction = new CCFadeOutUpTiles();

    if (pAction)
    {
        if (pAction->initWithSize(gridSize, time))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//检测是否满足相应条件的函数
float CCFadeOutUpTiles::testFunc(const ccGridSize& pos, float time)
{
	//计算出格子的位置。
CCPoint n = ccpMult(ccp((float)m_sGridSize.x, (float)m_sGridSize.y), time);
//为了后面powf中的除法避免除零而做的判断。

    if (n.y == 0.0f)
    {
        return 1.0f;
    }
	//计算出一个powf处理后的值。

    return powf(pos.y / n.y, 6);
}
//跟据距离转换格子。
void CCFadeOutUpTiles::transformTile(const ccGridSize& pos, float distance)
{
	//取得对应格子的顶点数据。
ccQuad3 coords = originalTile(pos);
//取得一个格子所占用的图像大小。
    CCPoint step = m_pTarget->getGrid()->getStep();
	//通过距离进行位置的重新计算。
	//让格子的下部的Y值上移,上部的Y值下移,这样格子就像被压扁了一样的效果。
    coords.bl.y += (step.y / 2) * (1.0f - distance);
    coords.br.y += (step.y / 2) * (1.0f - distance);
    coords.tl.y -= (step.y / 2) * (1.0f - distance);
    coords.tr.y -= (step.y / 2) * (1.0f - distance);
	//设置格子的新位置。
    setTile(pos, coords);
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//从左下角渐隐格子的动画。
class CC_DLL CCFadeOutBLTiles : public CCFadeOutTRTiles
{
public:
	//检测是否满足相应条件的函数
    virtual float testFunc(const ccGridSize& pos, float time);

public:
    //静态函数:创建一个从左下角渐隐格子的动画。参一为格子大小,参二为。
    CC_DEPRECATED_ATTRIBUTE static CCFadeOutBLTiles* actionWithSize(const ccGridSize& gridSize, float time);

//上面的create实现。
    static CCFadeOutBLTiles* create(const ccGridSize& gridSize, float time);
};
// //静态函数:创建一个从左下角渐隐格子的动画。参一为格子大小,参二为。

CCFadeOutBLTiles* CCFadeOutBLTiles::actionWithSize(const ccGridSize& gridSize, float time)
{
    return CCFadeOutBLTiles::create(gridSize, time);
}
//上面的create实现。
CCFadeOutBLTiles* CCFadeOutBLTiles::create(const ccGridSize& gridSize, float time)
{
	//new ,初始化,autorelease,失败处理一条龙!
    CCFadeOutBLTiles *pAction = new CCFadeOutBLTiles();

    if (pAction)
    {
        if (pAction->initWithSize(gridSize, time))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//检测是否满足相应条件的函数
float CCFadeOutBLTiles::testFunc(const ccGridSize& pos, float time)
{
	//计算出格子的位置。
CCPoint n = ccpMult(ccp((float)m_sGridSize.x, (float)m_sGridSize.y), (1.0f - time));
//为了后面powf中的除法避免除零而做的判断。

    if ((pos.x + pos.y) == 0)
    {
        return 1.0f;
    }
	//计算出一个powf处理后的值。

    return powf((n.x + n.y) / (pos.x + pos.y), 6);
}

对应图:

Cocos2d-x 2.0 网格动画深入分析

//向上部渐隐格子的动画。
class CC_DLL CCFadeOutUpTiles : public CCFadeOutTRTiles
{
public:
	//检测是否满足相应条件的函数
virtual float testFunc(const ccGridSize& pos, float time);
//跟据距离转换格子。
    virtual void transformTile(const ccGridSize& pos, float distance);

public:
//静态函数:创建一个从上部渐隐格子的动画。参一为格子大小,参二为动画时长。
    CC_DEPRECATED_ATTRIBUTE static CCFadeOutUpTiles* actionWithSize(const ccGridSize& gridSize, float time);
    //上面的create实现。
    static CCFadeOutUpTiles* create(const ccGridSize& gridSize, float time);

};
//静态函数:创建一个从上部渐隐格子的动画。参一为格子大小,参二为动画时长。

CCFadeOutUpTiles* CCFadeOutUpTiles::actionWithSize(const ccGridSize& gridSize, float time)
{
    return CCFadeOutUpTiles::create(gridSize, time);
}
//上面的create实现。
CCFadeOutUpTiles* CCFadeOutUpTiles::create(const ccGridSize& gridSize, float time)
{
	//new ,初始化,autorelease,失败处理一条龙!

    CCFadeOutUpTiles *pAction = new CCFadeOutUpTiles();

    if (pAction)
    {
        if (pAction->initWithSize(gridSize, time))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//检测是否满足相应条件的函数
float CCFadeOutUpTiles::testFunc(const ccGridSize& pos, float time)
{
	//计算出格子的位置。
CCPoint n = ccpMult(ccp((float)m_sGridSize.x, (float)m_sGridSize.y), time);
//为了后面powf中的除法避免除零而做的判断。

    if (n.y == 0.0f)
    {
        return 1.0f;
    }
	//计算出一个powf处理后的值。

    return powf(pos.y / n.y, 6);
}
//跟据距离转换格子。
void CCFadeOutUpTiles::transformTile(const ccGridSize& pos, float distance)
{
	//取得对应格子的顶点数据。
ccQuad3 coords = originalTile(pos);
//取得一个格子所占用的图像大小。
    CCPoint step = m_pTarget->getGrid()->getStep();
	//通过距离进行位置的重新计算。
	//让格子的下部的Y值上移,上部的Y值下移,这样格子就像被压扁了一样的效果。
    coords.bl.y += (step.y / 2) * (1.0f - distance);
    coords.br.y += (step.y / 2) * (1.0f - distance);
    coords.tl.y -= (step.y / 2) * (1.0f - distance);
    coords.tr.y -= (step.y / 2) * (1.0f - distance);
	//设置格子的新位置。
    setTile(pos, coords);
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//向下部渐隐格子的动画。
class CC_DLL CCFadeOutDownTiles : public CCFadeOutUpTiles
{
public:
	//检测是否满足相应条件的函数

    virtual float testFunc(const ccGridSize& pos, float time);

public:
 //静态函数:创建一个从下部渐隐格子的动画。参一为格子大小,参二为动画时长。

    CC_DEPRECATED_ATTRIBUTE static CCFadeOutDownTiles* actionWithSize(const ccGridSize& gridSize, float time);

    //上面的create实现。
    static CCFadeOutDownTiles* create(const ccGridSize& gridSize, float time);
};
//静态函数:创建一个从下部渐隐格子的动画。参一为格子大小,参二为动画时长。

CCFadeOutDownTiles* CCFadeOutDownTiles::actionWithSize(const ccGridSize& gridSize, float time)
{
    return CCFadeOutDownTiles::create(gridSize, time);
}
//上面的create实现。
CCFadeOutDownTiles* CCFadeOutDownTiles::create(const ccGridSize& gridSize, float time)
{
	//new ,初始化,autorelease,失败处理一条龙!

    CCFadeOutDownTiles *pAction = new CCFadeOutDownTiles();

    if (pAction)
    {
        if (pAction->initWithSize(gridSize, time))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}

//检测是否满足相应条件的函数
float CCFadeOutDownTiles::testFunc(const ccGridSize& pos, float time)
{
	//计算出格子的位置。
CCPoint n = ccpMult(ccp((float)m_sGridSize.x, (float)m_sGridSize.y), (1.0f - time));
//为了后面powf中的除法避免除零而做的判断。
    if (pos.y == 0)
    {
        return 1.0f;
    }
	//计算出一个powf处理后的值。
    return powf(n.y / pos.y, 6);
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//格子的消失动画
class CC_DLL CCTurnOffTiles : public CCTiledGrid3DAction
{
public:
	//析构
    ~CCTurnOffTiles(void);
    //初始化
bool initWithSeed(int s, const ccGridSize& gridSize, float duration);
//重新排列格子。
void shuffle(int *pArray, unsigned int nLen);
//开启格子。
void turnOnTile(const ccGridSize& pos);
//关闭格子。
    void turnOffTile(const ccGridSize& pos);
	//重载基类的相应函数。
    virtual CCObject* copyWithZone(CCZone* pZone);
    virtual void startWithTarget(CCNode *pTarget);
    virtual void update(float time);

public:
    //创建一个
    CC_DEPRECATED_ATTRIBUTE static CCTurnOffTiles* actionWithSize(const ccGridSize& size, float d);
    // 
    CC_DEPRECATED_ATTRIBUTE static CCTurnOffTiles* actionWithSeed(int s, const ccGridSize& gridSize, float duration);

    //上面的create实现。
    static CCTurnOffTiles* create(const ccGridSize& size, float d);
    //上面的create实现。
    static CCTurnOffTiles* create(int s, const ccGridSize& gridSize, float duration);

protected:
    int                m_nSeed;
    unsigned int    m_nTilesCount;
    int                *m_pTilesOrder;
};
//创建一个
CCTurnOffTiles* CCTurnOffTiles::actionWithSize(const ccGridSize& size, float d)
{
    return CCTurnOffTiles::create( size, d);
}
//上面的create实现。
CCTurnOffTiles* CCTurnOffTiles::create(const ccGridSize& size, float d)
{
	//new ,初始化,autorelease,失败处理一条龙!

    CCTurnOffTiles* pAction = new CCTurnOffTiles();
    if (pAction->initWithSize(size, d))
    {
        pAction->autorelease();
    }
    else
    {
        CC_SAFE_RELEASE_NULL(pAction);
    }
    return pAction;
}

//创建一个
CCTurnOffTiles* CCTurnOffTiles::actionWithSeed(int s, const ccGridSize& gridSize, float duration)
{
    return CCTurnOffTiles::create(s, gridSize, duration);
}
//上面的create实现。

CCTurnOffTiles* CCTurnOffTiles::create(int s, const ccGridSize& gridSize, float duration)
{
	//new ,初始化,autorelease,失败处理一条龙!
    CCTurnOffTiles *pAction = new CCTurnOffTiles();

    if (pAction)
    {
        if (pAction->initWithSeed(s, gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//初始化。
bool CCTurnOffTiles::initWithSeed(int s, const ccGridSize& gridSize, float duration)
{
	//调用基类的相应函数。
    if (CCTiledGrid3DAction::initWithSize(gridSize, duration))
{
	//保存参数到成员变量。
        m_nSeed = s;
        m_pTilesOrder = NULL;

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝。
CCObject* CCTurnOffTiles::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCTurnOffTiles* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        pCopy = (CCTurnOffTiles*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCTurnOffTiles();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCTiledGrid3DAction::copyWithZone(pZone);

    pCopy->initWithSeed(m_nSeed, m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//析构。
CCTurnOffTiles::~CCTurnOffTiles(void)
{
    CC_SAFE_DELETE_ARRAY(m_pTilesOrder);
}
//重新随机排列。
void CCTurnOffTiles::shuffle(int *pArray, unsigned int nLen)
{
	//定义临时变量,并循环进行随机排列。
    int i;
    for (i = nLen - 1; i >= 0; i--)
{
	//随机交换。
        unsigned int j = rand() % (i+1);
        int v = pArray[i];
        pArray[i] = pArray[j];
        pArray[j] = v;
    }
}
//开启格子
void CCTurnOffTiles::turnOnTile(const ccGridSize& pos)
{
	//设置格子的数据为原始数据。
    setTile(pos, originalTile(pos));
}
//关闭格子。
void CCTurnOffTiles::turnOffTile(const ccGridSize& pos)
{
	//定义一个新的顶点数据,都清零后设置为对应格子的顶点数据。

    ccQuad3 coords;
    memset(&coords, 0, sizeof(ccQuad3));
    setTile(pos, coords);
}

//设置演示当前动画的演员。
void CCTurnOffTiles::startWithTarget(CCNode *pTarget)
{
	//
    unsigned int i;
	//调用基类的相应函数。
    CCTiledGrid3DAction::startWithTarget(pTarget);
	//初始化随机种子。
    if (m_nSeed != -1)
    {
        srand(m_nSeed);
    }
	//取得格子数量
m_nTilesCount = m_sGridSize.x * m_sGridSize.y;
//创建相应大小的排序索引数组。
    m_pTilesOrder = new int[m_nTilesCount];
	//填充数据。
    for (i = 0; i < m_nTilesCount; ++i)
    {
        m_pTilesOrder[i] = i;
    }
	//随机排列格子。
    shuffle(m_pTilesOrder, m_nTilesCount);
}
//更新动画。
void CCTurnOffTiles::update(float time)
{
    unsigned int i, l, t;
	//通过进度值计算要消失的格子的数量。
    l = (int)(time * (float)m_nTilesCount);
	//遍历每个格子
    for( i = 0; i < m_nTilesCount; i++ )
{
	//取出顺序索引,并计算出相应的格子位置。
        t = m_pTilesOrder[i];
        ccGridSize tilePos = ccg( t / m_sGridSize.y, t % m_sGridSize.y );
		//如果当前索引i小于要消失的可子的数量值,关闭格子。
        if ( i < l )
        {
            turnOffTile(tilePos);
        }
        else
        {	//开启格子。
            turnOnTile(tilePos);
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//波浪状的格子动画。
class CC_DLL CCWavesTiles3D : public CCTiledGrid3DAction
{
public:
    //取得和设置振幅。
    inline float getAmplitude(void) { return m_fAmplitude; }
    inline void setAmplitude(float fAmplitude) { m_fAmplitude = fAmplitude; }

    //取得和设置频率。
    inline float getAmplitudeRate(void) { return m_fAmplitudeRate; }
    inline void setAmplitudeRate(float fAmplitudeRate) { m_fAmplitudeRate = fAmplitudeRate; }

    //初始化波浪状网格的动画
    bool initWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration);
	//创建一个当前类的实例拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//更新动画。
    virtual void update(float time);

public:
    //静态函数:创建一个当前类的实例对象指针,参数一为
    CC_DEPRECATED_ATTRIBUTE static CCWavesTiles3D* actionWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCWavesTiles3D* create(int wav, float amp, const ccGridSize& gridSize, float duration);
protected:
int m_nWaves;
//振幅。
float m_fAmplitude;
//频率。
    float m_fAmplitudeRate;
};
//静态函数:创建一个当前类的实例对象指针,参数一为
CCWavesTiles3D* CCWavesTiles3D::actionWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration)
{
    return CCWavesTiles3D::create(wav, amp, gridSize, duration);
}
//上面的create实现。
CCWavesTiles3D* CCWavesTiles3D::create(int wav, float amp, const ccGridSize& gridSize, float duration)
{
	//new ,初始化,autorelease,失败处理一条龙!
    CCWavesTiles3D *pAction = new CCWavesTiles3D();

    if (pAction)
    {
        if (pAction->initWithWaves(wav, amp, gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//初始化。
bool CCWavesTiles3D::initWithWaves(int wav, float amp, const ccGridSize& gridSize, float duration)
{
	//调用基类的初始化函数。
    if (CCTiledGrid3DAction::initWithSize(gridSize, duration))
{
	//将相应参数保存到成员变量中。
        m_nWaves = wav;
        m_fAmplitude = amp;
        m_fAmplitudeRate = 1.0f;

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝。
CCObject* CCWavesTiles3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCWavesTiles3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject)
    {
        pCopy = (CCWavesTiles3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCWavesTiles3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCTiledGrid3DAction::copyWithZone(pZone);

    pCopy->initWithWaves(m_nWaves, m_fAmplitude, m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCWavesTiles3D::update(float time)
{
    int i, j;
	//双循环遍历。
    for( i = 0; i < m_sGridSize.x; i++ )
    {
        for( j = 0; j < m_sGridSize.y; j++ )
        {
			//取得对应格子的顶点数据。
            ccQuad3 coords = originalTile(ccg(i, j));

			 //重新设置顶点数据位置。
            coords.bl.z = (sinf(time * (float)M_PI  *m_nWaves * 2 + 
                (coords.bl.y+coords.bl.x) * .01f) * m_fAmplitude * m_fAmplitudeRate );
            coords.br.z    = coords.bl.z;
            coords.tl.z = coords.bl.z;
            coords.tr.z = coords.bl.z;

			 //将新的位置数据设置给相应格子。
            setTile(ccg(i, j), coords);
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//跳动的格子动画。
class CC_DLL CCJumpTiles3D : public CCTiledGrid3DAction
{
public:
    //取得跳动的范围。
    inline float getAmplitude(void) { return m_fAmplitude; }
    inline void setAmplitude(float fAmplitude) { m_fAmplitude = fAmplitude; }

//取和和设置频率。
    inline float getAmplitudeRate(void) { return m_fAmplitudeRate; }
    inline void setAmplitudeRate(float fAmplitudeRate) { m_fAmplitudeRate = fAmplitudeRate; }

    //初始化。
bool initWithJumps(int j, float amp, const ccGridSize& gridSize, float duration);
//创建一个当前类的实例拷贝。
virtual CCObject* copyWithZone(CCZone* pZone);
//更新动画。
    virtual void update(float time);

public:
    //静态函数:创建一个当前类的动画实例。
    CC_DEPRECATED_ATTRIBUTE static CCJumpTiles3D* actionWithJumps(int j, float amp, const ccGridSize& gridSize, float duration);
    //上面的create实现。
    static CCJumpTiles3D* create(int j, float amp, const ccGridSize& gridSize, float duration);
protected:
	//跳跃的次数。
int m_nJumps;
//振幅。
float m_fAmplitude;
//频率。
    float m_fAmplitudeRate;
};
//静态函数:创建一个当前类的动画实例。
CCJumpTiles3D* CCJumpTiles3D::actionWithJumps(int j, float amp, const ccGridSize& gridSize, float duration)
{
    return CCJumpTiles3D::create(j, amp, gridSize, duration);
}
//上面的create实现。
CCJumpTiles3D* CCJumpTiles3D::create(int j, float amp, const ccGridSize& gridSize, float duration)
{
	//new ,初始化,autorelease,失败处理一条龙!

    CCJumpTiles3D *pAction = new CCJumpTiles3D();

    if (pAction)
    {
        if (pAction->initWithJumps(j, amp, gridSize, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//初始化。
bool CCJumpTiles3D::initWithJumps(int j, float amp, const ccGridSize& gridSize, float duration)
{
	//调用基类的相应函数。
    if (CCTiledGrid3DAction::initWithSize(gridSize, duration))
{
	//保存参数到成员变量。
        m_nJumps = j;
        m_fAmplitude = amp;
        m_fAmplitudeRate = 1.0f;

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝。
CCObject* CCJumpTiles3D::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCJumpTiles3D* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        pCopy = (CCJumpTiles3D*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCJumpTiles3D();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCTiledGrid3DAction::copyWithZone(pZone);
    pCopy->initWithJumps(m_nJumps, m_fAmplitude, m_sGridSize, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCJumpTiles3D::update(float time)
{
    int i, j;

	//定义两个临时变量,分别设置为不同的sin曲线变化值。
    float sinz =  (sinf((float)M_PI * time * m_nJumps * 2) * m_fAmplitude * m_fAmplitudeRate );
    float sinz2 = (sinf((float)M_PI * (time * m_nJumps * 2 + 1)) * m_fAmplitude * m_fAmplitudeRate );

	//双循环遍历。
    for( i = 0; i < m_sGridSize.x; i++ )
    {
        for( j = 0; j < m_sGridSize.y; j++ )
        {
			//取得对应格子的顶点数据。
            ccQuad3 coords = originalTile(ccg(i, j));

			//(i+j)的值对2取模,可以实现上,下,左,右相邻的Z值加成不同。
            if ( ((i+j) % 2) == 0 )
            {
                coords.bl.z += sinz;
                coords.br.z += sinz;
                coords.tl.z += sinz;
                coords.tr.z += sinz;
            }
            else
            {
                coords.bl.z += sinz2;
                coords.br.z += sinz2;
                coords.tl.z += sinz2;
                coords.tr.z += sinz2;
            }

			 //将新的顶点数据设置给相应格子。
            setTile(ccg(i, j), coords);
        }
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//横向分割的格子动画。
class CC_DLL CCSplitRows : public CCTiledGrid3DAction
{
public :
    //初始化。
    bool initWithRows(int nRows, float duration);
	//重载基类的相应函数。
    virtual CCObject* copyWithZone(CCZone* pZone);
    virtual void update(float time);
    virtual void startWithTarget(CCNode *pTarget);

public:
    //静态函数:创建一个横向分割的格子动画。参一为横向分的份数,参二为动画时长。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCSplitRows* actionWithRows(int nRows, float duration);
    //上面的create实现。
    static CCSplitRows* create(int nRows, float duration);
protected:
	//切分的行数。
int m_nRows;
//屏幕大小。
    CCSize m_winSize;
};
//静态函数:创建一个横向分割的格子动画。参一为横向分的份数,参二为动画时长。内部调用create实现。
CCSplitRows* CCSplitRows::actionWithRows(int nRows, float duration)
{
    return CCSplitRows::create(nRows, duration);
}
//上面的create实现。
CCSplitRows* CCSplitRows::create(int nRows, float duration)
{
	//new ,初始化,autorelease,失败处理一条龙!

    CCSplitRows *pAction = new CCSplitRows();

    if (pAction)
    {
        if (pAction->initWithRows(nRows, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//初始化。
bool CCSplitRows::initWithRows(int nRows, float duration)
{
	//保存切分的份数。
    m_nRows = nRows;
//将切分的份数做为参数放在格子大小的Y值中初始化3D格子动画。
    return CCTiledGrid3DAction::initWithSize(ccg(1, nRows), duration);
}
//产生一个当前类的实例拷贝。
CCObject* CCSplitRows::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCSplitRows* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        pCopy = (CCSplitRows*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCSplitRows();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCTiledGrid3DAction::copyWithZone(pZone);

    pCopy->initWithRows(m_nRows, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//以置演示当前动画的演员。
void CCSplitRows::startWithTarget(CCNode *pTarget)
{
    CCTiledGrid3DAction::startWithTarget(pTarget);
    m_winSize = CCDirector::sharedDirector()->getWinSizeInPixels();
}
//更新动画。
void CCSplitRows::update(float time)
{
    int j;
	//遍历切分的格子。在初始化时说过格子大小的Y值中保存了切分的份数。
    for (j = 0; j < m_sGridSize.y; ++j)
{
	//通过格子的的索引取得原始的顶点位置。
        ccQuad3 coords = originalTile(ccg(0, j));
//创建临时变量保存方向。
        float    direction = 1;
		//对i取2的模,可使相邻的切分块方向不同。
        if ( (j % 2 ) == 0 )
        {
            direction = -1;
        }
		//根据方向来对顶点X值进行偏移。
        coords.bl.x += direction * m_winSize.width * time;
        coords.br.x += direction * m_winSize.width * time;
        coords.tl.x += direction * m_winSize.width * time;
        coords.tr.x += direction * m_winSize.width * time;
		//设置格子的顶点数据,这样就可以实现每个切分格子的运动了。
        setTile(ccg(0, j), coords);
    }
}
对应图:

Cocos2d-x 2.0 网格动画深入分析

//纵向切分的格子运动动画。
class CC_DLL CCSplitCols : public CCTiledGrid3DAction
{
public:
    //初始化。
    bool initWithCols(int nCols, float duration);
	//重载基类的相应函数。
    virtual CCObject* copyWithZone(CCZone* pZone);
    virtual void update(float time);
    virtual void startWithTarget(CCNode *pTarget);

public:
    //静态函数:创建一个纵向分割的格子动画。参一为纵向切分的份数,参二为动画时长。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCSplitCols* actionWithCols(int nCols, float duration);
    //上面的create实现。
    static CCSplitCols* create(int nCols, float duration);
protected:
	//切分的列数。
int m_nCols;
//屏幕大小。
    CCSize m_winSize;
};
//静态函数:创建一个纵向分割的格子动画。参一为纵向切分的份数,参二为动画时长。内部调用create实现。

CCSplitCols* CCSplitCols::actionWithCols(int nCols, float duration)
{
    return CCSplitCols::create(nCols, duration);
}
//上面的create实现。
CCSplitCols* CCSplitCols::create(int nCols, float duration)
{
	//new ,初始化,autorelease,失败处理一条龙!
    CCSplitCols *pAction = new CCSplitCols();

    if (pAction)
    {
        if (pAction->initWithCols(nCols, duration))
        {
            pAction->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pAction);
        }
    }

    return pAction;
}
//初始化。
bool CCSplitCols::initWithCols(int nCols, float duration)
{
	//保存切分的份数。
m_nCols = nCols;
//将切分的份数做为参数放在格子大小的X值中初始化3D格子动画。
    return CCTiledGrid3DAction::initWithSize(ccg(nCols, 1), duration);
}
//产生一个当前类的实例拷贝。
CCObject* CCSplitCols::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCSplitCols* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        pCopy = (CCSplitCols*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCSplitCols();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCTiledGrid3DAction::copyWithZone(pZone);
    pCopy->initWithCols(m_nCols, m_fDuration);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//设置演示当前动画的演员。
void CCSplitCols::startWithTarget(CCNode *pTarget)
{
	//调用基类的相应函数。
CCTiledGrid3DAction::startWithTarget(pTarget);
//取得屏幕大小
    m_winSize = CCDirector::sharedDirector()->getWinSizeInPixels();
}
//更新动画。
void CCSplitCols::update(float time)
{
    int i;
	//遍历切分的格子。在初始化时说过格子大小的X值中保存了切分的份数。
    for (i = 0; i < m_sGridSize.x; ++i)
{
	//通过格子的的索引取得原始的顶点位置。
        ccQuad3 coords = originalTile(ccg(i, 0));
		//创建临时变量保存方向。
        float    direction = 1;
		//对i取2的模,可使相邻的切分块方向不同。
        if ( (i % 2 ) == 0 )
        {
            direction = -1;
        }
		//根据方向来对顶点Y值进行偏移。
        coords.bl.y += direction * m_winSize.height * time;
        coords.br.y += direction * m_winSize.height * time;
        coords.tl.y += direction * m_winSize.height * time;
        coords.tr.y += direction * m_winSize.height * time;
		//设置格子的顶点数据,这样就可以实现每个切分格子的运动了。
        setTile(ccg(i, 0), coords);
    }
}

对应图:

Cocos2d-x 2.0 网格动画深入分析

最后我们来看一下EffectsTest的场景演示方面的代码:

EffectsTest.h:

//由TestScene派生出一个场景。
class EffectTestScene : public TestScene
{
public:
    //运行这个场景。
    virtual void runThisTest();
};
//由CCLayerColor派生出一个TextLayer,用于演示各动画效果。
class TextLayer : public CCLayerColor
{
protected:
    //UxString    m_strTitle;

public:
    TextLayer(void);
    ~TextLayer(void);

    void checkAnim(float dt);

    virtual void onEnter();

    void restartCallback(CCObject* pSender);
    void nextCallback(CCObject* pSender);
    void backCallback(CCObject* pSender);

    void newScene();

    static TextLayer* create();
};

对应CPP:

//
enum {
    kTagTextLayer = 1,
    kTagBackground = 1,
    kTagLabel = 2,
};
//动画的索引
static int actionIdx=0; 
//效果标题列表。
static std::string effectsList[] =
{
    "Shaky3D",
    "Waves3D",
    "FlipX3D",
    "FlipY3D",
    "Lens3D",
    "Ripple3D",
    "Liquid",
    "Waves",
    "Twirl",
    "ShakyTiles3D",
    "ShatteredTiles3D",
    "ShuffleTiles",
    "FadeOutTRTiles",
    "FadeOutBLTiles",
    "FadeOutUpTiles",
    "FadeOutDownTiles",
    "TurnOffTiles",
    "WavesTiles3D",
    "JumpTiles3D",
    "SplitRows",
    "SplitCols",
    "PageTurn3D",
}; 

//由CCShaky3D派生出一个动画演示。
class Shaky3DDemo : public CCShaky3D 
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
		 //调用基类相应函数创建一个具体的动画演示。
        return CCShaky3D::create(5, false, ccg(15,10), t);
    }
};
//由CCWaves3D派生出一个动画演示。
class Waves3DDemo : public CCWaves3D 
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        //调用基类相应函数创建一个具体的动画演示。
        return CCWaves3D::create(5, 40, ccg(15,10), t);
    }
};
//由CCFlipX3D派生出一个动画演示。
class FlipX3DDemo : public CCFlipX3D 
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCFlipX3D* flipx  = CCFlipX3D::create(t);
        CCActionInterval* flipx_back = flipx->reverse();
        CCDelayTime* delay = CCDelayTime::create(2);
        //调用基类相应函数创建一个具体的动画演示。
        return (CCActionInterval*)(CCSequence::create(flipx, delay, flipx_back, NULL));
    }
};
//由CCFlipY3D派生出一个动画演示。
class FlipY3DDemo : public CCFlipY3D 
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCFlipY3D* flipy  = CCFlipY3D::create(t);
        CCActionInterval* flipy_back = flipy->reverse();
        CCDelayTime* delay = CCDelayTime::create(2);
        //调用基类相应函数创建一个具体的动画演示。
        return (CCActionInterval*)(CCSequence::create(flipy, delay, flipy_back, NULL));
    }
};
//由CCLens3D派生出一个动画演示。
class Lens3DDemo : public CCLens3D 
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCSize size = CCDirector::sharedDirector()->getWinSize();
        //调用基类相应函数创建一个具体的动画演示。
        return CCLens3D::create(CCPointMake(size.width/2,size.height/2), 240, ccg(15,10), t); 
    }
};

//由CCRipple3D派生出一个动画演示。
class Ripple3DDemo : public CCRipple3D 
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCSize size = CCDirector::sharedDirector()->getWinSize();
        //调用基类相应函数创建一个具体的动画演示。
        return CCRipple3D::create(CCPointMake(size.width/2,size.height/2), 240, 4, 160, ccg(32,24), t);
    }
};

//由CCLiquid派生出一个动画演示。
class LiquidDemo : public CCLiquid
{
public:
     //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        //调用基类相应函数创建一个具体的动画演示。
        return CCLiquid::create(4, 20, ccg(16,12), t); 
    }
};

//由CCWaves派生出一个动画演示。
class WavesDemo : public CCWaves 
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {//调用基类相应函数创建一个具体的动画演示。
        return CCWaves::create(4, 20, true, true, ccg(16,12), t);  
    }
};

//由CCTwirl派生出一个动画演示。
class TwirlDemo : public CCTwirl 
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {//调用基类相应函数创建一个具体的动画演示。
        CCSize size = CCDirector::sharedDirector()->getWinSize();
        return CCTwirl::create(CCPointMake(size.width/2, size.height/2), 1, 2.5f, ccg(12,8), t); 
    }
};

//由CCShakyTiles3D派生出一个动画演示。
class ShakyTiles3DDemo : public CCShakyTiles3D
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {//调用基类相应函数创建一个具体的动画演示。
        return CCShakyTiles3D::create(5, false, ccg(16,12), t) ;
    }

};


//由CCShatteredTiles3D派生出一个动画演示。
class ShatteredTiles3DDemo : public CCShatteredTiles3D
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {//调用基类相应函数创建一个具体的动画演示。
        return CCShatteredTiles3D::create(5, false, ccg(16,12), t); 
    }
};

//由CCShuffleTiles派生出一个动画演示。
class ShuffleTilesDemo : public CCShuffleTiles
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCShuffleTiles* shuffle = CCShuffleTiles::create(25, ccg(16,12), t);
        CCActionInterval* shuffle_back = shuffle->reverse();
        CCDelayTime* delay = CCDelayTime::create(2);
//调用基类相应函数创建一个具体的动画演示。
        return (CCActionInterval*)(CCSequence::create(shuffle, delay, shuffle_back, NULL));
    }
};

//由CCFadeOutTRTiles派生出一个动画演示。
class FadeOutTRTilesDemo : public CCFadeOutTRTiles
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCFadeOutTRTiles* fadeout = CCFadeOutTRTiles::create(ccg(16,12), t);
        CCActionInterval* back = fadeout->reverse();
        CCDelayTime* delay = CCDelayTime::create(0.5f);
        //调用基类相应函数创建一个具体的动画演示。
        return (CCActionInterval*)(CCSequence::create(fadeout, delay, back, NULL));
    }
};

//由CCFadeOutBLTiles派生出一个动画演示。
class FadeOutBLTilesDemo : public CCFadeOutBLTiles
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCFadeOutBLTiles* fadeout = CCFadeOutBLTiles::create(ccg(16,12), t);
        CCActionInterval* back = fadeout->reverse();
        CCDelayTime* delay = CCDelayTime::create(0.5f);
         //调用基类相应函数创建一个具体的动画演示。
        return (CCActionInterval*)(CCSequence::create(fadeout, delay, back, NULL));
    }
};

//由CCFadeOutUpTiles派生出一个动画演示。
class FadeOutUpTilesDemo : public CCFadeOutUpTiles
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCFadeOutUpTiles* fadeout = CCFadeOutUpTiles::create(ccg(16,12), t);
        CCActionInterval* back = fadeout->reverse();
        CCDelayTime* delay = CCDelayTime::create(0.5f);
        //调用基类相应函数创建一个具体的动画演示。
        return (CCActionInterval*)(CCSequence::create(fadeout, delay, back, NULL));
    }
};

//由CCFadeOutDownTiles派生出一个动画演示。
class FadeOutDownTilesDemo : public CCFadeOutDownTiles
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCFadeOutDownTiles* fadeout = CCFadeOutDownTiles::create(ccg(16,12), t);
        CCActionInterval* back = fadeout->reverse();
        CCDelayTime* delay = CCDelayTime::create(0.5f);
        //调用基类相应函数创建一个具体的动画演示。
        return (CCActionInterval*)(CCSequence::create(fadeout, delay, back, NULL));
    }
};

//由CCTurnOffTiles派生出一个动画演示。
class TurnOffTilesDemo : public CCTurnOffTiles
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCTurnOffTiles* fadeout = CCTurnOffTiles::create(25, ccg(48,32) , t);
        CCActionInterval* back = fadeout->reverse();
        CCDelayTime* delay = CCDelayTime::create(0.5f);
       //调用基类相应函数创建一个具体的动画演示。
        return (CCActionInterval*)(CCSequence::create(fadeout, delay, back, NULL));
    }
};

//由CCWavesTiles3D派生出一个动画演示。
class WavesTiles3DDemo : public CCWavesTiles3D
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {//调用基类相应函数创建一个具体的动画演示。
        return CCWavesTiles3D::create(4, 120, ccg(15,10), t); 
    }
};

//由CCJumpTiles3D派生出一个动画演示。
class JumpTiles3DDemo : public CCJumpTiles3D
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        CCSize size = CCDirector::sharedDirector()->getWinSize();
        //调用基类相应函数创建一个具体的动画演示。
        return CCJumpTiles3D::create(2, 30, ccg(15,10), t); 
    }
};

//由CCSplitRows派生出一个动画演示。
class SplitRowsDemo : public CCSplitRows
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        //调用基类相应函数创建一个具体的动画演示。
        return CCSplitRows::create(9, t); 
    }
};

//由CCSplitCols派生出一个动画演示。
class SplitColsDemo : public CCSplitCols
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        //调用基类相应函数创建一个具体的动画演示。
        return CCSplitCols::create(9, t); 
    }
};

//由CCPageTurn3D派生出一个动画演示。
class PageTurn3DDemo : public CCPageTurn3D
{
public:
    //重载其创建函数。
    static CCActionInterval* create(float t)
    {
        //调用基类相应函数创建一个具体的动画演示。
        CCDirector::sharedDirector()->setDepthTest(true);
        return CCPageTurn3D::create(ccg(15,10), t); 
    }
};

#define MAX_LAYER    22

//创建相应的效果。
CCActionInterval* createEffect(int nIndex, float t)
{
    //设置
    CCDirector::sharedDirector()->setDepthTest(false);
    //根据索引来创建相应的动画实例。
    switch(nIndex)
    {
        case 0: return Shaky3DDemo::create(t);
        case 1: return Waves3DDemo::create(t);
        case 2: return FlipX3DDemo::create(t);
        case 3: return FlipY3DDemo::create(t);
        case 4: return Lens3DDemo::create(t);
        case 5: return Ripple3DDemo::create(t);
        case 6: return LiquidDemo::create(t);
        case 7: return WavesDemo::create(t);
        case 8: return TwirlDemo::create(t);
        case 9: return ShakyTiles3DDemo::create(t);
        case 10: return ShatteredTiles3DDemo::create(t);
        case 11: return ShuffleTilesDemo::create(t);
        case 12: return FadeOutTRTilesDemo::create(t);
        case 13: return FadeOutBLTilesDemo::create(t);
        case 14: return FadeOutUpTilesDemo::create(t);
        case 15: return FadeOutDownTilesDemo::create(t);
        case 16: return TurnOffTilesDemo::create(t);
        case 17: return WavesTiles3DDemo::create(t);
        case 18: return JumpTiles3DDemo::create(t);
        case 19: return SplitRowsDemo::create(t);
        case 20: return SplitColsDemo::create(t);
        case 21: return PageTurn3DDemo::create(t);
    }

    return NULL;
}

//取得相应的动画。
CCActionInterval* getAction()
{
    CCActionInterval* pEffect = createEffect(actionIdx, 3);

    return pEffect;
} 

//运行当前的场景。
void EffectTestScene::runThisTest()
{
    //创建一个当前的动画演示层放入场景,并运行这个场景。
    addChild(TextLayer::create());
    CCDirector::sharedDirector()->replaceScene(this);
}

#define SID_RESTART        1
//构造函数。
TextLayer::TextLayer(void)
{
    //调用基类LayerColor的初始化函数,设置当前层的背景色。
    initWithColor( ccc4(32,128,32,255) );
    //
    float x,y;
    //取得屏幕大小。
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    x = s.width;
    y = s.height;
    //创建一个节点。
    CCNode* node = CCNode::create();
    //创建一个动画。
    CCActionInterval* effect = getAction();
    //将动画绑定到这个节点上。
    node->runAction(effect);
    //将这个节点再放入到当前层中。
    addChild(node, 0, kTagBackground);
    //创建第一个精灵做为背景。
    CCSprite *bg = CCSprite::create(s_back3);
    node->addChild(bg, 0);
//  bg->setAnchorPoint( CCPointZero );
    bg->setPosition(ccp(s.width/2, s.height/2));
    //创建第二个精灵(女一号)。
    CCSprite* grossini = CCSprite::create(s_pPathSister2);
    node->addChild(grossini, 1);
    grossini->setPosition( CCPointMake(x/3,y/2) );
    //创建一个缩放动画及对应的反向动画。
    CCActionInterval* sc = CCScaleBy::create(2, 5);
    CCActionInterval* sc_back = sc->reverse();
    //让第二个精灵运行相应的动画序列。 grossini->runAction( CCRepeatForever::create((CCActionInterval*)(CCSequence::create(sc, sc_back, NULL)) ) );
    //创建第三个精灵。(女二号)
    CCSprite* tamara = CCSprite::create(s_pPathSister1);
    node->addChild(tamara, 1);
tamara->setPosition( CCPointMake(2*x/3,y/2) );
//创建一个缩放动画及对应的反向动画。
    CCActionInterval* sc2 = CCScaleBy::create(2, 5);
    CCActionInterval* sc2_back = sc2->reverse();
    //让第三个精灵运行相应的动画序列。tamara->runAction( CCRepeatForever::create((CCActionInterval*)(CCSequence::create(sc2, sc2_back, NULL))) );
    //创建一个文字标签。
    CCLabelTTF* label = CCLabelTTF::create((effectsList[actionIdx]).c_str(), "Marker Felt", 32);
    //设置标签的位置并放入当前层中。
    label->setPosition( CCPointMake(x/2,y-80) );
    addChild(label);
    label->setTag( kTagLabel );
    //创建三个菜单按钮分别代表运行上一个,重新运行当前动画,运行下一个动画。
    CCMenuItemImage *item1 = CCMenuItemImage::create(s_pPathB1, s_pPathB2, this, menu_selector(TextLayer::backCallback) );
    CCMenuItemImage *item2 = CCMenuItemImage::create(s_pPathR1, s_pPathR2, this, menu_selector(TextLayer::restartCallback) );
    CCMenuItemImage *item3 = CCMenuItemImage::create(s_pPathF1, s_pPathF2, this, menu_selector(TextLayer::nextCallback) );
    //由三个菜单按钮创建菜单。
    CCMenu *menu = CCMenu::create(item1, item2, item3, NULL);
    //设置相应菜单按钮的位置。
    menu->setPosition(CCPointZero);
    item1->setPosition(CCPointMake( s.width/2 - item2->getContentSize().width*2, item2->getContentSize().height/2));
    item2->setPosition(CCPointMake( s.width/2, item2->getContentSize().height/2));
    item3->setPosition(CCPointMake( s.width/2 + item2->getContentSize().width*2, item2->getContentSize().height/2));
    //将菜单加入当前层中。
    addChild(menu, 1);    
    //对当前层调用一个函数。
    schedule( schedule_selector(TextLayer::checkAnim) );
}

//检查动画。
void TextLayer::checkAnim(float dt)
{
    //取得对应结点。
CCNode* s2 = getChildByTag(kTagBackground);
//判断如果没有正在运行中的动画,并且其有格子数据,则将其格子数据释放并置空。
    if ( s2->numberOfRunningActions() == 0 && s2->getGrid() != NULL)
        s2->setGrid(NULL);;
}

//析构。
TextLayer::~TextLayer(void)
{
}

//创建一个当前层的函数。
TextLayer* TextLayer::create()
{
    TextLayer* pLayer = new TextLayer();
    pLayer->autorelease();
    
    return pLayer;
}
//当前层被加载时的处理。
void TextLayer::onEnter()
{
    CCLayer::onEnter();
}
//创建一个新场景。
void TextLayer::newScene()
{
    CCScene* s = new EffectTestScene();
    CCNode* child = TextLayer::create();
    s->addChild(child);
    CCDirector::sharedDirector()->replaceScene(s);
    s->release();
}
//重启当前动画演示。
void TextLayer::restartCallback(CCObject* pSender)
{
    newScene();
}
//前进到下一个动画演示。
void TextLayer::nextCallback(CCObject* pSender)
{
    // update the action index
    actionIdx++;
    actionIdx = actionIdx % MAX_LAYER;

    newScene();
}
//回退到上一个动画演示。
void TextLayer::backCallback(CCObject* pSender)
{
    // update the action index
    actionIdx--;
    int total = MAX_LAYER;
    if( actionIdx < 0 )
        actionIdx += total;    

    newScene();
} 

 最后做个总结:

 

     Cocos2d-x提供了屏幕画面上的一些基于网格的动画,首先将要渲染的画面输出到一张纹理上,然后跟据屏幕大小创建相应数量的网格,通过对于网格上的顶点进行改变,形成顶点的运动动画,然后将纹理贴在网格上再绘制出来,就能够出现很多屏幕特效了。

 

     觉得怎么样?是不是恍然大悟呢?如果有这样的感觉,则我的辛苦就没有白费。

     最后,祝大家元旦快乐!2013年新的一年有更大的飞跃!

分类: cocos2d, cocos2d-x 标签:

cocos2d mac application how to add splash screen when launching (Default.png)

2012年12月26日 没有评论

i am migrating my iOS app onto mac. the loading time is a bit long (around 5 seconds) thus i need a splash loading screen (Just like Default.png image for iOS) but the project made from cocos2d template just shows a white screen. not sure about other apps. so is there anyway to set it?

I know that the screen size is not fixed on a mac app. but i have set a default size. and use auto scale in case of full screen mode.

EDIT:

I have tried a light weight loading scene as well but failed since the MainScene itself is light weight as well. I think the major loading time is due to the cocos2d environment set up.

In OS X a window appears when the application launches, it’s not designed to use splash screens.You might want to reconsider that choice.

But if the window is still to slow to load or to display its contents, you can still do that but manually, it isn’t easy like in iOS.You need to display another view inside the window until it loads.

EDIT

A little more of context: for example you can set in your xib file an image view containing the image do display.
Then you make start another thread that loads all the content that you need.After this, run a selector on the main thread that updates the window.

Based on my tests in Cocos2d 1.0.1 & 2.0 the basic Cocos2d OS X app launches really quickly.

This makes it seem pretty likely that it’s something about your first scene that is taking a long time to load, or something else. Instruments can help you gather information about what your app is doing.

I suggest you make an initial lightweight cocos2d scene that will load quickly at startup and then load your second scene and transition to it. Ideally the loading of the assets for your second scene would be asynchronous (at least the ones that are slow). There are numerous blog posts on how to do this. (search for “cocos2d asynchronous loading” and you’ll find many, such as this one: How to preload your game assets in a loading scene, though something more recent might be preferable).

分类: cocos2d, stackoverflow精选 标签:

cocos2d-x内存管理机制解析(二)

2012年12月19日 没有评论

转自:http://blog.csdn.net/a7833756/article/details/7632199


前一篇我们讲到cocos2d-x里的内存管理机制,以及引擎中的自动内存管理机制。一个被自动管理的对象从new出来之后到被放到autoreleasepool那么接下来,对象是如何被引擎自动delete掉的呢?首先我们要知道,cocos2d-x的引擎线程是单线程的,它不停的调用voidCCDisplayLinkDirector::mainLoop(void)来绘制当前的Scene ,同时对一些自动释放的对象进行管理。我们先到一个cocos2d-x项目的main()函数里面:

cocos2d-x内存管理机制解析(二)

这里调用了一个run()方法,我们跟踪进去:

cocos2d-x内存管理机制解析(二)

Run方法有个while(1)循环,不断的调用mainLoop(void)方法,来完成界面渲染和对象释放,我们进mainLoop():

cocos2d-x内存管理机制解析(二)

于是我们看到了引擎对自动管理的对象进行释放的操作。它调用的,是CCPoolManager的pop()方法,我们去看看这个pop()方法:

cocos2d-x内存管理机制解析(二)

如代码里面所示,m_pReleasePoolStack就是之前提到的当前内存池,也就是内存池管理者里面那个内存池堆栈的栈顶的那个内存池,对其进行clear()操作,记住,在clear()之前,被放置在自动管理池内的对象的引用次数都是为1的(依然只考虑对象被new出来之后马上autorelease()操作并且在其他地方不进行retain()),那么进行clear()操作时:

cocos2d-x内存管理机制解析(二)

CCAutoreleasePool会做这样两件事情,首先会把池中所有对象的被管理状态置为false,表示对象已经不再处于自动管理状态,然后清除管理池中所有的对象引用:

cocos2d-x内存管理机制解析(二)

在这一过程中,会调用每个对象的release()方法,这样,我们算一下,之前对象的引用次数为1,那么在这里进行一次release之后,引用为0,就会执行delete操作,这样一来,这个被管理的对象就被成功释放掉了。

下面我们来写个小demo验证一下这个过程:

New一个对象:

cocos2d-x内存管理机制解析(二)

s的引用次数为1,被管理状态为false:

cocos2d-x内存管理机制解析(二)

对其进行autorelease()

cocos2d-x内存管理机制解析(二)

s的引用依然为1,被管理状态为true:

cocos2d-x内存管理机制解析(二)

然后进行一次retain()操作:

cocos2d-x内存管理机制解析(二)

引用变为2

cocos2d-x内存管理机制解析(二)

接下来刷下一帧,刷完后我们再看o对象,发现其被管理状态变为false,引用变成1了,这说明如果我们之前没有手动执行过retain(),这个对象已经被引擎给回收掉了。

cocos2d-x内存管理机制解析(二)

这样一来,验证了引擎的自动回收机制,我们可以在retain()后面release()一次,来看看对象o被delete后的状态:

cocos2d-x内存管理机制解析(二)

发现其内部的数据都变成随机数值了,也就是对象已经被清除了。

 

最后我来做个简单的总结

Cocos2d-x中,采用引用计数的方式进行内存管理,谁需要引用这个对象,就对其retain()一次,同时在不需要它的时候,就要对其进行release()操作,这一点在引擎很多地方有示例,例如CCNode进行addchild()操作时,会对child进行retain()表示对其引用:

cocos2d-x内存管理机制解析(二)

而在removeChild()的时候会对其进行release()操作

cocos2d-x内存管理机制解析(二)

第二点是对象的autorelease()操作,该操作的效果是对象在当前这一帧被new出来之后,在下一帧之前没有被执行retain()(例如被add到某个CCMutableArray,或者被一个父Node作为子节点,也可以是我们手动retain()),那么这个对象在下一帧就会被引擎给delete掉,那么有时候出现的空指针错误,可能就来源于此。还有的时候,是在自己手动retain()后放入autorelease池,这样引擎只能将对象的引用减一,而不能delete掉,从而造成内存泄露。最后说一下,本人也是刚开始学习c++和cocos2d-x,写这篇博客与大家分享一下自己的心得,也是希望能帮到一部分对cocos2d内存管理有困惑的朋友,让大家能共同学习进步,同时对我所讲到的不合理的地方,希望各位大牛能够指出,感谢阅读!

分类: 未分类 标签:

cocos2d-x内存管理机制解析(一)

2012年12月19日 没有评论

转自:http://blog.csdn.net/a7833756/article/details/7628328


前言:c++内存机制,采用new关键字实例化的对象,必须在不使用的时候手动delete掉,否则new的时候开辟的内存就不能被回收,造成内存泄露。

我们来举个例子说明一下:

cocos2d-x内存管理机制解析(一)   cocos2d-x内存管理机制解析(一)

  运行 结果,vld工具提示了存在内存泄露:

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

当加上delete操作后:

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

下面步入正题:

1、cocos2d-x 内存管理的方式,cocos2d-x采用引用计数的方式进行内存管理,当一个对象的引用计数为0的时候,就会被引擎自动delete掉。

所有cocos2d-x里面的类都继承ccobject类(应该是吧、),下面看ccobject类源码:

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

这里 m_uReference 就是引用计数,在对象构造的时候,m_uReference置为1

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

然后每次对对象进行retain操作,reference+1

cocos2d-x内存管理机制解析(一)

    cocos2d-x内存管理机制解析(一)

每次对对象进行release操作,reference-1,如果reference在这次release之后变为0,那么delete掉它

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

2、以上是内存管理的基本原则,下面来讲引擎中是怎么对对象进行自动管理(autorelease)的。

我们以一个CCNode的生命历程为例,来讲一下自动管理的整个过程:

首先创建一个CCNode:

 cocos2d-x内存管理机制解析(一)cocos2d-x内存管理机制解析(一)

CCNode对象被new出来之后,立刻执行autorelease操作,我们来进行跟踪:cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

可以看到,首先将m_bManaged置为true,表示处于自动管理状态,然后加入自动管理池,继续跟踪:

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

getCurReleasePool() 返回一个 CCAutoreleasePool 对象指针,也就是一个自动释放池,那么我们先去看看这个自动释放池里面有什么:

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

首先就是一个ccobject数组,m_pManagedObjectArray , 这个数组放的就是接受自动释放的对象,也就是说,进行autorelease的对象,最终被放到它里面去了cocos2d-x内存管理机制解析(一)cocos2d-x内存管理机制解析(一)

那我们注意一下这里,m_pManagedObjectArray 是一个 CCMutableArray 对象,它的addobject()方法除了把一个对象放到这个array里面去,还做了什么呢,我们来看看源码:

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

大家应该看到了,进行了一次retain()操作,使得对象的引用+1,那么对象在被add到这个array里之后,引用应该为2(不考虑其他地方进行的retain),所以在此之后立刻进行了一次release(),使得这次add造成的引用取消,这样一来,对象从创建开始引用为1,到现在被放进自动释放池中后,引用依然为1,同时,被管理状态为true。

那么我再进行深入的分析一下

  getCurReleasePool()->addObject(pObject);cocos2d-x内存管理机制解析(一)

  里面的getCurReleasePool()方法,注意这个方法是 CCPoolManager 的方法:

cocos2d-x内存管理机制解析(一)

cocos2d-x内存管理机制解析(一)

那么我看到 CCPoolManager 类,顾名思义,我们也想得到它是对自动释放池进行管理的类,这是个全局变量,在main()函数执行之前由系统自动调用其默认构造方法进行实例化。下面进入这个类去看看里面有些什么:

 cocos2d-x内存管理机制解析(一)cocos2d-x内存管理机制解析(一)

 我们发现了,里面有一个 CCAutoreleasePool 对象 m_pCurReleasePool, 看它名字, 可以理解为 当前自动释放池 ,然后有一个内存池的数组 m_pReleasePoolStack ,里面放的就是多个内存释放池了(我好像就看到一个进去了)。那么我们连上刚才的思路,进去看看push()函数,做了什么事情:

 cocos2d-x内存管理机制解析(一)cocos2d-x内存管理机制解析(一)

如代码所示,push()操作new了一个自动释放池对象,并且将它赋值给 当前自动释放池(m_pCurReleasePool),然后将这个new的自动释放池对象放到CCPoolManager 里面的 释放池数组中。注意过程中对其引用计数的控制,自动释放池本身也是继承ccobject的,也有自己的引用计数,受相同的内存管理方式。

那么到这里,一个对象的autorelease()过程就完成了。


那么我来做一个简单的总结:

首先 new 一个对象, 然后执行其autorelease()方法,接下来是得到CCPoolManager 对象(这是一个全局的对象),用它的getCurReleasePool获取 当前自动释放池对象,并将这个new的对象放入 当前自动释放池对象 里面的m_pManagedObjectArray数组中,修改其被管理状态 m_bManaged 为 true。执行完这个完整的操作之后,这个新new出来的对象的引用次数为1,被管理状态为true,并且被放在一个管理对象的数组中。

先理解自动释放池的添加过程,并且搞清楚对象被添加前后之间的变化,然后下一篇,来讲被自动管理的对象是如何被引擎自动删除的。

分类: cocos2d, cocos2d-x 标签:

Cocos2d-x 2.0 变速动画深入分析

2012年12月14日 没有评论

[Cocos2d-x相关教程来源于红孩儿的游戏编程之路CSDN博客地址:http://blog.csdn.net/honghaier]

红孩儿Cocos2d-X学习园地QQ2群:44208467 加群写:Cocos2d-x 
红孩儿Cocos2d-X学习园地QQ群:249941957 [暂满]加群写:Cocos2d-x 

本章为我的Cocos2d-x教程一书初稿。望各位看官多提建议!

Cocos2d-x 2.0变速动画深入分析

另:本章所用Cocos2d-x版本为:

cocos2d-2.0-x-2.0.2 @ Aug 30 2012

http://cn.cocos2d-x.org/download

       变速动画都是由时间动画所衍生出来的,它是通过对一个匀速动画的进度进行调节来实现的,所以你要运行一个变速动画,首先要给他指定一个匀速动画,播放这个变速动画,它也播放被指定的匀速动画,在变速动画的更新函数中对被指定的匀速动画通过一个变速曲线计算得到相应的播放进度,变速动画停止播放时,被指定的匀速动画也必须被停止。所以,变速动画其实就是一个控制器,用来控制一个匀速动画的播放进度,使其产生变速的效果。

      为了讲述好本节,我专门写了一个曲线生成工具,这样可以更直观的看到变速曲线的形态。有兴趣的可以到我的群里下载这个工具。

      打开CActionEase.h:


#ifndef __ACTION_CCEASE_ACTION_H__
#define __ACTION_CCEASE_ACTION_H__

#include "CCActionInterval.h"
//使用Cocos2d命名空间
NS_CC_BEGIN
//要用到以下两个类
class CCObject;
class CCZone;

//所有变速动画的基类。
class CC_DLL CCActionEase : public CCActionInterval
{
public:
	//析构
    virtual ~CCActionEase(void);

    //初始化动画,参数为一个匀速时间动画。
    bool initWithAction(CCActionInterval *pAction);
	//产生一个当前实例的拷贝。
  virtual CCObject* copyWithZone(CCZone* pZone);
  //指定演示当前动画的演员。
  virtual void startWithTarget(CCNode *pTarget);
  //停止当前动画。
  virtual void stop(void);
  //更新动画。
  virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);

public:
    //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCActionEase* actionWithAction(CCActionInterval *pAction);

    //同上
    static CCActionEase* create(CCActionInterval *pAction);

protected:
	//保存对应的匀速动画。
    CCActionInterval *m_pOther;
};

对应CPP:

//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCActionEase* CCActionEase::actionWithAction(CCActionInterval *pAction)
{
    return CCActionEase::create(pAction);
}
//同上
CCActionEase* CCActionEase::create(CCActionInterval *pAction)
{
  //使用new创建一个当前类实例.
    CCActionEase *pRet = new CCActionEase();
    if (pRet)
   {
     //初始化.
        if (pRet->initWithAction(pAction))
        {
   //交由内存管理器进行释放管理.
            pRet->autorelease();
        }
        else
        {
   //如果初始化失败,则直接释放
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }
  //返回创建的实例.
    return pRet;
}
//初始化.
bool CCActionEase::initWithAction(CCActionInterval *pAction)
{
  //有效性判断.
    CCAssert(pAction != NULL, "");
  //先调用基类的初始化函数.
    if (CCActionInterval::initWithDuration(pAction->getDuration()))
   {
     //如果成功保存参数动画,本着"占用就加1"的原则,对其引用计数加一.
        m_pOther = pAction;
        pAction->retain();

        return true;
    }

    return false;
}
//产生一个当前类的实例拷贝.
CCObject* CCActionEase::copyWithZone(CCZone *pZone)
{
  //
    CCZone* pNewZone = NULL;
    CCActionEase* pCopy = NULL;
    //判断参数有效以及其内部已经有创建好的拷贝。
  if(pZone && pZone->m_pCopyObject) 
    {
        //直接强转后返回这个创建好的拷贝。
        pCopy = (CCActionEase*)(pZone->m_pCopyObject);
    }
    else
   {
     //如果无效,新创建一个当前类实例,并创建一个用于拷贝的类实例,将当前类实例设为拷贝类实例的内部拷贝,其实就是建立一个通用的拷贝对象,它内部有一个万物基类CCObject的指针,用来保存各个派生类的实例对象。
        pCopy = new CCActionEase();
        pZone = pNewZone = new CCZone(pCopy);
    }
  //先调用基类的相应函数对其进行基类属性的相关初始化,这个函数会一层层调用当前类基类直至CCAction的相应函数。
    CCActionInterval::copyWithZone(pZone);
  //使用保存的匀速动画来初始化拷贝实例。
    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    //释放通用的拷贝对象。
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//析构
CCActionEase::~CCActionEase(void)
{
  //释放占用的匀速动画实例。
    CC_SAFE_RELEASE(m_pOther);
}

//指定演示当前动画的演员。
void CCActionEase::startWithTarget(CCNode *pTarget)
{
  //调用基类的相应函数。
   CCActionInterval::startWithTarget(pTarget);
   //设定匀速动画的演员。
    m_pOther->startWithTarget(m_pTarget);
}
//停止当前动画。
void CCActionEase::stop(void)
{
  //让匀速动画停止播放。
   m_pOther->stop();
   //调用基类的相应函数停止当前动画。
    CCActionInterval::stop();
}
//更新动画。
void CCActionEase::update(float time)
{
  //更新匀速动画。
    m_pOther->update(time);
}
//创建一个反向播放的变速动画。
CCActionInterval* CCActionEase::reverse(void)
{
  //通过创建一个反向播放的匀速动画做为参数来创建相应的变速动画。
    return CCActionEase::create(m_pOther->reverse());
}

       上面只是一个基类,它并未真正的提供速度的变化调节,下面还有一个基类,提供了一个速度调节系数值。

//可以设定速度的变速动画基类。
class CC_DLL CCEaseRateAction : public CCActionEase
{
public:
	//析构函数。
    virtual ~CCEaseRateAction(void);

    //设置速度调节系数。
    inline void setRate(float rate) { m_fRate = rate; }
    //取得速度调节系数。
    inline float getRate(void) { return m_fRate; }

    //初始化当前动画。
    bool initWithAction(CCActionInterval *pAction, float fRate);
	//创建一个当前动画的实例拷贝。
   virtual CCObject* copyWithZone(CCZone* pZone);
   //创建一个反向播放的当前动画。
    virtual CCActionInterval* reverse(void);

public:
    //静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为速度。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseRateAction* actionWithAction(CCActionInterval* pAction, float fRate);

   //同上。
    static CCEaseRateAction* create(CCActionInterval* pAction, float fRate);

protected:
	//保存速度调节系数值。
    float m_fRate;
};

CPP实现:

 //静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为速度。内部调用create实现。
CCEaseRateAction* CCEaseRateAction::actionWithAction(CCActionInterval *pAction, float fRate)
{
    return CCEaseRateAction::create(pAction, fRate);
}
//同上。
CCEaseRateAction* CCEaseRateAction::create(CCActionInterval *pAction, float fRate)
{
  //先创建相应的变速动画。
    CCEaseRateAction *pRet = new CCEaseRateAction();
    if (pRet)
   {
     //如果成功,进行初始化后交由内存管理器处理。
        if (pRet->initWithAction(pAction, fRate))
        {
            pRet->autorelease();
        }
        else
        {
  //如果失败,释放并置空。
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet;
}

//初始化函数。
bool CCEaseRateAction::initWithAction(CCActionInterval *pAction, float fRate)
{
  //调用基类的初始化处理。
    if (CCActionEase::initWithAction(pAction))
   {
     //保存速度。
        m_fRate = fRate;
        return true;
    }

    return false;
}

//产生一个当前类的实例拷贝。参见基类的解释。
CCObject* CCEaseRateAction::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseRateAction* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseRateAction*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseRateAction();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval*)(m_pOther->copy()->autorelease()), m_fRate);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}

//析构
CCEaseRateAction::~CCEaseRateAction(void)
{
}
//创建一个反向播放的变速动画。
CCActionInterval* CCEaseRateAction::reverse(void)
{
    return CCEaseRateAction::create(m_pOther->reverse(), 1 / m_fRate);
}

       第二个类有了速度属性,但这个速度属性并未对动画起任何作用。后面的类由这个带速度属性的动画基类派生,真正实现相应的变速效果。

//由快变慢的变速动画。
class CC_DLL CCEaseIn : public CCEaseRateAction
{
public:
	//更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);
public:
   //静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为速度。内部调用create实现。
     CC_DEPRECATED_ATTRIBUTE static CCEaseIn* actionWithAction(CCActionInterval* pAction, float fRate);

     //同上。
    static CCEaseIn* create(CCActionInterval* pAction, float fRate);
};

CPP:

//静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为速度。内部调用create实现。
CCEaseIn* CCEaseIn::actionWithAction(CCActionInterval *pAction, float fRate)
{
    return CCEaseIn::create(pAction, fRate);
}
//同上,参见CCEaseRateAction的create函数。
CCEaseIn* CCEaseIn::create(CCActionInterval *pAction, float fRate)
{
    CCEaseIn *pRet = new CCEaseIn();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, fRate))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet;
}
//产生一个当前类的实例的拷贝,参见CCEaseRateAction的相应函数。
CCObject* CCEaseIn::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseIn* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseIn*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseIn();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval*)(m_pOther->copy()->autorelease()), m_fRate);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCEaseIn::update(float time)
{
  //这里使用了一个浮点的m_fRate次方计算,time值在0~1间变化,但使用powf(time,m_fRate)会在第一象限生成一个曲线。
   m_pOther->update(powf(time, m_fRate));
   //后面的图把m_fRate在0.1到10之间的曲线表现出来,其中X方向代表的是time,也就是进度,系数值就是m_fRate,红色线代表了powf(time,m_fRate)函数。大家可以看到,在m_fRate小于1时函数是先很短时间内达到接近1之后的增速越来越慢,大于1时函数是开始基本都不递增,到后面增速加快,最后非常快。
}

//创建一个反向播放的变速动画。
CCActionInterval*   CCEaseIn::reverse(void)
{
       return       CCEaseIn::create(m_pOther->reverse(),m_fRate);
}

Cocos2d-x 2.0 变速动画深入分析

//由慢变快的变速动画,与上个类基个相同,只是在更新函数中速度值不同。
class CC_DLL CCEaseOut : public CCEaseRateAction
{
public:
   //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseOut* actionWithAction(CCActionInterval* pAction, float fRate);

     //同上。
    static CCEaseOut* create(CCActionInterval* pAction, float fRate);
};

CPP:

//静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为速度。内部调用create实现。
CCEaseOut* CCEaseOut::actionWithAction(CCActionInterval *pAction, float fRate)
{
    return CCEaseOut::create(pAction, fRate);
}
//同上。
CCEaseOut* CCEaseOut::create(CCActionInterval *pAction, float fRate)
{
    CCEaseOut *pRet = new CCEaseOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, fRate))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet;   
}
//产生一个当前类的实例拷贝
CCObject* CCEaseOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval*)(m_pOther->copy()->autorelease()), m_fRate);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新函数。
void CCEaseOut::update(float time)
{
  //本动画与上面的动画相似。我也给出曲线图:
    m_pOther->update(powf(time, 1 / m_fRate));
}
//创建一个反向播放的变速动画。
CCActionInterval* CCEaseOut::reverse()
{
    return CCEaseOut::create(m_pOther->reverse(), 1 / m_fRate);
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseInOut : public CCEaseRateAction
{
public:
   //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
  //静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为速度。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseInOut* actionWithAction(CCActionInterval* pAction, float fRate);

     //同上。
    static CCEaseInOut* create(CCActionInterval* pAction, float fRate);
};
//静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为速度。内部调用create实现。
CCEaseInOut* CCEaseInOut::actionWithAction(CCActionInterval *pAction, float fRate)
{
    return CCEaseInOut::create(pAction, fRate);
}
//同上
CCEaseInOut* CCEaseInOut::create(CCActionInterval *pAction, float fRate)
{
    CCEaseInOut *pRet = new CCEaseInOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, fRate))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前类的实例拷贝。
CCObject* CCEaseInOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseInOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseInOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseInOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval*)(m_pOther->copy()->autorelease()), m_fRate);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}

//更新动画的函数。
void CCEaseInOut::update(float time)
{
  //这个曲线稍复杂,继续上图
    time *= 2;
    if (time < 1)
    {
        m_pOther->update(0.5f * powf(time, m_fRate));
    }
    else
    {
        m_pOther->update(1.0f - 0.5f * powf(2-time, m_fRate));
    }
}
//创建一个反向播放的变速动画。
CCActionInterval* CCEaseInOut::reverse(void)
{
    return CCEaseInOut::create(m_pOther->reverse(), m_fRate);
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseExponentialIn : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
    //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseExponentialIn* actionWithAction(CCActionInterval* pAction);
     //同上。
    static CCEaseExponentialIn* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseExponentialIn* CCEaseExponentialIn::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseExponentialIn::create(pAction);
}
//同上。
CCEaseExponentialIn* CCEaseExponentialIn::create(CCActionInterval* pAction)
{
    CCEaseExponentialIn *pRet = new CCEaseExponentialIn();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet;    
}
//创建一个当前类的实例拷贝。
CCObject* CCEaseExponentialIn::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseExponentialIn* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseExponentialIn*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseExponentialIn();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}

//更新动画。
void CCEaseExponentialIn::update(float time)
{
  //不废话,上曲线,此曲线没有系数。是固定曲线。
    m_pOther->update(time == 0 ? 0 : powf(2, 10 * (time/1 - 1)) - 1 * 0.001f);
}

//创建一个反向播放的变速动画。
CCActionInterval* CCEaseExponentialIn::reverse(void)
{
    return CCEaseExponentialOut::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseExponentialOut : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseExponentialOut* actionWithAction(CCActionInterval* pAction);
     //同上。
    static CCEaseExponentialOut* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseExponentialOut* CCEaseExponentialOut::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseExponentialOut::create(pAction);
}
 //同上。
CCEaseExponentialOut* CCEaseExponentialOut::create(CCActionInterval* pAction)
{
    CCEaseExponentialOut *pRet = new CCEaseExponentialOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseExponentialOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseExponentialOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseExponentialOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseExponentialOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新函数。
void CCEaseExponentialOut::update(float time)
{
  //上曲线说明,此曲线没有系数。是固定曲线。
  
    m_pOther->update(time == 1 ? 1 : (-powf(2, -10 * time / 1) + 1));
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseExponentialOut::reverse(void)
{
    return CCEaseExponentialIn::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseExponentialInOut : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);
public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseExponentialInOut* actionWithAction(CCActionInterval* pAction);

   //同上。
    static CCEaseExponentialInOut* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseExponentialInOut* CCEaseExponentialInOut::actionWithAction(CCActionInterval *pAction)
{
    return CCEaseExponentialInOut::create(pAction);
}
//同上。
CCEaseExponentialInOut* CCEaseExponentialInOut::create(CCActionInterval *pAction)
{
    CCEaseExponentialInOut *pRet = new CCEaseExponentialInOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseExponentialInOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseExponentialInOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseExponentialInOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseExponentialInOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//动画更新。
void CCEaseExponentialInOut::update(float time)
{
  //上曲线,没有系数,固定曲线
  
    time /= 0.5f;
    if (time < 1)
    {
        time = 0.5f * powf(2, 10 * (time - 1));
    }
    else
    {
        time = 0.5f * (-powf(2, -10 * (time - 1)) + 2);
    }

    m_pOther->update(time);
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseExponentialInOut::reverse()
{
    return CCEaseExponentialInOut::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

//cos曲线方式变化的变速动画。
class CC_DLL CCEaseSineIn : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseSineIn* actionWithAction(CCActionInterval* pAction);
    //同上
    static CCEaseSineIn* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseSineIn* CCEaseSineIn::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseSineIn::create(pAction);
}
//同上
CCEaseSineIn* CCEaseSineIn::create(CCActionInterval* pAction)
{
    CCEaseSineIn *pRet = new CCEaseSineIn();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseSineIn::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseSineIn* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject)
    {
        //in case of being called at sub class
        pCopy = (CCEaseSineIn*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseSineIn();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新
void CCEaseSineIn::update(float time)
{	//上曲线图,无需参数,固定曲线:
  
    m_pOther->update(-1 * cosf(time * (float)M_PI_2) + 1);
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseSineIn::reverse(void)
{
    return CCEaseSineOut::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

//sin曲线方式变化的变速动画。
class CC_DLL CCEaseSineOut : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseSineOut* actionWithAction(CCActionInterval* pAction);
    //同上
    static CCEaseSineOut* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseSineOut* CCEaseSineOut::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseSineOut::create(pAction);
}
//同上
CCEaseSineOut* CCEaseSineOut::create(CCActionInterval* pAction)
{
    CCEaseSineOut *pRet = new CCEaseSineOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseSineOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseSineOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseSineOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseSineOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新
void CCEaseSineOut::update(float time)
{
  //上图说明:
  
    m_pOther->update(sinf(time * (float)M_PI_2));
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseSineOut::reverse(void)
{
    return CCEaseSineIn::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

//另种cos曲线方式变化的变速动画。
class CC_DLL CCEaseSineInOut : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseSineInOut* actionWithAction(CCActionInterval* pAction);
   //同上
    static CCEaseSineInOut* create(CCActionInterval* pAction);
};

//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseSineInOut* CCEaseSineInOut::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseSineInOut::create(pAction);
}
//同上
CCEaseSineInOut* CCEaseSineInOut::create(CCActionInterval* pAction)
{
    CCEaseSineInOut *pRet = new CCEaseSineInOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseSineInOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseSineInOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseSineInOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseSineInOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新函数。
void CCEaseSineInOut::update(float time)
{
  //上曲线说明:
    m_pOther->update(-0.5f * (cosf((float)M_PI * time) - 1));
}

//创建一个反向播放的当前动画。
CCActionInterval* CCEaseSineInOut::reverse()
{
    return CCEaseSineInOut::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

//一个基类,用于衍生后面的变速动画。
class CC_DLL CCEaseElastic : public CCActionEase
{
public:
    //取得系数
    inline float getPeriod(void) { return m_fPeriod; }
   //设置系数
    inline void setPeriod(float fPeriod) { m_fPeriod = fPeriod; }

    //初始化函数。
    bool initWithAction(CCActionInterval *pAction, float fPeriod = 0.3f);
  //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   
  //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
    //静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为系数。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseElastic* actionWithAction(CCActionInterval *pAction, float fPeriod = 0.3f);
    //同上
    static CCEaseElastic* create(CCActionInterval *pAction, float fPeriod = 0.3f);
protected:
   //曲线系数。
    float m_fPeriod;
};

//静态函数:创建对应匀速动画的变速动画,参数一为一个匀速动画。参数二为系数。内部调用create实现。
CCEaseElastic* CCEaseElastic::actionWithAction(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    return CCEaseElastic::create(pAction, fPeriod);
}
 //同上
CCEaseElastic* CCEaseElastic::create(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    CCEaseElastic *pRet = new CCEaseElastic();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, fPeriod))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//初始化函数。
bool CCEaseElastic::initWithAction(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    if (CCActionEase::initWithAction(pAction))
   {
     //保存曲线系数。
        m_fPeriod = fPeriod;
        return true;
    }

    return false;
}
  
//创建一个当前动画的实例拷贝。
CCObject* CCEaseElastic::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseElastic* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseElastic*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseElastic();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()), m_fPeriod);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseElastic::reverse(void)
{
    CCAssert(0, "Override me");

    return NULL;
}

//上面基类衍生的新类。
class CC_DLL CCEaseElasticIn : public CCEaseElastic
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,第一参数为一个匀速动画。第二参数为曲线系数,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseElasticIn* actionWithAction(CCActionInterval *pAction, float fPeriod = 0.3f);
    //同上。
    static CCEaseElasticIn* create(CCActionInterval *pAction, float fPeriod = 0.3f);
};

//静态函数:创建对应匀速动画的变速动画,第一参数为一个匀速动画。第二参数为曲线系数,内部调用create实现。
CCEaseElasticIn* CCEaseElasticIn::actionWithAction(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    return CCEaseElasticIn::create(pAction, fPeriod);
}
 //同上。
CCEaseElasticIn* CCEaseElasticIn::create(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    CCEaseElasticIn *pRet = new CCEaseElasticIn();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, fPeriod))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseElasticIn::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseElasticIn* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseElasticIn*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseElasticIn();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()), m_fPeriod);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCEaseElasticIn::update(float time)
{
  //比较复杂,上图说明在不同的系数时的曲线结果:
  
    float newT = 0;
    if (time == 0 || time == 1)
    {
        newT = time;
    }
    else
    {
        float s = m_fPeriod / 4;
        time = time - 1;
        newT = -powf(2, 10 * time) * sinf((time - s) * M_PI_X_2 / m_fPeriod);
    }

    m_pOther->update(newT);
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseElasticIn::reverse(void)
{
    return CCEaseElasticOut::create(m_pOther->reverse(), m_fPeriod);
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseElasticOut : public CCEaseElastic
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,第一参数为一个匀速动画。第二参数为曲线系数,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseElasticOut* actionWithAction(CCActionInterval *pAction, float fPeriod = 0.3f);

    //同上
    static CCEaseElasticOut* create(CCActionInterval *pAction, float fPeriod = 0.3f);
};
   //静态函数:创建对应匀速动画的变速动画,第一参数为一个匀速动画。第二参数为曲线系数,内部调用create实现。

CCEaseElasticOut* CCEaseElasticOut::actionWithAction(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    return CCEaseElasticOut::create(pAction, fPeriod);
}
//同上
CCEaseElasticOut* CCEaseElasticOut::create(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    CCEaseElasticOut *pRet = new CCEaseElasticOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, fPeriod))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject *CCEaseElasticOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseElasticOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseElasticOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseElasticOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()), m_fPeriod);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCEaseElasticOut::update(float time)
{
  //继续上曲线说明:
  
    float newT = 0;
    if (time == 0 || time == 1)
    {
        newT = time;
    }
    else
    {
        float s = m_fPeriod / 4;
        newT = powf(2, -10 * time) * sinf((time - s) * M_PI_X_2 / m_fPeriod) + 1;
    }

    m_pOther->update(newT);
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseElasticOut::reverse(void)
{
    return CCEaseElasticIn::create(m_pOther->reverse(), m_fPeriod);
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseElasticInOut : public CCEaseElastic
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,第一参数为一个匀速动画。第二参数为曲线系数,内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseElasticInOut* actionWithAction(CCActionInterval *pAction, float fPeriod = 0.3f);

    //同上
    static CCEaseElasticInOut* create(CCActionInterval *pAction, float fPeriod = 0.3f);
};
//静态函数:创建对应匀速动画的变速动画,第一参数为一个匀速动画。第二参数为曲线系数,内部调用create实现。
CCEaseElasticInOut* CCEaseElasticInOut::actionWithAction(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    return CCEaseElasticInOut::create(pAction, fPeriod);
}
//同上
CCEaseElasticInOut* CCEaseElasticInOut::create(CCActionInterval *pAction, float fPeriod/* = 0.3f*/)
{
    CCEaseElasticInOut *pRet = new CCEaseElasticInOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction, fPeriod))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseElasticInOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseElasticInOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseElasticInOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseElasticInOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()), m_fPeriod);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;

}
//更新动画。
void CCEaseElasticInOut::update(float time)
{
  //挺复杂的曲线:
  
    float newT = 0;
    if (time == 0 || time == 1)
    {
        newT = time;
    }
    else
    {
        time = time * 2;
        if (! m_fPeriod)
        {
            m_fPeriod = 0.3f * 1.5f;
        }

        float s = m_fPeriod / 4;

        time = time - 1;
        if (time < 0)
        {
            newT = -0.5f * powf(2, 10 * time) * sinf((time -s) * M_PI_X_2 / m_fPeriod);
        }
        else
        {
            newT = powf(2, -10 * time) * sinf((time - s) * M_PI_X_2 / m_fPeriod) * 0.5f + 1;
        }
    }

    m_pOther->update(newT);
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseElasticInOut::reverse(void)
{
    return CCEaseElasticInOut::create(m_pOther->reverse(), m_fPeriod);
}

Cocos2d-x 2.0 变速动画深入分析

//又是一个变速动画的基类,用于衍生一些复杂的变速曲线。
class CC_DLL CCEaseBounce : public CCActionEase
{
public:
  //计算曲线处理
   float bounceTime(float time);
   //产生一个当前类的实例拷贝。
   virtual CCObject* copyWithZone(CCZone* pZone);
   //创建一个反向播放的当前动画
    virtual CCActionInterval* reverse();

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseBounce* actionWithAction(CCActionInterval* pAction);
    //同上。
    static CCEaseBounce* create(CCActionInterval* pAction);
};
   
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseBounce* CCEaseBounce::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseBounce::create(pAction);
}
//同上。
CCEaseBounce* CCEaseBounce::create(CCActionInterval* pAction)
{
    CCEaseBounce *pRet = new CCEaseBounce();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//产生一个当前类的实例拷贝。
CCObject* CCEaseBounce::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseBounce* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseBounce*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseBounce();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//计算曲线处理
float CCEaseBounce::bounceTime(float time)
{
  //复杂曲线说明:
  
    if (time < 1 / 2.75)
    {
        return 7.5625f * time * time;
    } else 
    if (time < 2 / 2.75)
    {
        time -= 1.5f / 2.75f;
        return 7.5625f * time * time + 0.75f;
    } else
    if(time < 2.5 / 2.75)
    {
        time -= 2.25f / 2.75f;
        return 7.5625f * time * time + 0.9375f;
    }

    time -= 2.625f / 2.75f;
    return 7.5625f * time * time + 0.984375f;
}
//创建一个反向播放的当前动画
CCActionInterval* CCEaseBounce::reverse()
{
    return CCEaseBounce::create(m_pOther->reverse());
}

//上面类的衍生类。
class CC_DLL CCEaseBounceIn : public CCEaseBounce
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseBounceIn* actionWithAction(CCActionInterval* pAction);
    //同上。
    static CCEaseBounceIn* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseBounceIn* CCEaseBounceIn::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseBounceIn::create(pAction);
}
//同上。
CCEaseBounceIn* CCEaseBounceIn::create(CCActionInterval* pAction)
{
    CCEaseBounceIn *pRet = new CCEaseBounceIn();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseBounceIn::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseBounceIn* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseBounceIn*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseBounceIn();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画。
void CCEaseBounceIn::update(float time)
{
  //先计算出变速曲线的结果然后做为进度值设置给匀速动画。
  //曲线未设系数,为固定曲线。
  
    float newT = 1 - bounceTime(1 - time);
    m_pOther->update(newT);
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseBounceIn::reverse(void)
{
    return CCEaseBounceOut::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseBounceOut : public CCEaseBounce
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseBounceOut* actionWithAction(CCActionInterval* pAction);
    //同上
    static CCEaseBounceOut* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseBounceOut* CCEaseBounceOut::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseBounceOut::create(pAction);
}
//同上
CCEaseBounceOut* CCEaseBounceOut::create(CCActionInterval* pAction)
{
    CCEaseBounceOut *pRet = new CCEaseBounceOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseBounceOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseBounceOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject)
    {
        //in case of being called at sub class
        pCopy = (CCEaseBounceOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseBounceOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画
void CCEaseBounceOut::update(float time)
{
  //曲线说明:
  //曲线未设系数,为固定曲线。
  
    float newT = bounceTime(time);
    m_pOther->update(newT);
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseBounceOut::reverse(void)
{
    return CCEaseBounceIn::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseBounceInOut : public CCEaseBounce
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseBounceInOut* actionWithAction(CCActionInterval* pAction);
    //同上
    static CCEaseBounceInOut* create(CCActionInterval* pAction);
};
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseBounceInOut* CCEaseBounceInOut::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseBounceInOut::create(pAction);
}
//同上
CCEaseBounceInOut* CCEaseBounceInOut::create(CCActionInterval* pAction)
{
    CCEaseBounceInOut *pRet = new CCEaseBounceInOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet; 
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseBounceInOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseBounceInOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseBounceInOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseBounceInOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//动画更新
void CCEaseBounceInOut::update(float time)
{
  //曲线说明:
  
    float newT = 0;
    if (time < 0.5f)
    {
        time = time * 2;
        newT = (1 - bounceTime(1 - time)) * 0.5f;
    }
    else
    {
        newT = bounceTime(time * 2 - 1) * 0.5f + 0.5f;
    }

    m_pOther->update(newT);
}
//创建一个反向播放的当前动画。

CCActionInterval* CCEaseBounceInOut::reverse()
{
    return CCEaseBounceInOut::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseBackIn : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseBackIn* actionWithAction(CCActionInterval* pAction);
    //同上
    static CCEaseBackIn* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseBackIn* CCEaseBackIn::actionWithAction(CCActionInterval *pAction)
{
    return CCEaseBackIn::create(pAction);
}
//同上
CCEaseBackIn* CCEaseBackIn::create(CCActionInterval *pAction)
{
    CCEaseBackIn *pRet = new CCEaseBackIn();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet;
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseBackIn::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseBackIn* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseBackIn*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseBackIn();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画.
void CCEaseBackIn::update(float time)
{
  //菜花,上曲线!
  
    float overshoot = 1.70158f;
    m_pOther->update(time * time * ((overshoot + 1) * time - overshoot));
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseBackIn::reverse(void)
{
    return CCEaseBackOut::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseBackOut : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseBackOut* actionWithAction(CCActionInterval* pAction);
    //同上
    static CCEaseBackOut* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseBackOut* CCEaseBackOut::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseBackOut::create(pAction);
}
//同上
CCEaseBackOut* CCEaseBackOut::create(CCActionInterval* pAction)
{
    CCEaseBackOut *pRet = new CCEaseBackOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet;
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseBackOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseBackOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseBackOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseBackOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//更新动画.
void CCEaseBackOut::update(float time)
{
  //奶妈,上曲线!
  
    float overshoot = 1.70158f;

    time = time - 1;
    m_pOther->update(time * time * ((overshoot + 1) * time + overshoot) + 1);
}
//创建一个反向播放的当前动画。
CCActionInterval* CCEaseBackOut::reverse(void)
{
    return CCEaseBackIn::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

class CC_DLL CCEaseBackInOut : public CCActionEase
{
public:
    //更新动画。
   virtual void update(float time);
   //创建一个反向播放的当前动画。
   virtual CCActionInterval* reverse(void);
   //创建一个当前动画的实例拷贝。
    virtual CCObject* copyWithZone(CCZone* pZone);

public:
   //静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
    CC_DEPRECATED_ATTRIBUTE static CCEaseBackInOut* actionWithAction(CCActionInterval* pAction);
   //同上
    static CCEaseBackInOut* create(CCActionInterval* pAction);
};
//静态函数:创建对应匀速动画的变速动画,参数为一个匀速动画。内部调用create实现。
CCEaseBackInOut* CCEaseBackInOut::actionWithAction(CCActionInterval* pAction)
{
    return CCEaseBackInOut::create(pAction);
}
//同上
CCEaseBackInOut* CCEaseBackInOut::create(CCActionInterval* pAction)
{
    CCEaseBackInOut *pRet = new CCEaseBackInOut();
    if (pRet)
    {
        if (pRet->initWithAction(pAction))
        {
            pRet->autorelease();
        }
        else
        {
            CC_SAFE_RELEASE_NULL(pRet);
        }
    }

    return pRet;
}
//创建一个当前动画的实例拷贝。
CCObject* CCEaseBackInOut::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCEaseBackInOut* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCEaseBackInOut*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCEaseBackInOut();
        pNewZone = new CCZone(pCopy);
    }

    pCopy->initWithAction((CCActionInterval *)(m_pOther->copy()->autorelease()));
    
    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//动画更新
void CCEaseBackInOut::update(float time)
{
  //容嬷嬷,上曲线!
  
    float overshoot = 1.70158f * 1.525f;

    time = time * 2;
    if (time < 1)
    {
        m_pOther->update((time * time * ((overshoot + 1) * time - overshoot)) / 2);
    }
    else
    {
        time = time - 2;
        m_pOther->update((time * time * ((overshoot + 1) * time + overshoot)) / 2 + 1);
    }
}

//创建一个反向播放的当前动画。
CCActionInterval* CCEaseBackInOut::reverse()
{
    return CCEaseBackInOut::create(m_pOther->reverse());
}

Cocos2d-x 2.0 变速动画深入分析

     虽然大部分代码很无聊,但是我相信,时间久了,各位同学会发现,本博的代码仍是您在进行Cocos2d-x开发的超级帮助。最后,周末愉快!~

                          Cocos2d-x 2.0 变速动画深入分析

     

分类: cocos2d, cocos2d-x 标签:

Cocos2d-x2.0 进度动画 深入分析

2012年12月11日 没有评论


[Cocos2d-x相关教程来源于红孩儿的游戏编程之路CSDN博客地址:http://blog.csdn.net/honghaier]

红孩儿Cocos2d-X学习园地QQ2群:44208467 加群写:Cocos2d-x 
红孩儿Cocos2d-X学习园地QQ群:249941957 [暂满]加群写:Cocos2d-x 

本章为我的Cocos2d-x教程一书初稿。望各位看官多提建议!Cocos2d-x2.0 进度动画 深入分析

 Cocos2d-x2.0 进度动画深入分析

另:本章所用Cocos2d-x版本为:

cocos2d-2.0-x-2.0.2 @ Aug 30 2012

http://cn.cocos2d-x.org/download


          在Cocos2d-x 2.0中有一个工程例子叫"ActionsProgressTest",故明思义是进度动画的演示,应该说在几乎所有的RPG类游戏中我们都会看到进度条,所以进度动画的作用之大是无须我多言。我们本节就来学习一下Cocos2d-x 2.0的进度动画。

          首先,先把那个"ActionsProgressTest"放一边,我要做的不是让大家去知其然,而是要知其所以然。所以我们要学习一下进度动画的原理与实现,在此我们向大家介绍一下所要用到的三个关键功能类:

1.CCProgressTimer :  进度动画的渲染器,核心实现了进度动画的显示功能,本身是一个结点,通过渲染一个精灵来表现进度的变化。

2.CCProgressTo:    TO进度控制器,控制进度从当前进度变化到某个值.

3.CCProgressFromTo:   FromTo进度控制器,控制进度从一个指定值到另一个值的变化.


          咱们先来看一下CCProgressTimer,这个类是整个进度动画的重中之重。

打开CCProgressTimer .h:

#ifndef __MISC_NODE_CCPROGRESS_TIMER_H__
#define __MISC_NODE_CCPROGRESS_TIMER_H__
//使用精灵类
#include "sprite_nodes/CCSprite.h"
//使用Cocos2d命名空间
NS_CC_BEGIN

//定义一个枚举,代表两种不同的进度动画目标渲染类型。
typedef enum {
	///绕圆心转动的进度动画
	    kCCProgressTimerTypeRadial,
    ///条形的进度动画。
    kCCProgressTimerTypeBar,
} CCProgressTimerType;

//由CCNode和CCRGBAProtocol派生出CCProgressTimer类。
class CC_DLL CCProgressTimer : public CCNode, public CCRGBAProtocol
{
public:
	//构造函数。
	CCProgressTimer();
	//析构函数。
    ~CCProgressTimer(void);

    //取得当前的进度动画目标渲染类型
    inline CCProgressTimerType getType(void) { return m_eType; }

    //返回当前时刻的进度值。
    inline float getPercentage(void) {return m_fPercentage; }

	//取得当前进度动画所渲染的精灵。
	inline CCSprite* getSprite(void) { return m_pSprite; }

    //设置当前进度动画所渲染的精灵,并初始化动画。
    bool initWithSprite(CCSprite* sp);
	//设置当前时刻的进度值。
	void setPercentage(float fPercentage);
	//设置当前进度动画所渲染的精灵
	void setSprite(CCSprite *pSprite);
	//设置当前的进度动画目标渲染类型
	void setType(CCProgressTimerType type);
	//设置是否反向播放进度动画。
    void setReverseProgress(bool reverse);
	//渲染当前结点。
	virtual void draw(void);
	//设置锚点位置。
    void setAnchorPoint(CCPoint anchorPoint);
	//设置颜色。
	virtual void setColor(const ccColor3B& color);
	//取得颜色。
	virtual const ccColor3B& getColor(void);
	//取得透明度。
	virtual GLubyte getOpacity(void);
	//设置透明度。
	virtual void setOpacity(GLubyte opacity);
	//设置透明度是否按颜色值变动而变动。
	virtual void setOpacityModifyRGB(bool bValue);
	//取得透明度是否按颜色值变动而变动。
    virtual bool isOpacityModifyRGB(void);
    //取得是否是按反方向播放动画。
	inline bool isReverseDirection() { return m_bReverseDirection; };
	//设置是否按反方向播放动画。
    inline void setReverseDirection(bool value) { m_bReverseDirection = value; };

public:
    //静态函数,创建一个进度时间控制器,内部调用create实现.
    CC_DEPRECATED_ATTRIBUTE static CCProgressTimer* progressWithSprite(CCSprite* sp);
    //同上.
    static CCProgressTimer* create(CCSprite* sp);
protected:
	//由一个二维插值参数值计算出纹理坐标U,V。
	ccTex2F textureCoordFromAlphaPoint(CCPoint alpha);
	//由一个二维插值参数值计算出顶点坐标X,Y。
    ccVertex2F vertexFromAlphaPoint(CCPoint alpha);
    //更新进度
	void updateProgress(void);
	//更新条形进度的状态
	void updateBar(void);
	//更新绕圆心转动的状态
	void updateRadial(void);
	//更新颜色
	void updateColor(void);
	//
    CCPoint boundaryTexCoord(char index);

protected:
	//进度动画目标渲染类型
	CCProgressTimerType m_eType;
	//当前的进度值
    float m_fPercentage;
    //所渲染的精灵.
	CCSprite *m_pSprite;
	//顶点数量
	int m_nVertexDataCount;
	//顶点数据指针。
    ccV2F_C4B_T2F *m_pVertexData;

	//这里是一个称为“中点”的成员变量值,但它的意义绝不是这么简单,如果是绕中心旋转的进度动画,它就是中心,如果是条形动画,它代表了UV随进度变化的起始位置,如果是在最左边,其值为(0,y),如果是在最右边,其值为(1,y),如果在最上面(x,0),如果在最下面(x,1);如果是在中心(0.5,0.5)。
	CC_PROPERTY(CCPoint, m_tMidpoint, Midpoint);
	
    //设里是一个表示动画方向的成员变量值,如果是横向方向,则设为(1,0),如果是纵向方向,则设为(0,1);
    CC_SYNTHESIZE(CCPoint, m_tBarChangeRate, BarChangeRate);
    //bool变量,代表是否反方向播放动画。
    bool m_bReverseDirection;
};

NS_CC_END

#endif 

再来看CPP文件:

#include "CCProgressTimer.h"

#include "ccMacros.h"
#include "textures/CCTextureCache.h"
#include "support/CCPointExtension.h"
#include "shaders/CCGLProgram.h"
#include "shaders/CCShaderCache.h"
#include "shaders/ccGLStateCache.h"
#include "CCDirector.h"
#include "support/TransformUtils.h"
#include "CCDrawingPrimitives.h"
// extern
#include "kazmath/GL/matrix.h"

#include <float.h>
//使用Cocos2d命名空间
NS_CC_BEGIN

//定义动画的四边形的四个角的纹理UV数量
#define kProgressTextureCoordsCount 4
// 将动画的四边形的四个角的纹理UV按位压缩到一个char中,从左下角{0,1}起,然后左上角{0,0},右上角{1,0},最后右下角{1,1},对应为0x4b,也就是01001011啊,貌似很方便,其实很坑爹。
const char kCCProgressTextureCoords = 0x4b;

//构造函数
CCProgressTimer::CCProgressTimer()
:m_eType(kCCProgressTimerTypeRadial)
,m_fPercentage(0.0f)
,m_pSprite(NULL)
,m_nVertexDataCount(0)
,m_pVertexData(NULL)
,m_tMidpoint(0,0)
,m_tBarChangeRate(0,0)
,m_bReverseDirection(false)
{}
//静态函数,创建一个进度时间控制器,内部调用create实现.CCProgressTimer* CCProgressTimer::progressWithSprite(CCSprite* sp)
{
    return CCProgressTimer::create(sp);
}
//同上
CCProgressTimer* CCProgressTimer::create(CCSprite* sp)
{
	//先用new创建一个CCProgressTimer 实例对象。
	CCProgressTimer *pProgressTimer = new CCProgressTimer();
	//对其进行初始化,这里应该先做一个有效性判断。
    if (pProgressTimer->initWithSprite(sp))
	{
	//交由内存管理器进行释放。
        pProgressTimer->autorelease();
    }
    else
	{
	//如果初始化失败,删除实例并置空。
        delete pProgressTimer;
        pProgressTimer = NULL;
    }        
	//返回新创建的CCProgressTimer 实例对象指针。
    return pProgressTimer;
}

//初始化。
bool CCProgressTimer::initWithSprite(CCSprite* sp)
{
	//设置当前进度为0
	setPercentage(0.0f);
	//设置顶点BUF的指针为空,顶点数量为0,。
    m_pVertexData = NULL;
    m_nVertexDataCount = 0;
	//设置锚点。
	setAnchorPoint(ccp(0.5f,0.5f));
	//设置动画形式为绕圆心旋转。
	m_eType = kCCProgressTimerTypeRadial;
	//正方向播放动画。
	m_bReverseDirection = false;
	//设置圆心位置。
	setMidpoint(ccp(0.5f, 0.5f));
	//
	setBarChangeRate(ccp(1,1));
	//设置渲染的精灵。
    setSprite(sp);
    
 	// 设置使用的Shader代码片段.动画的效果由Shader来渲染。
setShaderProgram(CCShaderCache::sharedShaderCache()->programForKey(kCCShader_PositionTextureColor));
    return true;
}
//析构函数。
CCProgressTimer::~CCProgressTimer(void)
{
	//释放顶点BUF,并对所占用的精灵进行引用计数减1操作。
    CC_SAFE_FREE(m_pVertexData);
    CC_SAFE_RELEASE(m_pSprite);
}
//设置当前的进度值。
void CCProgressTimer::setPercentage(float fPercentage)
{
	//如果进度值有更新。
    if (m_fPercentage != fPercentage)
	{
	//先将进度值限定在0~100间,然后更新进度。
        m_fPercentage = clampf(fPercentage, 0, 100);
        updateProgress();
    }
}
//设置演示当前动画的精灵。
void CCProgressTimer::setSprite(CCSprite *pSprite)
{
	//先做个判断,防止重复进行设置。
    if (m_pSprite != pSprite)
	{
	//占用新的精灵,对其引用计数器加1
        CC_SAFE_RETAIN(pSprite);
	//释放老的精灵,对其引用计数器减1
        CC_SAFE_RELEASE(m_pSprite);
	   //将新的精灵设置为当前演示动画的精灵。
        m_pSprite = pSprite;
       //设置绘制当前精灵的区域大小
        setContentSize(m_pSprite->getContentSize());

        //  如果顶点BUF有值,
        if (m_pVertexData)
        {
	   //释放并置空
            CC_SAFE_FREE(m_pVertexData);
           //设置顶点数量为0
            m_nVertexDataCount = 0;
        }
    }        
}
//设置当前的进度动画目标渲染类型
void CCProgressTimer::setType(CCProgressTimerType type)
{
	//做个判断,避免重复设置。
    if (type != m_eType)
    {
      //  如果顶点BUF有值,
        if (m_pVertexData)
        { 		   //释放并置空
            CC_SAFE_FREE(m_pVertexData);
            m_pVertexData = NULL;
            //设置顶点数量为0
            m_nVertexDataCount = 0;
        }
        //设置进度动画目标渲染类型.
        m_eType = type;
    }
}
//设置是否按反方向播放动画。
void CCProgressTimer::setReverseProgress(bool reverse)
{
	//做个判断,避免重复设置。
    if( m_bReverseDirection != reverse ) {
        m_bReverseDirection = reverse;

       //如果顶点BUF有值,释放并置空并置顶点数量为0
        CC_SAFE_FREE(m_pVertexData);
        m_nVertexDataCount = 0;
    }
}
//设置颜色。
void CCProgressTimer::setColor(const ccColor3B& color)
{
	//对所控制的精灵进行设置颜色。
	m_pSprite->setColor(color);
	//更新颜色。
    updateColor();
}
//取得颜色。
const ccColor3B& CCProgressTimer::getColor(void)
{
	//由所控制的精灵取得颜色。
    return m_pSprite->getColor();
}
//设置透明度。
void CCProgressTimer::setOpacity(GLubyte opacity)
{
	//由所控制的精灵设置透明度。
	m_pSprite->setOpacity(opacity);
	//更新颜色。
    updateColor();
}
//取得透明度。
GLubyte CCProgressTimer::getOpacity(void)
{
	//由所控制的精灵取得透明度。
    return m_pSprite->getOpacity();
}
//设置透明度是否按颜色值变动而变动。
void CCProgressTimer::setOpacityModifyRGB(bool bValue)
{
    CC_UNUSED_PARAM(bValue);
}
//取得透明度是否按颜色值变动而变动。
bool CCProgressTimer::isOpacityModifyRGB(void)
{
    return false;
}

//根据一个二维插值参数值计算当前进度的纹理UV。
ccTex2F CCProgressTimer::textureCoordFromAlphaPoint(CCPoint alpha)
{
	//定义一个2维纹理坐标结构,初始化u,v为0,0
	ccTex2F ret = {0.0f, 0.0f};
	//如果没有操控的精灵,返回.
    if (!m_pSprite) {
        return ret;
    }
    //取得精灵的绘制四边形的顶点
	ccV3F_C4B_T2F_Quad quad = m_pSprite->getQuad();
	
	//左下角的纹理坐标存入min
	CCPoint min = ccp(quad.bl.texCoords.u,quad.bl.texCoords.v);
	//右上角的纹理坐标存入max
	CCPoint max = ccp(quad.tr.texCoords.u,quad.tr.texCoords.v);
	
    //如果精灵切换需要旋转90度,这里交换一下x,y值.
    if (m_pSprite->isTextureRectRotated()) {
        CC_SWAP(alpha.x, alpha.y, float);
	}
	//通过插值计算出对应的UV坐标位置存入一个ccTex2F 值返回.
    return tex2(min.x * (1.f - alpha.x) + max.x * alpha.x, min.y * (1.f - alpha.y) + max.y * alpha.y);
}
//根据一个二维插值参数值计算当前进度的顶点X,Y。
ccVertex2F CCProgressTimer::vertexFromAlphaPoint(CCPoint alpha)
{
	//定义一个2维顶点值,初始化x,y为0,0
	ccVertex2F ret = {0.0f, 0.0f};
	//如果没有操控的精灵,返回.
    if (!m_pSprite) {
        return ret;
	}
	//取得精灵的绘制四边形的顶点
	ccV3F_C4B_T2F_Quad quad = m_pSprite->getQuad();
	//左下角的位置存入min
	CCPoint min = ccp(quad.bl.vertices.x,quad.bl.vertices.y);
	//右上角的位置存入max
	CCPoint max = ccp(quad.tr.vertices.x,quad.tr.vertices.y);
	//通过插值计算出对应的顶点位置存入ret.
    ret.x = min.x * (1.f - alpha.x) + max.x * alpha.x;
    ret.y = min.y * (1.f - alpha.y) + max.y * alpha.y;
    return ret;
}
//更新颜色
void CCProgressTimer::updateColor(void)
{
	//如果没有操控的精灵,返回.
    if (!m_pSprite) {
        return;
    }
	//如果有顶点数据.
    if (m_pVertexData)
	{
	//取得左上角顶点的色彩存入临时色彩变量sc,然后遍历所有顶点设置为sc。
        ccColor4B sc = m_pSprite->getQuad().tl.colors;
        for (int i = 0; i < m_nVertexDataCount; ++i)
        {
            m_pVertexData[i].colors = sc;
        }            
    }
}
//更新进度。
void CCProgressTimer::updateProgress(void)
{
    switch (m_eType)
	{
	//绕圆心转动的进度动画。
	case kCCProgressTimerTypeRadial:
	//更新旋转
        updateRadial();
        break;
	//条形进度动画。
	case kCCProgressTimerTypeBar:
	//更新条形进度。
        updateBar();
        break;
    default:
        break;
    }
}
//设置锚点。
void CCProgressTimer::setAnchorPoint(CCPoint anchorPoint)
{
    CCNode::setAnchorPoint(anchorPoint);
}
//取得中点。
CCPoint CCProgressTimer::getMidpoint(void)
{
    return m_tMidpoint;
}
//设置中点。
void CCProgressTimer::setMidpoint(CCPoint midPoint)
{
    //将x,y限定到0~1间。
	m_tMidpoint = ccpClamp(midPoint, CCPointZero, ccp(1,1));
}

//绕中心旋转的进度动画的更新
void CCProgressTimer::updateRadial(void)
{
	//如果没有操控的精灵直接返回。
    if (!m_pSprite) {
        return;
	}
	//将进度值计算成百分比.
    float alpha = m_fPercentage / 100.f;
	//根据百分比计算出旋转的角度.
    float angle = 2.f*((float)M_PI) * ( m_bReverseDirection ? alpha : 1.0f - alpha);

    //将顶点中间的位置存入topMid.
	CCPoint topMid = ccp(m_tMidpoint.x, 1.f);
	//将topMid绕m_tMidpoint旋转angle度,将结果存入percentagePt。
    CCPoint percentagePt = ccpRotateByAngle(topMid, m_tMidpoint, angle);

	//定义一个索引值
	int index = 0;
	//定义一个点存来存储由中心点向旋转位置发射线与精灵四边形边缘的碰撞位置点。
    CCPoint hit = CCPointZero;

    if (alpha == 0.f) {
        //如果百度百分比为0,则碰撞点在顶部中间位置,索引设为0。
        hit = topMid;
        index = 0;
    } else if (alpha == 1.f) {
        //如果百度百分比为1,则碰撞点也在顶部中间位置,索引设为4。

        hit = topMid;
        index = 4;
    } else {
	//运行一个循环来判断
        float min_t = FLT_MAX;
	//顺时针遍历所有的拐角顶点。
        for (int i = 0; i <= kProgressTextureCoordsCount; ++i) {
           
	   //取得顺时针方向的上一个四边形拐角点的索引。
            int pIndex = (i + (kProgressTextureCoordsCount - 1))%kProgressTextureCoordsCount;
	   // 取得当前索引对应的四边形拐角点的UV坐标。
            CCPoint edgePtA = boundaryTexCoord(i % kProgressTextureCoordsCount);
	//取得顺时针方向的上一个四边形拐角点的UV坐标。
            CCPoint edgePtB = boundaryTexCoord(pIndex);
	    //在循环中,以底部中点为分隔,做为起始和结束的时候对应的边缘段。
            if(i == 0)
           {
	  //底部中点至左下角为起始边缘段。
                edgePtB = ccpLerp(edgePtA, edgePtB, 1-m_tMidpoint.x);
            } 
            else if(i == 4)
            {
                //右下角至底部中点为结束边缘段。
                edgePtA = ccpLerp(edgePtA, edgePtB, 1-m_tMidpoint.x);
            }

            // 定义FLOAT临时变量s,t。
            // s用来存放中心点按旋转角度方向的直线与边缘直线相交时交点与中心点的距离。
            // t用来存放中心点按旋转角度方向的直线与边缘直线相交时交点与边缘段起点的距离。
            float s = 0, t = 0;
           //判断以中心点和旋转点percentagePt所在的直线与edgePtA,edgePtB所在的直线是否相交,如果相交,返回s和t。
            if(ccpLineIntersect(edgePtA, edgePtB, m_tMidpoint, percentagePt, &s, &t))
            {
                //如果有交点。
                if ((i == 0 || i == 4)) {
                    // 第一和最末次循环时s值的有效性判断。
                    if (!(0.f <= s && s <= 1.f)) {
                        continue;
                    }
                }
               //计录每次循环进行碰撞检测时,有效的最短t值和对应的循环索引。
                if (t >= 0.f) {
                    if (t < min_t) {
                        min_t = t;
                        index = i;
                    }
                }
            }
        }

        //   由min_t和方向计算出碰撞点存入hit。
        hit = ccpAdd(m_tMidpoint, ccpMult(ccpSub(percentagePt, m_tMidpoint),min_t));

    }


	// 根据碰撞点所在的拐角象限计算需要多少顶点来绘制,加3的意义是要加上中点,12点位置和碰撞点三个点。
	
    bool sameIndexCount = true;
	if(m_nVertexDataCount != index + 3){
	//如果顶点有变化,释放顶点缓冲。
        sameIndexCount = false;
        CC_SAFE_FREE(m_pVertexData);
        m_nVertexDataCount = 0;
    }

	//如果在上面的判断中释放了顶点缓冲,这里需要重建顶点缓冲。
    if(!m_pVertexData) {
        m_nVertexDataCount = index + 3;
        m_pVertexData = (ccV2F_C4B_T2F*)malloc(m_nVertexDataCount * sizeof(ccV2F_C4B_T2F));
        CCAssert( m_pVertexData, "CCProgressTimer. Not enough memory");
	}
	//更新顶点的颜色.
    updateColor();
	//设置顶点缓冲区的各顶点位置和纹理UV坐标。
    if (!sameIndexCount) {

        //设置中点位置和纹理UV坐标。
        m_pVertexData[0].texCoords = textureCoordFromAlphaPoint(m_tMidpoint);
        m_pVertexData[0].vertices = vertexFromAlphaPoint(m_tMidpoint);
	//12点位置和纹理UV坐标。
        m_pVertexData[1].texCoords = textureCoordFromAlphaPoint(topMid);
        m_pVertexData[1].vertices = vertexFromAlphaPoint(topMid);
	//当前时刻所要绘制的拐角点的位置和UV坐标.
        for(int i = 0; i < index; ++i){
            CCPoint alphaPoint = boundaryTexCoord(i);
            m_pVertexData[i+2].texCoords = textureCoordFromAlphaPoint(alphaPoint);
            m_pVertexData[i+2].vertices = vertexFromAlphaPoint(alphaPoint);
        }
    }

    //碰撞点的位置和UV坐标.
    m_pVertexData[m_nVertexDataCount - 1].texCoords = textureCoordFromAlphaPoint(hit);
    m_pVertexData[m_nVertexDataCount - 1].vertices = vertexFromAlphaPoint(hit);

}

//条形的进度动画的更新.
void CCProgressTimer::updateBar(void)
{
	//如果没有操控的精灵直接返回。
    if (!m_pSprite) {
        return;
	}
	//将进度值计算成百分比.
	float alpha = m_fPercentage / 100.0f;
	//根据百分比计算x,y方向上的偏移值.
	CCPoint alphaOffset = ccpMult(ccp(1.0f * (1.0f - m_tBarChangeRate.x) + alpha * m_tBarChangeRate.x, 1.0f * (1.0f - m_tBarChangeRate.y) + alpha * m_tBarChangeRate.y), 0.5f);
	//计算中点位置在受到偏移后的最小和最大值。
    CCPoint min = ccpSub(m_tMidpoint, alphaOffset);
	CCPoint max = ccpAdd(m_tMidpoint, alphaOffset);
	
	//将最小值和最大值取在有效范围内。
    if (min.x < 0.f) {
        max.x += -min.x;
        min.x = 0.f;
    }

    if (max.x > 1.f) {
        min.x -= max.x - 1.f;
        max.x = 1.f;
    }

    if (min.y < 0.f) {
        max.y += -min.y;
        min.y = 0.f;
    }

    if (max.y > 1.f) {
        min.y -= max.y - 1.f;
        max.y = 1.f;
    }

	//根据方向来设置相应的四边形的顶点数据。
	if (!m_bReverseDirection) {
	//如果正方向.
	//如果顶点缓冲为空,申请四个顶点的数据缓冲区。
        if(!m_pVertexData) {
            m_nVertexDataCount = 4;
            m_pVertexData = (ccV2F_C4B_T2F*)malloc(m_nVertexDataCount * sizeof(ccV2F_C4B_T2F));
            CCAssert( m_pVertexData, "CCProgressTimer. Not enough memory");
        }
        //左上角
        m_pVertexData[0].texCoords = textureCoordFromAlphaPoint(ccp(min.x,max.y));
        m_pVertexData[0].vertices = vertexFromAlphaPoint(ccp(min.x,max.y));

        //左下角
        m_pVertexData[1].texCoords = textureCoordFromAlphaPoint(ccp(min.x,min.y));
        m_pVertexData[1].vertices = vertexFromAlphaPoint(ccp(min.x,min.y));

        //右上角
        m_pVertexData[2].texCoords = textureCoordFromAlphaPoint(ccp(max.x,max.y));
        m_pVertexData[2].vertices = vertexFromAlphaPoint(ccp(max.x,max.y));

        //右下角
        m_pVertexData[3].texCoords = textureCoordFromAlphaPoint(ccp(max.x,min.y));
        m_pVertexData[3].vertices = vertexFromAlphaPoint(ccp(max.x,min.y));
	} 
	else 
	{
	//如果是反方向,这里用了8个顶点,以使能够正确显示相应的四边形。我个人感觉这段代码写的比较恶心,而且很难理解,在ActionsProgressTest中并没有相应的演示,我经过测试后发现它是为了当你设置m_bReverseDirection为true后如果方向不符无法正确显示而做的一个算法,以致在后面需要调用两次渲染才能确保渲染正确,个人感觉这一段应可以改造为更简单和通俗易懂的四个顶点的填充,所以深深的建议你略过这一段代码。
	
        if(!m_pVertexData) {
            m_nVertexDataCount = 8;
            m_pVertexData = (ccV2F_C4B_T2F*)malloc(m_nVertexDataCount * sizeof(ccV2F_C4B_T2F));
            CCAssert( m_pVertexData, "CCProgressTimer. Not enough memory");
            // 左上角
            m_pVertexData[0].texCoords = textureCoordFromAlphaPoint(ccp(0,1));
            m_pVertexData[0].vertices = vertexFromAlphaPoint(ccp(0,1));

            //左下角
            m_pVertexData[1].texCoords = textureCoordFromAlphaPoint(ccp(0,0));
            m_pVertexData[1].vertices = vertexFromAlphaPoint(ccp(0,0));

            //右上角
            m_pVertexData[6].texCoords = textureCoordFromAlphaPoint(ccp(1,1));
            m_pVertexData[6].vertices = vertexFromAlphaPoint(ccp(1,1));

            //右下角
            m_pVertexData[7].texCoords = textureCoordFromAlphaPoint(ccp(1,0));
            m_pVertexData[7].vertices = vertexFromAlphaPoint(ccp(1,0));
        }

        // 左上角2
        m_pVertexData[2].texCoords = textureCoordFromAlphaPoint(ccp(min.x,max.y));
        m_pVertexData[2].vertices = vertexFromAlphaPoint(ccp(min.x,max.y));

        //左下角2
        m_pVertexData[3].texCoords = textureCoordFromAlphaPoint(ccp(min.x,min.y));
        m_pVertexData[3].vertices = vertexFromAlphaPoint(ccp(min.x,min.y));

        // 右上角2
        m_pVertexData[4].texCoords = textureCoordFromAlphaPoint(ccp(max.x,max.y));
        m_pVertexData[4].vertices = vertexFromAlphaPoint(ccp(max.x,max.y));

        // 右下角2
        m_pVertexData[5].texCoords = textureCoordFromAlphaPoint(ccp(max.x,min.y));
        m_pVertexData[5].vertices = vertexFromAlphaPoint(ccp(max.x,min.y));
	}
	//更新颜色
    updateColor();
}

//根据索引取得相应对应四边形的四个角的纹理UV。
CCPoint CCProgressTimer::boundaryTexCoord(char index)
{
	//既然之前将四个角的UV都压缩到一个char中,这里就是通过位运算将其取出来的过程。
	if (index < kProgressTextureCoordsCount) {
//因为这四个角的UV值就是0或1,所以各占一位,并且四个角是顺时针顺序放入到char中的,这里通过索引参数稍做计算可以取得对应位的值。
	
        if (m_bReverseDirection) {
//如果是反方向,如何如何计算。
            return ccp((kCCProgressTextureCoords>>(7-(index<<1)))&1,(kCCProgressTextureCoords>>(7-((index<<1)+1)))&1);
        } else {
//如果是正方向,如何如何计算。
            return ccp((kCCProgressTextureCoords>>((index<<1)+1))&1,(kCCProgressTextureCoords>>(index<<1))&1);
        }
    }
    return CCPointZero;
}

//绘制
void CCProgressTimer::draw(void)
{
	//如果顶点数组为空或要绘制的精灵为空,直接返回.
    if( ! m_pVertexData || ! m_pSprite)
        return;
	//设置使用shader.
    CC_NODE_DRAW_SETUP();
	//设置精灵的混合状态.
    ccGLBlendFunc( m_pSprite->getBlendFunc().src, m_pSprite->getBlendFunc().dst );
	//设置顶点的格式.
    ccGLEnableVertexAttribs(kCCVertexAttribFlag_PosColorTex );
	//设置纹理
    ccGLBindTexture2D( m_pSprite->getTexture()->getName() );
	//设置渲染使用的顶点缓冲区中的数据结构格式.
	//数据结构首先是顶点信息.
	glVertexAttribPointer( kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, sizeof(m_pVertexData[0]) , &m_pVertexData[0].vertices);
	//然后是纹理坐标信息.
	glVertexAttribPointer( kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, sizeof(m_pVertexData[0]), &m_pVertexData[0].texCoords);
	//最后是色彩信息.
    glVertexAttribPointer( kCCVertexAttrib_Color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(m_pVertexData[0]), &m_pVertexData[0].colors);
	
	//如果是绕圆心旋转的进度动画,使用扇型方式进行三角形的绘制。
    if(m_eType == kCCProgressTimerTypeRadial)
    {
        glDrawArrays(GL_TRIANGLE_FAN, 0, m_nVertexDataCount);
    } 
    else if (m_eType == kCCProgressTimerTypeBar)
	{
	//如果是条形的进度动画,根据相应的方向进行三角形的绘制。
        if (!m_bReverseDirection) 
        {
	   //正方向只需要进行一次绘制。
            glDrawArrays(GL_TRIANGLE_STRIP, 0, m_nVertexDataCount);
        } 
        else 
        {
            //如果是反方向,需要进行两次绘制,这个原因嘛,就在前面那段8个顶点的BUF创建所决定,我在此建议Cocos2d-x的开发者重新考虑一下算法的修改,不行就干掉这个条形动画的反向处理,因为实际上是没什么用处的。
            glDrawArrays(GL_TRIANGLE_STRIP, 0, m_nVertexDataCount/2);
            glDrawArrays(GL_TRIANGLE_STRIP, 4, m_nVertexDataCount/2);
            // 渲染次数统计多增加一次渲染调用。
            CC_INCREMENT_GL_DRAWS(1);
        }
	}
	//渲染次数统计增加一次渲染调用。
    CC_INCREMENT_GL_DRAWS(1);
}

NS_CC_END

        我们看: CCProgressTimer 类实现了进度动画表现方案的核心算法处理,进度动画的更新和渲染都由它来完成,有了这个类,我们就可以根据进度值来绘制相应的绕圆心旋转或是条形的进度动画了。

        但具体进度的变化控制则是由 CCProgressTo 和 CCProgressFromTo 来完成的。我们接着来看一下,打开CCActionProgressTimer.h:

#ifndef __ACTION_CCPROGRESS_TIMER_H__
#define __ACTION_CCPROGRESS_TIMER_H__
//用到时间动画类.
#include "CCActionInterval.h"
//开始Cocos2d命名空间
NS_CC_BEGIN

//============= CCProgressTo ==============================
//由时间动画派生出进度动画,对进度进行从0到另一个值的变化控制.
class CC_DLL CCProgressTo : public CCActionInterval
{
public:
	//初始化进度动画,参数一为动画时长,参数二为目标百分比值。
    bool initWithDuration(float duration, float fPercent);
	//产生一个拷贝
	virtual CCObject* copyWithZone(CCZone *pZone);
	//设置演示当前动画的演员,启动动画。
	virtual void startWithTarget(CCNode *pTarget);
	//每帧更新动画的处理。
    virtual void update(float time);

public:
	    //静态函数,创建一个进度动画,内部调用create来实现,参一为动画时长,参二为结束进度值。

    CC_DEPRECATED_ATTRIBUTE static CCProgressTo* actionWithDuration(float duration, float fPercent);
	//同上
    static CCProgressTo* create(float duration, float fPercent);
protected:
	//起始进度值
	float m_fTo;
	//结束进度值
    float m_fFrom;
};

对应的CPP实现:

//定义一个宏
#define kProgressTimerCast CCProgressTimer*

// 静态函数,创建一个进度动画,内部调用create来实现。
CCProgressTo* CCProgressTo::actionWithDuration(float duration, float fPercent)
{
    return CCProgressTo::create(duration, fPercent);
}
//同上
CCProgressTo* CCProgressTo::create(float duration, float fPercent)
{
	//先new出一个进度动画。
	CCProgressTo *pProgressTo = new CCProgressTo();
	//初始化这个进度动画。
	pProgressTo->initWithDuration(duration, fPercent);
	//交由内存管理器进行释放管理。
    pProgressTo->autorelease();
	//返回创建的进度动画。
    return pProgressTo;
}
//初始化进度动画,参数一为动画时长,参数二为目标百分比值。
bool CCProgressTo::initWithDuration(float duration, float fPercent)
{
	//调用基类的初始化函数。
    if (CCActionInterval::initWithDuration(duration))
	{
	//保存目标进度值。
        m_fTo = fPercent;

        return true;
    }

    return false;
}

//产生一个拷贝,讲的太多,参看动画三板斧。
CCObject* CCProgressTo::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCProgressTo* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        pCopy = (CCProgressTo*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCProgressTo();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCActionInterval::copyWithZone(pZone);
    pCopy->initWithDuration(m_fDuration, m_fTo);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//设置演示当前动画的演员。
void CCProgressTo::startWithTarget(CCNode *pTarget)
{
	//调用基类的相应函数。
	CCActionInterval::startWithTarget(pTarget);
	//取得演示当前进度动画的渲染器中记录的进度百分比做为起始进度。
    m_fFrom = ((kProgressTimerCast)(pTarget))->getPercentage();
   //重置起始进度。
    if (m_fFrom == 100)
    {
        m_fFrom = 0;
    }
}

//每帧更新动画。
void CCProgressTo::update(float time)
{
	//根据时间计算出插值进度设置为目标演员的当前进度。
    ((kProgressTimerCast)(m_pTarget))->setPercentage(m_fFrom + (m_fTo - m_fFrom) * time);
}

CCProgressFromTo :

//由时间动画派生出进度动画,对进度进行从一个值到另一个值的变化控制.
class CC_DLL CCProgressFromTo : public CCActionInterval
{
public:
   
	//初始化进度动画,参数一为动画时长,参数二为目标百分比值。
    bool initWithDuration(float duration, float fFromPercentage, float fToPercentage);
	//产生一个拷贝
	virtual CCObject* copyWithZone(CCZone *pZone);
	//生成一个反向动画。
    virtual CCActionInterval* reverse(void);
	//设置演示当前动画的演员,启动动画。
	virtual void startWithTarget(CCNode *pTarget);
	//每帧更新动画的处理。
    virtual void update(float time);

public:
    
	//静态函数,创建一个进度动画,内部调用create来实现,参一为动画时长,参二为起始进度值,参三为结束进度值。
    CC_DEPRECATED_ATTRIBUTE static CCProgressFromTo* actionWithDuration(float duration, float fFromPercentage, float fToPercentage);
    //同上
    static CCProgressFromTo* create(float duration, float fFromPercentage, float fToPercentage);
protected:
	//进度进起值
	float m_fTo;
	//进度结束值
    float m_fFrom;
};

其对应的CPP实现:

//静态函数,创建一个进度动画,内部调用create来实现。
CCProgressFromTo* CCProgressFromTo::actionWithDuration(float duration, float fFromPercentage, float fToPercentage)
{
    return CCProgressFromTo::create(duration, fFromPercentage, fToPercentage);
}
//同上
CCProgressFromTo* CCProgressFromTo::create(float duration, float fFromPercentage, float fToPercentage)
{
    CCProgressFromTo *pProgressFromTo = new CCProgressFromTo();
    pProgressFromTo->initWithDuration(duration, fFromPercentage, fToPercentage);
    pProgressFromTo->autorelease();

    return pProgressFromTo;
}
//初始化。
bool CCProgressFromTo::initWithDuration(float duration, float fFromPercentage, float fToPercentage)
{
	//调用基类的初始化函数。保存进度动画的起止值。
    if (CCActionInterval::initWithDuration(duration))
    {
        m_fTo = fToPercentage;
        m_fFrom = fFromPercentage;

        return true;
    }

    return false;
}
//产生一个进度动画的拷贝。
CCObject* CCProgressFromTo::copyWithZone(CCZone *pZone)
{
    CCZone* pNewZone = NULL;
    CCProgressFromTo* pCopy = NULL;
    if(pZone && pZone->m_pCopyObject) 
    {
        //in case of being called at sub class
        pCopy = (CCProgressFromTo*)(pZone->m_pCopyObject);
    }
    else
    {
        pCopy = new CCProgressFromTo();
        pZone = pNewZone = new CCZone(pCopy);
    }

    CCActionInterval::copyWithZone(pZone);

    pCopy->initWithDuration(m_fDuration, m_fFrom, m_fTo);

    CC_SAFE_DELETE(pNewZone);
    return pCopy;
}
//产生一个反向的进度动画。
CCActionInterval* CCProgressFromTo::reverse(void)
{
	//这里只是交换了一下起止值就搞定了。
    return CCProgressFromTo::create(m_fDuration, m_fTo, m_fFrom);
}
//设置演示动画的目标。
void CCProgressFromTo::startWithTarget(CCNode *pTarget)
{
    CCActionInterval::startWithTarget(pTarget);
}
//更新进度动画
void CCProgressFromTo::update(float time)
{
	//通过时间插值来计算出当前的进度值。
    ((kProgressTimerCast)(m_pTarget))->setPercentage(m_fFrom + (m_fTo - m_fFrom) * time);
}

         现在我们知道了,当要实现一个进度动画时,我们使用CCProgressTimer 来设定相应的动画形式和操纵的精灵,使用CProgressToCCProgressFromTo来设定进度动画的进度变化形式.之后运行这个进度动画就可以了。

         这三个类的功能讲解可以使我们深入的理解进度动画的内部构成。我们现在来看一下具体的应用,打开

ActionsProgressTest.h

//为什么#ifndef 和#define 不一样,大坑啊~!各位注意改正。
#ifndef _ACTIONS__PROGRESS_TEST_H_
#define _ACTIONS_PROGRESS_TEST_H_

//测试工程的头文件,包含测试场景的定义
#include "../testBasic.h"

//这里定义一个精灵显示层,做为进度动画的显示主体。
class SpriteDemo : public CCLayer
{
public:
	//构造函数与析构函数
    SpriteDemo(void);
    ~SpriteDemo(void);
	//取得主标题,副标题
    virtual std::string title();
    virtual std::string subtitle();
	//重载当前层被加载时的处理函数。
    virtual void onEnter();
	//声明重启,下一个演示,上一个演示的回调函数。
    void restartCallback(CCObject* pSender);
    void nextCallback(CCObject* pSender);
    void backCallback(CCObject* pSender);
};

其对应的CPP实现:

//构造
SpriteDemo::SpriteDemo(void)
{
}
//析构
SpriteDemo::~SpriteDemo(void)
{
}
//取得主标题std::string SpriteDemo::title()
{
    return "ActionsProgressTest";
}

//取得副标题
std::string SpriteDemo::subtitle()
{
    return "";
}
//重载当前层被加载时的处理函数。
void SpriteDemo::onEnter()
{
	//调用基类的相应函数对CCLayer进行初始化。
    CCLayer::onEnter();
	//取得窗口的大小。
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//创建一个文字标签,显示标题,字体为Arial,字号为18。
    CCLabelTTF* label = CCLabelTTF::create(title().c_str(), "Arial", 18);
	//将文字标签放入当前层
    addChild(label, 1);
	//设置文字标签的位置
    label->setPosition( CCPointMake(s.width/2, s.height-50) );
	//取得幅标题
    std::string strSubtitle = subtitle();
    if( ! strSubtitle.empty() ) 
    {
		//如果副标题不为空,则创建副标题,字体为Thonburi,字号为22。
        CCLabelTTF* l = CCLabelTTF::create(strSubtitle.c_str(), "Thonburi", 22);
		//将副标题文字标签放入当前层
        addChild(l, 1);
		//设置副标题文字标签的位置	
        l->setPosition( CCPointMake(s.width/2, s.height-80) );
    }    
	//创建三个菜单按钮,用于用户选择控制动画的演示。
	//返回上一个演示。
    CCMenuItemImage *item1 = CCMenuItemImage::create(s_pPathB1, s_pPathB2, this, menu_selector(SpriteDemo::backCallback) );
	//重启当前演示。
    CCMenuItemImage *item2 = CCMenuItemImage::create(s_pPathR1, s_pPathR2, this, menu_selector(SpriteDemo::restartCallback) );
	//进行下一个演示。
    CCMenuItemImage *item3 = CCMenuItemImage::create(s_pPathF1, s_pPathF2, this, menu_selector(SpriteDemo::nextCallback) );
	//由这三个菜单按钮来创建一个菜单。
    CCMenu *menu = CCMenu::create(item1, item2, item3, NULL);
	//设置菜单的位置为左下角零点。
    menu->setPosition(CCPointZero);
	//设置三个菜单按钮相对于菜单的位置。
    item1->setPosition(CCPointMake( s.width/2 - item2->getContentSize().width*2, item2->getContentSize().height/2));
    item2->setPosition(CCPointMake( s.width/2, item2->getContentSize().height/2));
    item3->setPosition(CCPointMake( s.width/2 + item2->getContentSize().width*2, item2->getContentSize().height/2)); 
	//将菜单放入当前层。 
    addChild(menu, 1);    
	//设置一个填充为红色的层。
    CCLayerColor *background = CCLayerColor::create(ccc4(255,0,0,255));
	//将这个实体色填充的层放入当前层中做为背景层。
    addChild(background, -10);
}

//定义重启的回调函数。
void SpriteDemo::restartCallback(CCObject* pSender)
{
	//创建一个进度动画的场景实例
    CCScene* s = new ProgressActionsTestScene();
	//将新创建的当前的演示效果CCLayer放入这个场景。
    s->addChild(restartAction()); 
	//运行此场景
    CCDirector::sharedDirector()->replaceScene(s);
	//因新new的场景计数器为1,在交由设备运行时会再加1,这里完成场景的交接,故对其引用计数器减1。
    s->release();
}
//定义下一个演示的回调函数。
void SpriteDemo::nextCallback(CCObject* pSender)
{
	//创建一个进度动画的场景实例
    CCScene* s = new ProgressActionsTestScene();
	//将一个新的演示效果CCLayer放入这个场景。
    s->addChild( nextAction() );
	//运行此场景
    CCDirector::sharedDirector()->replaceScene(s);
	//完成场景的交接,对其引用计数器减1。
    s->release();
}
//定义上一个演示的回调函数。
void SpriteDemo::backCallback(CCObject* pSender)
{
    CCScene* s = new ProgressActionsTestScene();
    s->addChild( backAction() );
    CCDirector::sharedDirector()->replaceScene(s);
    s->release();
} 

        和动画三板斧演示中的ActionsDemo一样,这个类是为了演示进度动画而做的一个基类,后面的各种演示会由此类派生实现。

SpriteProgressToRadial:

//============================================================
//圆形进度动画:圆形进度动画是一个绕中心将精灵边缘扫描一圈在这个过程中消失的动画消果。

class SpriteProgressToRadial : public SpriteDemo
{
public:
	//重载当前层被加载时的处理函数。
    virtual void onEnter();
	//取得副标题
    virtual std::string subtitle();
};

对应的CPP实现:

//重载当前层被加载时的处理函数。
void SpriteProgressToRadial::onEnter()
{
	//基类的相应函数.
    SpriteDemo::onEnter();
    //取得窗口大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//创建两个进度动画的控制器.2秒进度值变化到100。
    CCProgressTo *to1 = CCProgressTo::create(2, 100);
    CCProgressTo *to2 = CCProgressTo::create(2, 100);
//创建一个进度动画的渲染器.使用女一号演员精灵来渲染。
	
	CCProgressTimer *left = CCProgressTimer::create(CCSprite::create(s_pPathSister1));
	//设置动画表现为绕圆心转动。
	left->setType( kCCProgressTimerTypeRadial );
	//将渲染器放入当前层.
	addChild(left);
	//设置渲染器的位置在屏幕左边
	left->setPosition(CCPointMake(100, s.height/2));
	//让它运行一个无限循环的进度动画,进度变化由控制器1来控制。
    left->runAction( CCRepeatForever::create(to1));
//创建另一个进度动画的渲染器.使用色块图精灵来渲染。
	
    CCProgressTimer *right = CCProgressTimer::create(CCSprite::create(s_pPathBlock));
    right->setType(kCCProgressTimerTypeRadial);
    // 设置逆时针旋转。
	right->setReverseProgress(true);
	//将渲染器放入当前层.
	addChild(right);
	//设置渲染器的位置在屏幕右边
	right->setPosition(CCPointMake(s.width-100, s.height/2));
	//让它运行一个无限循环的进度动画,进度变化由控制器2来控制。
    right->runAction( CCRepeatForever::create(to2));
}
//取得副标题。
std::string SpriteProgressToRadial::subtitle()
{
    return "ProgressTo Radial";
}

SpriteProgressToHorizontal:

//===============SpriteProgressToHorizontal =================
//条形的横向进度动画演示
class SpriteProgressToHorizontal : public SpriteDemo
{
public:
	//重载当前层被加载时的处理函数。
    virtual void onEnter();
	//取得副标题
    virtual std::string subtitle();
};

对应的CPP实现:

//当前层被加载时的处理函数。
void SpriteProgressToHorizontal::onEnter()
{
	//基类的相应函数。
    SpriteDemo::onEnter();
    //取得窗口的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    //创建两个进度动画的控制器.2秒进度值变化到100。
    CCProgressTo *to1 = CCProgressTo::create(2, 100);
    CCProgressTo *to2 = CCProgressTo::create(2, 100);
    //创建一个进度动画的渲染器.使用女演员精灵来渲染。
    CCProgressTimer *left = CCProgressTimer::create(CCSprite::create(s_pPathSister1));
	//设置表现为条形进度动画。
    left->setType(kCCProgressTimerTypeBar);
    //设置进度起点在最左边
    left->setMidpoint(ccp(0,0));
    //设置进度动画方向为从左到右随进度增长而显现。
    left->setBarChangeRate(ccp(1, 0));
	//将渲染器放入当前层。
	addChild(left);
	//设置渲染器的位置在屏幕左边
	left->setPosition(CCPointMake(100, s.height/2));
	//让它运行一个无限循环的进度动画,进度变化由控制器1来控制。
    left->runAction( CCRepeatForever::create(to1));
    //创建另一个进度动画的渲染器.使用女二号演员精灵来渲染。

	CCProgressTimer *right = CCProgressTimer::create(CCSprite::create(s_pPathSister2));
	//设置表现为条形进度动画。
    right->setType(kCCProgressTimerTypeBar);
    //设置进度起点在最右边
    right->setMidpoint(ccp(1, 0));
    //设置进度动画方向为从右到左随进度增长而显现。
	right->setBarChangeRate(ccp(1, 0));
	//将渲染器放入当前层。
	addChild(right);
	//设置渲染器的位置在屏幕右边
	right->setPosition(CCPointMake(s.width-100, s.height/2));
	//让它运行一个无限循环的进度动画,进度变化由控制器2来控制。
    right->runAction( CCRepeatForever::create(to2));
}
//取得幅标题。
std::string SpriteProgressToHorizontal::subtitle()
{
    return "ProgressTo Horizontal";
}

SpriteProgressToVertical:

//==========SpriteProgressToVertical =============================
//纵向的条形进度动画演示
class SpriteProgressToVertical : public SpriteDemo
{
public:
	//重载当前层被加载时的处理函数。
    virtual void onEnter();
	//取得副标题
    virtual std::string subtitle();
};

对应的CPP实现:

//当前层被加载时的处理函数。
void SpriteProgressToVertical::onEnter()
{
	//基类的相应函数。
    SpriteDemo::onEnter();
    //取得窗口的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    //创建两个进度动画的控制器.2秒进度值变化到100。
    CCProgressTo *to1 = CCProgressTo::create(2, 100);
    CCProgressTo *to2 = CCProgressTo::create(2, 100);
    //创建一个进度动画的渲染器.使用女演员精灵来渲染。
    CCProgressTimer *left = CCProgressTimer::create(CCSprite::create(s_pPathSister1));
	//设置表现为条形进度动画。
    left->setType(kCCProgressTimerTypeBar);
    //设置进度起点在最上边
    left->setMidpoint(ccp(0,0));
    //设置进度动画方向为从上到下随进度增长而显现。

	left->setBarChangeRate(ccp(0, 1));
	//将渲染器放入当前层。
	addChild(left);
	//设置渲染器的位置在屏幕左边
	left->setPosition(CCPointMake(100, s.height/2));
	//让它运行一个无限循环的进度动画,进度变化由控制器1来控制。
    left->runAction( CCRepeatForever::create(to1));
    //创建另一个进度动画的渲染器.使用女二号演员精灵来渲染。
	CCProgressTimer *right = CCProgressTimer::create(CCSprite::create(s_pPathSister2));
	//设置表现为条形进度动画。
    right->setType(kCCProgressTimerTypeBar);
    //设置进度起点在最下边
    right->setMidpoint(ccp(0, 1));
	//设置进度动画方向为从下到上随进度增长而显现。    	right->setBarChangeRate(ccp(0, 1));
	//将渲染器放入当前层。
	addChild(right);
	//设置渲染器的位置在屏幕右边
	right->setPosition(CCPointMake(s.width-100, s.height/2));
	//让它运行一个无限循环的进度动画,进度变化由控制器2来控制。
    right->runAction( CCRepeatForever::create(to2));
}
//取得幅标题。
std::string SpriteProgressToVertical::subtitle()
{
    return "ProgressTo Vertical";
}

SpriteProgressToRadialMidpointChanged:

//===========SpriteProgressToRadialMidpointChanged =============
//中点可改变的绕中点旋转的进度动画。
class SpriteProgressToRadialMidpointChanged : public SpriteDemo
{
public:
	//重载当前层被加载时的处理函数。
    virtual void onEnter();
	//取得副标题
    virtual std::string subtitle();
};

对应的CPP实现:

//当前层被加载时的处理函数。
void SpriteProgressToRadialMidpointChanged::onEnter()
{
	//基类的相应函数。
    SpriteDemo::onEnter();
//取得窗口的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    //创建进度动画的控制器.2秒进度值变化到100。
    CCProgressTo *action = CCProgressTo::create(2, 100);

    //创建一个进度动画的渲染器.使用块色图精灵来渲染。
    CCProgressTimer *left = CCProgressTimer::create(CCSprite::create(s_pPathBlock));
	//设置表现为绕圆心旋转的进度动画。
	left->setType(kCCProgressTimerTypeRadial);
	//将渲染器放入当前层。
	addChild(left);
	//设置旋转的中心点在横向靠左1/4位置,纵向靠上1/4位置。
	left->setMidpoint(ccp(0.25f, 0.75f));
	//设置渲染器的位置在屏幕左边。
	left->setPosition(ccp(100, s.height/2));
	//让它运行一个无限循环的进度动画,进度变化由控制器1的拷贝来控制。
    left->runAction(CCRepeatForever::create((CCActionInterval *)action->copy()->autorelease()));
   
	//创建另一个进度动画的渲染器.以下与上基本相同,只是中心点位置和精灵位置不同。
    CCProgressTimer *right = CCProgressTimer::create(CCSprite::create(s_pPathBlock));
    right->setType(kCCProgressTimerTypeRadial);
    right->setMidpoint(ccp(0.75f, 0.25f));
    addChild(right);
    right->setPosition(ccp(s.width-100, s.height/2));
    right->runAction(CCRepeatForever::create((CCActionInterval *)action->copy()->autorelease()));
}
//取得幅标题。
std::string SpriteProgressToRadialMidpointChanged::subtitle()
{
    return "Radial w/ Different Midpoints";
}

SpriteProgressBarVarious:

//=============SpriteProgressBarVarious =======================
//
class SpriteProgressBarVarious : public SpriteDemo
{
public:
	//重载当前层被加载时的处理函数。
    virtual void onEnter();
	//取得副标题
    virtual std::string subtitle();
};

对应的CPP:

void SpriteProgressBarVarious::onEnter()
{
	//基类的相应函数。
    SpriteDemo::onEnter();
	//取得窗口的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    //创建进度动画的控制器.2秒进度值变化到100。
    CCProgressTo *to = CCProgressTo::create(2, 100);
    //创建一个进度动画的渲染器.使用女演员精灵来渲染。
	CCProgressTimer *left = CCProgressTimer::create(CCSprite::create(s_pPathSister1));
	//设置表现为条形的进度动画。
    left->setType(kCCProgressTimerTypeBar);

    //设置起始位置在中间。
    left->setMidpoint(ccp(0.5f, 0.5f));
    //设置方向为横向向两边扩散。
	left->setBarChangeRate(ccp(1, 0));
	//将渲染器放入当前层
	addChild(left);
	//设置渲染器的位置在屏幕左边。
	left->setPosition(ccp(100, s.height/2));
	//运行进度动画,动画表现为根据进度的递增精灵会横向由中心向两边显现。
    left->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));
	//创建另一个渲染器.使用女二号演员精灵来渲染。
	CCProgressTimer *middle = CCProgressTimer::create(CCSprite::create(s_pPathSister2));
	//设置表现为条形的进度动画。
    middle->setType(kCCProgressTimerTypeBar);
    //设置起始位置在屏幕中间。
    middle->setMidpoint(ccp(0.5f, 0.5f));
    //设置方向为向四周扩散。
	middle->setBarChangeRate(ccp(1,1));
	//将渲染器放入当前层
	addChild(middle);
	//设置渲染器的位置在中央。
	middle->setPosition(ccp(s.width/2, s.height/2));
	//运行进度动画,动画表现为根据进度的递增精灵会横向由中心向四周显现。
    middle->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));

	//创建第三个渲染器。
	CCProgressTimer *right = CCProgressTimer::create(CCSprite::create(s_pPathSister2));
	//设置表现为条形的进度动画。
    right->setType(kCCProgressTimerTypeBar);
    //设置起始位置在中间。
    right->setMidpoint(ccp(0.5f, 0.5f));
     //设置方向为纵向向两边扩散。
	right->setBarChangeRate(ccp(0, 1));
	//将渲染器放入当前层
    addChild(right);
	//设置渲染器的位置在屏幕右边。
	right->setPosition(ccp(s.width-100, s.height/2));
	//运行进度动画,动画表现为根据进度的递增精灵会纵向由中心向两边显现。
    right->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));
}
//取得幅标题。
std::string SpriteProgressBarVarious::subtitle()
{
    return "ProgressTo Bar Mid";
}

SpriteProgressBarTintAndFace:

//==========SpriteProgressBarTintAndFade ===================
//进度动画之颜色,透明度的变化。
class SpriteProgressBarTintAndFade : public SpriteDemo
{
public:
	//重载当前层被加载时的处理函数。
    virtual void onEnter();
	//取得副标题
    virtual std::string subtitle();
};

CPP实现:

void SpriteProgressBarTintAndFade::onEnter()
{
	//基类的相应函数。
    SpriteDemo::onEnter();
	//取得窗口的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//创建进度动画的控制器.6秒进度值变化到100。
    CCProgressTo *to = CCProgressTo::create(6, 100);	//创建一个动画序列,先是1秒内变化到红色,再经1秒变化到绿色,最后1秒变化到蓝色。
    CCAction *tint = CCSequence::create(CCTintTo::create(1, 255, 0, 0),
                                         CCTintTo::create(1, 0, 255, 0),
                                         CCTintTo::create(1, 0, 0, 255),
                                         NULL);
	//创建一个动画序列,先是1秒内透明度变化到0而消失,再经1秒变化到255显现。
    CCAction *fade = CCSequence::create(CCFadeTo::create(1.0f, 0),
                                         CCFadeTo::create(1.0f, 255),
                                         NULL);
	//创建一个进度动画渲染器,由女演员来表演这个进度动画效果。
	CCProgressTimer *left = CCProgressTimer::create(CCSprite::create(s_pPathSister1));
	//设置进度动画的形式为条形动画。
    left->setType(kCCProgressTimerTypeBar);

    //设置起点为中间位置。
    left->setMidpoint(ccp(0.5f, 0.5f));
     //设置动画的方向为精灵根据进度的递增横向渐渐扩大显示。
	left->setBarChangeRate(ccp(1, 0));
	//将渲染器放入当前层。
	addChild(left);
	//设置渲染器的位置放在屏幕左边。
	left->setPosition(ccp(100, s.height/2));
	//让渲染器运行一个无限循环进度动画,由上面进度动画控制器的拷贝来进行控制。
	left->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));
	//让渲染器运行一个无限循环动画序列,不断的进行上面的色彩变化。
	left->runAction(CCRepeatForever::create((CCActionInterval *)tint->copy()->autorelease()));
	//将一个文字标签放入到渲染器的结点之下。
    left->addChild(CCLabelTTF::create("Tint", "Marker Felt", 20.0f));
	//创建第二个进度动画的渲染器。
    CCProgressTimer *middle = CCProgressTimer::create(CCSprite::create(s_pPathSister2));
	//设置其表现形式为条形动画。
    middle->setType(kCCProgressTimerTypeBar);
    //设置动画的起点在中心点位置。
    middle->setMidpoint(ccp(0.5f, 0.5f));
    //设置动画的方向为精灵根据进度的递增向四周渐渐扩大显示。
	middle->setBarChangeRate(ccp(1, 1));
	//将渲染器放入当前层。
	addChild(middle);
	//设置渲染器的位置在屏幕中央。
	middle->setPosition(ccp(s.width/2, s.height/2));
	//让渲染器运行一个无限循环的进度动画,由上面进度动画控制器的拷贝来进行控制。
	middle->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));
	//让渲染器运行一个无限循环动画序列,不断的进行上面的透明度变化。
    middle->runAction(CCRepeatForever::create((CCActionInterval *)fade->copy()->autorelease()));
	//将一个文字标签放入到渲染器的结点之下。
    middle->addChild(CCLabelTTF::create("Fade", "Marker Felt", 20.0f));
	//创建第三个进度动画的渲染器。
	CCProgressTimer *right = CCProgressTimer::create(CCSprite::create(s_pPathSister2));
	//设置其表现形式为条形动画。
    right->setType(kCCProgressTimerTypeBar);
    //设置动画的起点在中心点位置。
    right->setMidpoint(ccp(0.5f, 0.5f));
    //设置动画的方向为精灵根据进度的递增纵向渐渐扩大显示。
    right->setBarChangeRate(ccp(0, 1));
	addChild(right);
	//设置渲染器的位置在屏幕右边。
	right->setPosition(ccp(s.width-100, s.height/2));
	//让渲染器运行一个无限循环的进度动画,由上面进度动画控制器的拷贝来进行控制。
	right->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));
	//让渲染器运行一个无限循环动画序列,不断的进行上面的颜色变化。
    right->runAction(CCRepeatForever::create((CCActionInterval *)tint->copy()->autorelease()));
   //让渲染器运行一个无限循环动画序列,不断的进行上面的透明度变化。
	right->runAction(CCRepeatForever::create((CCActionInterval *)fade->copy()->autorelease()));
	//将一个文字标签放入到渲染器的结点之下。
    right->addChild(CCLabelTTF::create("Tint and Fade", "Marker Felt", 20.0f));
}
//取得幅标题。
std::string SpriteProgressBarTintAndFade::subtitle()
{
    return "ProgressTo Bar Mid";
}

SpriteProgressWithSpriteFrame:

//==========SpriteProgressWithSpriteFrame ===============
//进度动画之使用序列帧中的单帧精灵来演示。
class SpriteProgressWithSpriteFrame : public SpriteDemo
{
public:
	//重载当前层被加载时的处理函数。
    virtual void onEnter();
	//取得副标题
    virtual std::string subtitle();
};

CPP实现:

void SpriteProgressWithSpriteFrame::onEnter()
{
	//基类的相应函数。
    SpriteDemo::onEnter();
	//取得窗口的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//创建进度动画的控制器.6秒进度值变化到100。
    CCProgressTo *to = CCProgressTo::create(6, 100);

	//读取一个plist导出一个序列帧动画。
	CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("zwoptex/grossini.plist");
	//创建一个进度动画渲染器,使用序列帧中的grossini_dance_01.png图像来进行动画的渲染。
	CCProgressTimer *left = CCProgressTimer::create(CCSprite::createWithSpriteFrameName("grossini_dance_01.png"));
	//将进度动画的表现形式设置为条形动画。
    left->setType(kCCProgressTimerTypeBar);
    //设置动画的起点在中心点位置。
    left->setMidpoint(ccp(0.5f, 0.5f));
    //设置进度动画为精灵根据进度的递增横向渐渐扩大显示。
	left->setBarChangeRate(ccp(1, 0));
	//将渲染器放入当前层。
	addChild(left);
	//设置渲染器的位置放在屏幕左边。
	left->setPosition(ccp(100, s.height/2));
	//让渲染器运行一个无限循环的进度动画,由上面进度动画控制器的拷贝来进行控制。
    left->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));
	//创建第二个进度动画的渲染器。使用序列帧中的grossini_dance_02.png图像来进行动画的渲染。
	
	CCProgressTimer *middle = CCProgressTimer::create(CCSprite::createWithSpriteFrameName("grossini_dance_02.png"));
	//设置其表现形式为条形动画。
    middle->setType(kCCProgressTimerTypeBar);
    //设置动画的起点在中心点位置。
    middle->setMidpoint(ccp(0.5f, 0.5f));
	//设置动画的方向为精灵根据进度的递增向四周渐渐扩大显示。
	middle->setBarChangeRate(ccp(1, 1));
	//将渲染器放入当前层。
	addChild(middle);
	//设置渲染器的位置放在屏幕中央。
	middle->setPosition(ccp(s.width/2, s.height/2));
	//让渲染器运行一个无限循环的进度动画,由上面进度动画控制器的拷贝来进行控制。
    middle->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));
	//创建第三个进度动画的渲染器使用序列帧中的grossini_dance_03.png图像来进行动画的渲染。
	CCProgressTimer *right = CCProgressTimer::create(CCSprite::createWithSpriteFrameName("grossini_dance_03.png"));
	//设置其表现形式为条形动画。
    right->setType(kCCProgressTimerTypeRadial);
    //设置动画的起点在中心点位置。
    right->setMidpoint(ccp(0.5f, 0.5f));
    //设置动画的方向为精灵根据进度的递增纵向渐渐扩大显示。
	right->setBarChangeRate(ccp(0, 1));
	//将渲染器放入当前层。
	addChild(right);
	//设置渲染器的位置放在屏幕右边。
	right->setPosition(ccp(s.width-100, s.height/2));
	//让渲染器运行一个无限循环的进度动画,由上面进度动画控制器的拷贝来进行控制。
    right->runAction(CCRepeatForever::create((CCActionInterval *)to->copy()->autorelease()));
}

//取得幅标题。
std::string SpriteProgressWithSpriteFrame::subtitle()
{
    return "Progress With Sprite Frame";
}

       这些演示类都讲完了,最后是在场景中通过按钮把这些演示实例联系起来让用户可以控制演示哪一个进度动画。

//============================================================
//TestBasic.h中定义了基础的演示场景类,这里由它派生一个场景类用于演示本节的进度动画。
class ProgressActionsTestScene : public TestScene
{
public:
	//重载运行场景时的处理。
    virtual void runThisTest();
};

对应的CPP:

#include "ActionsProgressTest.h"
#include "../testResource.h"
//场景索引。
static int sceneIdx = -1; 
//演示实例的数量。
#define MAX_LAYER    7
//创建相应的演示动画的CCLayer。

//下一个动画演示。
CCLayer* nextAction();
//上一个动画演示。
CCLayer* backAction();
//重新启动当前的动画演示。
CCLayer* restartAction();

//创建对应的进度动画演示CCLayer实例。
CCLayer* createLayer(int nIndex)
{
    switch(nIndex)
    {
        case 0: return new SpriteProgressToRadial();
        case 1: return new SpriteProgressToHorizontal();
        case 2: return new SpriteProgressToVertical();
        case 3: return new SpriteProgressToRadialMidpointChanged();
        case 4: return new SpriteProgressBarVarious();
        case 5: return new SpriteProgressBarTintAndFade();
        case 6: return new SpriteProgressWithSpriteFrame();
    }

    return NULL;
}

//下一个动画演示。
CCLayer* nextAction()
{
	//索引加1,并与最大数量取模,限定在有效范围内。
    sceneIdx++;
    sceneIdx = sceneIdx % MAX_LAYER;
	//创建对应的进度动画演示实例CCLayer。
	CCLayer* pLayer = createLayer(sceneIdx);
	//将其交由内存管理器来进行释放处理。
    pLayer->autorelease();
	//返回对应进度动画演示实例CCLayer。
    return pLayer;
}
//上一个动画演示。
CCLayer* backAction()
{
	//索引减1,并限定在有效范围内。
	sceneIdx--;
    int total = MAX_LAYER;
    if( sceneIdx < 0 )
        sceneIdx += total;    
	//创建对应的进度动画演示实例CCLayer。
	CCLayer* pLayer = createLayer(sceneIdx);
	//将其交由内存管理器来进行释放处理。
    pLayer->autorelease();
//返回对应进度动画演示实例CCLayer。
    return pLayer;
}

//重新启动当前的动画演示。
CCLayer* restartAction()
{
	//创建对应的进度动画演示实例CCLayer。
	CCLayer* pLayer = createLayer(sceneIdx);
	//将其交由内存管理器来进行释放处理。
    pLayer->autorelease();
	//返回对应进度动画演示实例CCLayer。
    return pLayer;
} 

//启动当前场景。
void ProgressActionsTestScene::runThisTest()
{
	//将第一个进度动画演示的CCLayer实例创建出来并放入当前场景。
	addChild(nextAction());
	//运行当前场景。
    CCDirector::sharedDirector()->replaceScene(this);
}

        终于把这些东东都解释完了,我想大家不会只是知其然,而更是知其所以然。这几个月的辛苦努力,能换来大家对于博客的关注,我很开心,只是目前仍然对Cocos2d-x处于学习状态中,暂时只想尽快把它分析完了,然后再考虑出一些实例和视频教程,如果当前源码大家看起来有点头疼,可以多动手操作一下,相信我,对于基本功的提高,读代码能力的提高都是有极大的好处的。

分类: cocos2d, cocos2d-x 标签:

Creating iOS Universal App, How To Detect All 5 Resolutions?

2012年12月7日 没有评论

Title pretty well says it. I’m creating an iOS app and am at the point of add art assets. I have 5 backgrounds for iPhone low res(iPhone 3GS or lower ), iPhone retina (iPhone 4 or higher), iPhone 5, iPad low res, and iPad high res.

What’s the best way to handle which background gets loaded based on the device?

Also, is there a way to test what all 5 looks like in the simulator? Right now, of course, you can only test iPhone and iPad.

Also, this is a game and I’m using cocos2d if that would make a difference.

For cocos2D-iPhone, the default suffixes are as follows:

  • Non-retina iPhone: image.png
  • Retina iPhone: image-hd.png
  • Non-retina iPad: image-ipad.png
  • Retina iPad: image-ipadhd.png

Note from the wiki page:

WARNING: It is NOT recommend to use the ”@2x” suffix. Apple treats those images in a special way which might cause bugs in your
cocos2d application.

Cocos2D will automatically detect your hardware and will load the appropriate image. You can change the default suffixes in AppDelegate.m.

AFAIK, there is no suffix for iPhone 5 images, so you can manually detect and load your custom sprite by detecting the device height:

CGRect screenBounds = [[UIScreen mainScreen] bounds];
if (screenBounds.size.height == 568) {
    // code for iPhone 5
} else {
    // code for all other iOS devices
}

And as the others said, you can test all devices through the simulator (Hardware -> Device)

You can have two versions of each image

image.png, image@2x.png

The system will automatically pick image@2x.png if it is a retina device where ever you refer to image.png

Also in the simulator, you can go to Hardware->Device and then pick if you want to see retina or not.

If you’re using cocos2d, then you’ll need to use -hd suffixes on your retina-resolution images. Check out their wiki page for more info on that.

I don’t work with cocos2d myself, but from the sound of it it, iPhone 5’s screen resolution is handled in the same way an iPad’s screen resolution is handled, by adjusting the layout accordingly. A search in stackoverflow should yield some good results for cocos2d and iPhone 5.

As @Srikanth mentioned, include image.png & image@2x.png, and the system will automatically choose the higher-res one for high-res screens and the lower for lower-res screens. This works on both iPhone and iPad.

For iPhone 5, the screen is still Retina. The system will choose your -@2x image automatically. You can define Auto Layout (or springs and struts) in Interface Builder or in code.

If for some reason you absolutely need an image specific to the iPhone 5-type screens, I believe you can add an image-568h@2x.png and the system will automatically choose that for 4-inch screens.

The only reason I can think of that you would include a -568h@2x image in your bundle is for launch images: You need one specific to 4-inch screens.

Also, about the Simulator: You can test all 5 resolutions. In the simulator menu bar (at the top of screen) choose Hardware>Device. Here you have an option for all 5 resolutions.

分类: stackoverflow精选, unity3d 标签:

Cocos2d-x 2.0 之 Actions “三板斧” 之三

2012年12月6日 没有评论

[Cocos2d-x相关教程来源于红孩儿的游戏编程之路CSDN博客地址:http://blog.csdn.net/honghaier]

红孩儿Cocos2d-X学习园地QQ2群:44208467 加群写:Cocos2d-x 
红孩儿Cocos2d-X学习园地QQ群:249941957 [暂满]加群写:Cocos2d-x 

本章为我的Cocos2d-x教程一书初稿。望各位看官多提建议!


 Cocos2d-x 2.0 TestCpp 之 ActionsTest深入分析

另:本章所用Cocos2d-x版本为:

cocos2d-2.0-x-2.0.2 @ Aug 30 2012

http://cn.cocos2d-x.org/download

  之前两斧子,相信大家已经对于动画的原理有了比较清楚的了解,这最后一斧子,咱们一起看一看ActionsTest.hcpp。我们打开头文件来看一下代码:

#ifndef _ActionsTest_H_
#define _ActionsTest_H_
//包含示例的基本头文件,因为要用到演示场景基类TestScene。这个类在之前的TestCpp框架分析中有讲解。
#include "../testBasic.h"
////----#include "cocos2d.h"
//使用Cocos2d的命名空间
USING_NS_CC;
//这里是一个枚举,列出了示例中所有的精灵动画类型
enum
{
    ACTION_MANUAL_LAYER = 0,//基本状态
    ACTION_MOVE_LAYER,		//移动动画
    ACTION_SCALE_LAYER,		//缩放动画
    ACTION_ROTATE_LAYER,		//旋转动画
    ACTION_SKEW_LAYER,		//扭曲动画
    ACTION_SKEWROTATE_LAYER,//扭曲与旋转组合动画
    ACTION_JUMP_LAYER,		//跳跃动画
    ACTION_CARDINALSPLINE_LAYER,//贝塞尔曲线动画
    ACTION_CATMULLROM_LAYER,//点构成的曲线动画
    ACTION_BEZIER_LAYER,		//贝塞尔曲线路径动画
    ACTION_BLINK_LAYER,		//闪现动画
    ACTION_FADE_LAYER,		//淡入淡出动画
    ACTION_TINT_LAYER,		//变色动画
    ACTION_ANIMATE_LAYER,	//帧动画
    ACTION_SEQUENCE_LAYER,	//动画序列
    ACTION_SEQUENCE2_LAYER,	//动画序列
    ACTION_SPAWN_LAYER,		//动画组合
    ACTION_REVERSE,			//反向播放动画
    ACTION_DELAYTIME_LAYER,	//动画暂停与继续播放
    ACTION_REPEAT_LAYER,		//重复播放动画
    ACTION_REPEATEFOREVER_LAYER,//无限循环播放动画
    ACTION_ROTATETOREPEATE_LAYER,//循环旋转动画一
    ACTION_ROTATEJERK_LAYER,//循环旋转动画二
    ACTION_CALLFUNC_LAYER,//动画与函数调用一
    ACTION_CALLFUNCND_LAYER,//动画与函数调用二
    ACTION_REVERSESEQUENCE_LAYER,//反向动画序列。
    ACTION_REVERSESEQUENCE2_LAYER,//反向动画序列二。
    ACTION_ORBIT_LAYER,//旋转摄像机动画
    ACTION_FLLOW_LAYER,//跟随动画
    ACTION_TARGETED_LAYER,//控制目标动画
    PAUSERESUMEACTIONS_LAYER,//暂停与恢复动画
    ACTION_ISSUE1305_LAYER,//1305号动画
    ACTION_ISSUE1305_2_LAYER,//1305号的动画二
    ACTION_ISSUE1288_LAYER,//1288号动画
    ACTION_ISSUE1288_2_LAYER,//1288的动画二
    ACTION_ISSUE1327_LAYER,//1327号动画
    ACTION_LAYER_COUNT,//动画最大数量
};

//看完这些枚举,我想说的是,精灵动画的类型真TMD丰富啊!竟然多到想不出名字~:)

//这是用于展示每种动画的基础场景类,它包含了一个返回主菜单的按钮。
class ActionsTestScene : public TestScene
{
public:
	//重虚函数runThisTest做一些初始化工作。
    virtual void runThisTest();
};
为了方便代码阅读,我将CPP中相应函数实现移过来,后面都按这种格式:
//演示动画所用场景基类的初始化函数重载
void ActionsTestScene::runThisTest()
{
	//先将索引置-1,后面调用NextAction()使其加1变为0,即演示第一个动画。
    s_nActionIdx = -1;
    addChild(NextAction());
	//运行当前场景。
    CCDirector::sharedDirector()->replaceScene(this);
}



//从CCLayer派生出一个基础的动画演示类,用于包含要表现动作的一些精灵。
class ActionsDemo : public CCLayer
{
protected:
	//动画的主角要出场啦!以下是三个图片精灵实例指针,其分别指向出场表演的男1号grossini,女1号tamara,女2号kathia,这一男两女将成为动画演示的三位演员。大家欢迎它们!
    CCSprite*    m_grossini;
    CCSprite*    m_tamara;
    CCSprite*    m_kathia;
public:
	//重载当前动画类被载入时要调用的函数onEnter做一些精灵生成的处理。
    virtual void onEnter();
	//重载当前动画类被卸载时要调用的函数onExit做一些释放处理。
    virtual void onExit();
	//这个函数用于指定需要几位演员出场时如果要求居中对齐该怎么站位。
    void centerSprites(unsigned int numberOfSprites);
	//这个函数用于指定需要几位演员出场时如果要求居左对齐该怎么站位。
    void alignSpritesLeft(unsigned int numberOfSprites);
	//取得动画的主标题
    virtual std::string title();
	//取得动画的副标题
    virtual std::string subtitle();
	//当在点击“重置”按钮时的回调函数
    void restartCallback(CCObject* pSender);
	//当在点击“下一个”按钮时的回调函数
    void nextCallback(CCObject* pSender);
	//当在点击“上一个”按钮时的回调函数。
    void backCallback(CCObject* pSender);
};
//取得演示动画CCLayer所用基类的主标题
std::string ActionsDemo::title()
{
    return "ActionsTest";
}
//取得演示动画CCLayer所用基类的副标题
std::string ActionsDemo::subtitle()
{
    return "";
}
//加载演示动画CCLayer所用基类时的初始化处理函数。
void ActionsDemo::onEnter()
{
    CCLayer::onEnter();

	//创建了三个演员。
	//男一号,其使用图片地址为s_pPathGrossini
    m_grossini = CCSprite::create(s_pPathGrossini);
    m_grossini->retain();

	//女一号,其使用图片地址为s_pPathSister1
    m_tamara = CCSprite::create(s_pPathSister1); 
	m_tamara->retain();
	
	//女二号,其使用图片地址为s_pPathSister2
    m_kathia = CCSprite::create(s_pPathSister2);
	m_kathia->retain();
	
	//将三位演员都放入当前演示动画所在的CCLayer中。
    addChild(m_grossini, 1);
    addChild(m_tamara, 2);
    addChild(m_kathia, 3);
	//取得屏幕的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//男一号站在屏幕中下位置
	m_grossini->setPosition(CCPointMake(s.width/2, s.height/3));
	//女一号站在屏幕中上位置
	m_tamara->setPosition(CCPointMake(s.width/2, 2*s.height/3));
	//女二号站在屏幕正中间
    m_kathia->setPosition(CCPointMake(s.width/2, s.height/2)); 

    // 创建一个文字标签用于显示标题
    std::string str = title();
    const char * pTitle = str.c_str();
    CCLabelTTF* label = CCLabelTTF::create(pTitle, "Arial", 18);
    addChild(label, 1);
	//将文字标签放在屏幕正中靠上位置
    label->setPosition( CCPointMake(s.width/2, s.height - 30) );
	//创建一个文字标签用于显示副标题
    std::string strSubtitle = subtitle();
    if( ! strSubtitle.empty() ) 
    {
		//创建文件标签并放在主标题文字标签之下。
        CCLabelTTF* l = CCLabelTTF::create(strSubtitle.c_str(), "Thonburi", 22);
        addChild(l, 1);
        l->setPosition( CCPointMake(s.width/2, s.height - 60) );
    }    

    // 创建三个按钮(看名字应理解为图片菜单项,其实就是具有普通和按下两种状态的图片切换效果的按钮)用于控制演示的动画。
	// 第一个按钮,在按下时调用演示上一个动画的函数。
    CCMenuItemImage *item1 = CCMenuItemImage::create(s_pPathB1, s_pPathB2, this, menu_selector(ActionsDemo::backCallback) );
	// 第二个按钮,在按下时调用重新演示当前动画的函数。
    CCMenuItemImage *item2 = CCMenuItemImage::create(s_pPathR1, s_pPathR2, this, menu_selector(ActionsDemo::restartCallback) );
	// 第三个按钮,在按下时调用演示下一个动画的函数。
    CCMenuItemImage *item3 = CCMenuItemImage::create(s_pPathF1, s_pPathF2, this, menu_selector(ActionsDemo::nextCallback) );
	//由这三个按钮(也就是刚说的“图片菜单项”)生成一个菜单。因为CMenuItemImage和CCMenu都是CCNode的子类。所以这一句本质上是将若干CCNode做为一个新的CCNode的子节点并返回。
    CCMenu *menu = CCMenu::create(item1, item2, item3, NULL);
	//将菜单放在零零点位置。
    menu->setPosition(CCPointZero);
	//设置各个按钮相对于菜单项的位置。
    item1->setPosition(CCPointMake(s.width/2 - item2->getContentSize().width*2, item2->getContentSize().height/2));
    item2->setPosition(CCPointMake(s.width/2, item2->getContentSize().height/2));
    item3->setPosition(CCPointMake(s.width/2 + item2->getContentSize().width*2, item2->getContentSize().height/2));
	//将菜单加入当前的演示动画CCLayer所用基类中。
    addChild(menu, 1);
}
//在当前演示动画CCLayer所用基类被释放时的处理函数
void ActionsDemo::onExit()
{
	//精灵的释放,代表三位演员的退场。
    m_grossini->release();
    m_tamara->release();
    m_kathia->release();

    CCLayer::onExit();
}
//重新演示当前动画的回调函数。
void ActionsDemo::restartCallback(CCObject* pSender)
{
	//创建一个新场景
    CCScene* s = new ActionsTestScene();
	//将RestartAction()函数返回的CCLayer加入场景中。
    s->addChild( RestartAction() );
	//将新场景做为游戏要显示的场景。
    CCDirector::sharedDirector()->replaceScene(s);
	//引用计数器减1操作,以使未来可以正确的被释放。
    s->release();
}
//演示下一个动画的回调函数。
void ActionsDemo::nextCallback(CCObject* pSender)
{
	//创建一个新场景
    CCScene* s = new ActionsTestScene();
	//将NextAction()函数返回的CCLayer加入场景中。
    s->addChild( NextAction() );
	//将新场景做为游戏要显示的场景。
    CCDirector::sharedDirector()->replaceScene(s);
	//引用计数器减1操作,以使未来可以正确的被释放。
    s->release();
}
//演示上一个动画的回调函数。
void ActionsDemo::backCallback(CCObject* pSender)
{
	//创建一个新场景
    CCScene* s = new ActionsTestScene();
	//将BackAction ()函数返回的CCLayer加入场景中。
    s->addChild( BackAction() );
	//将新场景做为游戏要显示的场景。
    CCDirector::sharedDirector()->replaceScene(s);
	//引用计数器减1操作,以使未来可以正确的被释放。
    s->release();
}
//这个函数用于指定需要几位演员出场时如果要求居中对齐该怎么站位。
void ActionsDemo::centerSprites(unsigned int numberOfSprites)
{
	//取得屏幕大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    if( numberOfSprites == 0 )
    {	//如果指定没有演员,将三位演员都设为不显示
        m_tamara->setVisible(false);
        m_kathia->setVisible(false);
        m_grossini->setVisible(false);
    } 
    else if ( numberOfSprites == 1 ) 
    {	//如果指定只有一位演员来表演,则将男一号放在屏幕中央,两位女演员设为不显示。
        m_tamara->setVisible(false);
        m_kathia->setVisible(false);
        m_grossini->setPosition(CCPointMake(s.width/2, s.height/2));
    }
    else if( numberOfSprites == 2 ) 
    {   //如果指定两位演员来表演,则将两位女演员放在屏幕中心位置对齐的两边,并将男演员设为不显示。     
        m_kathia->setPosition( CCPointMake(s.width/3, s.height/2));
        m_tamara->setPosition( CCPointMake(2*s.width/3, s.height/2));
        m_grossini->setVisible(false);
    } 
    else if( numberOfSprites == 3 ) 
    {	//三位演员同时上场,分别放在屏幕左,中,右三个位置。
        m_grossini->setPosition( CCPointMake(s.width/2, s.height/2));
        m_tamara->setPosition( CCPointMake(s.width/4, s.height/2));
        m_kathia->setPosition( CCPointMake(3 * s.width/4, s.height/2));
    }
}
//这个函数用于指定需要几位演员出场时如果要求居左对齐该怎么站位。同上,只是位置略有差别。
void ActionsDemo::alignSpritesLeft(unsigned int numberOfSprites)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();

    if( numberOfSprites == 1 ) 
    {
        m_tamara->setVisible(false);
        m_kathia->setVisible(false);
        m_grossini->setPosition(CCPointMake(60, s.height/2));
    } 
    else if( numberOfSprites == 2 ) 
    {        
        m_kathia->setPosition( CCPointMake(60, s.height/3));
        m_tamara->setPosition( CCPointMake(60, 2*s.height/3));
        m_grossini->setVisible( false );
    } 
    else if( numberOfSprites == 3 ) 
    {
        m_grossini->setPosition( CCPointMake(60, s.height/2));
        m_tamara->setPosition( CCPointMake(60, 2*s.height/3));
        m_kathia->setPosition( CCPointMake(60, s.height/3));
    }
}



//这是第一个要演示的动画,其实它只是把三位演员显示出来。
class ActionManual : public ActionsDemo
{
public:
	//重载当前动画类被载入时要调用的函数onEnter做一些精灵生成的处理。
    virtual void onEnter();
	//重载取得动画的副标题
    virtual std::string subtitle();
};
//基础演示动画所用CCLayer被加载时的初始化处理函数。
void ActionManual::onEnter()
{	//调用基类的同名函数,加载三位演员。
    ActionsDemo::onEnter();
	//取得屏幕的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//将女一号演员在X,Y方向上分别缩放后放在相应位置,并设置其半透明。
    m_tamara->setScaleX( 2.5f);
    m_tamara->setScaleY( -1.0f);
    m_tamara->setPosition( CCPointMake(100,70) );
	//透明度的取值为0~255,0代表完全透明,255代表完全不透明。
    m_tamara->setOpacity( 128);

	//男一号演员,这里让它旋转120度之后放在屏幕中心位置,并设置其全身颜色为红色。
    m_grossini->setRotation( 120);
    m_grossini->setPosition( CCPointMake(s.width/2, s.height/2));
	//色彩设置为红色。ccc3分别用R,G,B三元色做为参数返回色彩值。
    m_grossini->setColor( ccc3( 255,0,0));
	//女二号演员,这里设置位置为屏幕中心靠左。
    m_kathia->setPosition( CCPointMake(s.width-100, s.height/2));
	//色彩设置为蓝色,这以用预定义的宏ccBLUE来代表蓝色的色彩值。
    m_kathia->setColor( ccBLUE);
}
//取得当前演示动画的副标题。
std::string ActionManual::subtitle()
{
    return "Manual Transformation";
}


//第二种动画演示表现了三位演员的移动变化。
class ActionMove : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
//移动动画所用CCLayer被加载时的初始化处理函数。
void ActionMove::onEnter()
{	//调用基类的同名函数,加载三位演员。
    ActionsDemo::onEnter();
	//让三位演员以居中对齐方式进行站位。
    centerSprites(3);
	//取得屏幕的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//创建三个时间渐变动画。第一个是由CCActionInterval子类CCMoveTo静态函数所创建的“2秒移动到某位置”,第二个是由CCActionInterval子类CCMoveTo静态函数所创建的“2秒移动多少距离”。第三个是第二个动画的反向播放。
    CCActionInterval*  actionTo = CCMoveTo::create(2, CCPointMake(s.width-40, s.height-40));
    CCActionInterval*  actionBy = CCMoveBy::create(2, CCPointMake(80,80));
    CCActionInterval*  actionByBack = actionBy->reverse();
	//让三个演员分别按照不同的动画形式来演示。女一号就按第一种动画来进行演示。
    m_tamara->runAction( actionTo);
	//男一号呢?它的演示是第二个动画和第三个动画的串联。CCSequence::create函数可以将多个动画串联在一起,按照串联的顺序进行逐个播放。
    m_grossini->runAction( CCSequence::create(actionBy, actionByBack, NULL));
	//女二号同女一号类似也是演示一个移动到某位置的动画。这里指定1秒内移动到40,40的位置。
    m_kathia->runAction(CCMoveTo::create(1, CCPointMake(40,40)));
}
//这里取得移动动画演示的副标题。
std::string ActionMove::subtitle()
{
    return "MoveTo / MoveBy";
}

//第三种动画演示表现了三位演员的缩放变化。
class ActionScale : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
//缩放动画演示
void ActionScale::onEnter()
{	
	//动画演示的初始化
    ActionsDemo::onEnter();
	//将三个演员按居中对齐进行站位
    centerSprites(3);
	//三个要演示的动画形式分别是
	//1.缩放到指定的程度
    CCActionInterval*  actionTo = CCScaleTo::create(2.0f, 0.5f);
	//2.当前缩放值再续继缩放多少
    CCActionInterval*  actionBy = CCScaleBy::create(2.0f, 1.0f, 10.0f);
	//3.同2
    CCActionInterval*  actionBy2 = CCScaleBy::create(2.0f, 5.0f, 1.0f);
	//让男一号演示动画1
    m_grossini->runAction( actionTo);
	//让女一号演示一个动画序列,这个序列为先演示动画2,再演示动画2的反向播放。
    m_tamara->runAction( CCSequence::create(actionBy, actionBy->reverse(), NULL));
	//女二号的动画同女一号
    m_kathia->runAction( CCSequence::create(actionBy2, actionBy2->reverse(), NULL));
}
//副标题
std::string ActionScale::subtitle()
{
    return "ScaleTo / ScaleBy";
}

//第四种动画演示表现了三位演员的旋转变化
class ActionRotate : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionRotate::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//将三个演员按居中对齐进行站位
    centerSprites(3);
	//定义几种旋转到某个角度的动画
    CCActionInterval*  actionTo = CCRotateTo::create( 2, 45);
    CCActionInterval*  actionTo2 = CCRotateTo::create( 2, -45);
    CCActionInterval*  actionTo0 = CCRotateTo::create(2 , 0);
	//女一号演示一个动画序列
    m_tamara->runAction( CCSequence::create(actionTo, actionTo0, NULL));
	//定义从现在的角度在2秒内继续旋转360度的动画
    CCActionInterval*  actionBy = CCRotateBy::create(2 ,  360);
	//定义actionBy的反向播放动画
    CCActionInterval*  actionByBack = actionBy->reverse();
	//男一号演示一个动画序列
    m_grossini->runAction( CCSequence::create(actionBy, actionByBack, NULL));
	//女二号演示一个动画序列,这个动画序列中有一个动画为actionTo0的拷贝,并将这个拷贝设为由内存管理器进行内存释放。这句里有两个知识点:(1)为什么要使用动画的拷贝?(2)为什么要调用autorelease?答案分别是:(1)目前的引擎机制要求每个动画只能有一个演员使用。当你调用runAction时会将动画加入动画管理器,而动画管理器调用addAction函数时,会在最后调用pAction->startWithTarget(pTarget);如果这个动画已经有一个演员在使用了,这里会覆盖掉之前的演员信息,动画只能被最后使用的演员占有。(2)因为create函数创建动画时,会在内部对动画调用autorelease,而copy函数只会新生成一个动画的复制品,不会对其进行调用autorelease。
    m_kathia->runAction( CCSequence::create(actionTo2, actionTo0->copy()->autorelease(), NULL));
}
//显示副标题
std::string ActionRotate::subtitle()
{
    return "RotateTo / RotateBy";
}

//第五种动画演示表现了三位演员的扭曲变化。
class ActionSkew : public ActionsDemo
{
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionSkew::onEnter()
{	
	//动画演示的初始化
    ActionsDemo::onEnter();
	//将三个演员按居中对齐进行站位
    centerSprites(3);
	//这里定义了五种动画
	//前两种动画是扭曲到指定程度
    CCActionInterval *actionTo = CCSkewTo::create(2, 37.2f, -37.2f);
    CCActionInterval *actionToBack = CCSkewTo::create(2, 0, 0);
	//然后两种动画是继续扭曲多少
    CCActionInterval *actionBy = CCSkewBy::create(2, 0.0f, -90.0f);
    CCActionInterval *actionBy2 = CCSkewBy::create(2, 45.0f, 45.0f);
	//最后一种动画是actionBy的反向播放
    CCActionInterval *actionByBack = actionBy->reverse();
	//女一号演示一个动画序列,这个动画序列有两个动画,先是actionTo,然后是actionToBack
    m_tamara->runAction(CCSequence::create(actionTo, actionToBack, NULL));
	//男一号演示一个动画序列,这个动画序列有两个动画,先是actionBy,然后是actionByBack
    m_grossini->runAction(CCSequence::create(actionBy, actionByBack, NULL));
	//女二号演示一个动画序列,这个动画序列也是有两个动画,先是actionBy2,然后是它的反向播放。
    m_kathia->runAction(CCSequence::create(actionBy2, actionBy2->reverse(), NULL));
}
//副标题
string ActionSkew::subtitle()
{
    return "SkewTo / SkewBy";
}

//第六种动画演示表现的是前面几种变化的大杂烩。
class ActionSkewRotateScale : public ActionsDemo
{
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionSkewRotateScale::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//本动画用不到三位演员,在此将它们删除
    m_tamara->removeFromParentAndCleanup(true);
    m_grossini->removeFromParentAndCleanup(true);
    m_kathia->removeFromParentAndCleanup(true);
	//这里取得一个宽高均为100的大小
    CCSize boxSize = CCSizeMake(100.0f, 100.0f);
	//创建一个颜色层
    CCLayerColor *box = CCLayerColor::create(ccc4(255, 255, 0, 255));
	//设置锚点为左下角
    box->setAnchorPoint(ccp(0, 0));
	//设置当前颜色层的位置
    box->setPosition(ccp(190, 110));
	//设置颜色色的大小
    box->setContentSize(boxSize);
	//在颜色层上再加立两个子颜色层。
	//第一个是红色,放在左上角。
    static float markrside = 10.0f;
    CCLayerColor *uL = CCLayerColor::create(ccc4(255, 0, 0, 255));
    box->addChild(uL);
    uL->setContentSize(CCSizeMake(markrside, markrside));
    uL->setPosition(ccp(0.f, boxSize.height - markrside));
    uL->setAnchorPoint(ccp(0, 0));
	//第二个是蓝色,放在右上角。
    CCLayerColor *uR = CCLayerColor::create(ccc4(0, 0, 255, 255));
    box->addChild(uR);
    uR->setContentSize(CCSizeMake(markrside, markrside));
    uR->setPosition(ccp(boxSize.width - markrside, boxSize.height - markrside));
    uR->setAnchorPoint(ccp(0, 0));
    addChild(box);
	//定义几种动画,分别为扭曲,旋转,缩放。
    CCActionInterval *actionTo = CCSkewTo::create(2, 0.f, 2.f);
    CCActionInterval *rotateTo = CCRotateTo::create(2, 61.0f);
    CCActionInterval *actionScaleTo = CCScaleTo::create(2, -0.44f, 0.47f);

    CCActionInterval *actionScaleToBack = CCScaleTo::create(2, 1.0f, 1.0f);
    CCActionInterval *rotateToBack = CCRotateTo::create(2, 0);
    CCActionInterval *actionToBack = CCSkewTo::create(2, 0, 0);
	//让颜色层同时演示三个动画序列。这里要理解为什么它可以同时演示多个动画序列?我们之前将过runAction会将演员和动画通知动画管理器,这些动画会存入相应的动画集,动画管理器在每帧会更新相应的动画,这里虽然用的是动画序列,但是动画序列本身仍然是动画。所以调用多次runAction可以将多个动画或动画序列同时播放。
    box->runAction(CCSequence::create(actionTo, actionToBack, NULL));
    box->runAction(CCSequence::create(rotateTo, rotateToBack, NULL));
    box->runAction(CCSequence::create(actionScaleTo, actionScaleToBack, NULL));
}
//取得副标题。
string ActionSkewRotateScale::subtitle()
{
    return "Skew + Rotate + Scale";
}

//第七种动画演示表现的是如何让演员们按照抛物线跳跃。
class ActionJump : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionJump::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//将三个演员按居中对齐进行站位
    centerSprites(3);
	//定义一个动画,代表跳跃到某个位置
    CCActionInterval*  actionTo = CCJumpTo::create(2, CCPointMake(300,300), 50, 4);
	//定义一个动画,代表从现在的位置跳跃多远距离。
    CCActionInterval*  actionBy = CCJumpBy::create(2, CCPointMake(300,0), 50, 4);
	//定义一个只是向上跳的动画
    CCActionInterval*  actionUp = CCJumpBy::create(2, CCPointMake(0,0), 80, 4);
	//定义第二个动画的反向播放动画
    CCActionInterval*  actionByBack = actionBy->reverse();
	//三位演员分别运行相应动画。
    m_tamara->runAction( actionTo);
    m_grossini->runAction( CCSequence::create(actionBy, actionByBack, NULL));
	//CCRepeatForever是一个无限循环动画。它将指定的动画进行无限循环播放。
    m_kathia->runAction( CCRepeatForever::create(actionUp));
}
//显示副标题。
std::string ActionJump::subtitle()
{
    return "JumpTo / JumpBy";
}

//第八种动画演示表现的是让演员们按照贝塞尔曲线的路径运动。
class ActionBezier : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionBezier::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//取得屏幕大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();

	//将三位演员按居中对齐进行站位
    centerSprites(3);

    // 创建第一个贝塞尔曲线
    ccBezierConfig bezier;
    bezier.controlPoint_1 = CCPointMake(0, s.height/2);
    bezier.controlPoint_2 = CCPointMake(300, -s.height/2);
    bezier.endPosition = CCPointMake(300,100);
	//创建一个贝塞尔曲线动画,这个CCBezierBy的意思是当前位置为曲线起点。曲线的其它点是相对于它的位置。
    CCActionInterval*  bezierForward = CCBezierBy::create(3, bezier);
	//创建上面动画的反向播放动画。
    CCActionInterval*  bezierBack = bezierForward->reverse();    
	//创建一个无限循环动画序列,这个动画序列由上面两个动画组成。    CCAction*  rep = CCRepeatForever::create((CCActionInterval*)CCSequence::create( bezierForward, bezierBack, NULL));


    // 创建第二个贝塞尔曲线
	// 设置一下女一号的当前位置。
    m_tamara->setPosition(CCPointMake(80,160));
    ccBezierConfig bezier2;
    bezier2.controlPoint_1 = CCPointMake(100, s.height/2);
    bezier2.controlPoint_2 = CCPointMake(200, -s.height/2);
    bezier2.endPosition = CCPointMake(240,160);
	//创建一个贝塞尔曲线动画,这个CCBezierTo的意思是演员当前位置为曲线起点。曲线的其它点是屏幕的绝对位置。
    CCActionInterval*  bezierTo1 = CCBezierTo::create(2, bezier2);    

    //设置一下女二号的当前位置。创建相同的动画。
    m_kathia->setPosition(CCPointMake(400,160));
	//如果刚才的ActionRotate 您理解的透彻,那这里其实也可以改成:CCActionInterval*  bezierTo2 = (CCActionInterval*)(bezierTo1->copy()->autorelease());

    CCActionInterval*  bezierTo2 = CCBezierTo::create(2, bezier2);
	//三位演员开始动画演示。
    m_grossini->runAction( rep);
    m_tamara->runAction(bezierTo1);
    m_kathia->runAction(bezierTo2);

}
//显示副标题。
std::string ActionBezier::subtitle()
{
    return "BezierBy / BezierTo";
}

//第九种动画演示表现的是演员们玩“我闪我闪乱你眼”
class ActionBlink : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionBlink::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//将二位女演员按居中对齐进行站位
    centerSprites(2);
	//这个CCBlink的create简单,就是指定几秒内共闪动几次。
    CCActionInterval*  action1 = CCBlink::create(2, 10);
    CCActionInterval*  action2 = CCBlink::create(2, 5);
	//两位演员开始表演“闪闪惹人爱”
    m_tamara->runAction( action1);
    m_kathia->runAction(action2);
}
//显示副标题。
std::string  ActionBlink::subtitle()
{
    return "Blink";
}


//第十种动画演示表现的是演员们淡入淡出
class ActionFade : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionFade::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//将二位女演员按居中对齐进行站位
    centerSprites(2);
	//设置女一号的透明度为0
    m_tamara->setOpacity( 0 );
	//CCFadeIn是一个淡入动画,参数为秒数。代表需要多久显示。
    CCActionInterval*  action1 = CCFadeIn::create(1.0f);
	//淡入的反向播放,其时是从算法上实现了淡出。
    CCActionInterval*  action1Back = action1->reverse();
	//CCFadeOut是一个淡出动画。参数为秒数。代表需要多久消融。
    CCActionInterval*  action2 = CCFadeOut::create(1.0f);
	//淡入的反向播放,其时是从算法上实现了淡入。
    CCActionInterval*  action2Back = action2->reverse();
	//两位女演员各自演员一个动画序列。
    m_tamara->runAction( CCSequence::create( action1, action1Back, NULL));
    m_kathia->runAction( CCSequence::create( action2, action2Back, NULL));
}
//显示副标题。
std::string  ActionFade::subtitle()
{
    return "FadeIn / FadeOut";
}

//第十一种动画演示表现的是演员们如何进行色彩渐变。
class ActionTint : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionTint::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//将二位女演员按居中对齐进行站位
    centerSprites(2);
	//创建三个变色动画,第一个是2秒时间变化到指定的色值。第二个是2秒时间从当前色彩状态变化多少色值,第三个是第二个动画的反向动画。
    CCActionInterval*  action1 = CCTintTo::create(2, 255, 0, 255);
    CCActionInterval*  action2 = CCTintBy::create(2, -127, -255, -127);
    CCActionInterval*  action2Back = action2->reverse();
	//女一号运行动画1。
    m_tamara->runAction( action1);
	//女二号运行一个动画序列,这个动画序列先运行动画2,然后运行动画3。
    m_kathia->runAction( CCSequence::create( action2, action2Back, NULL));
}

std::string  ActionTint::subtitle()
{
    return "TintTo / TintBy";
}


//第十二种动画演示表现的是演员的逐帧动作动画。
class ActionAnimate : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual void onExit();
    virtual std::string title();
    virtual std::string subtitle();
};
void ActionAnimate::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//将三位演员按居中对齐进行站位
    centerSprites(3);
	//创建一个序列帧动画。
    CCAnimation* animation = CCAnimation::create();
	//载入15张图片做为每帧显示的精灵图片。
    for( int i=1;i<15;i++)
    {
        char szName[100] = {0};
        sprintf(szName, "Images/grossini_dance_%02d.png", i);
        animation->addSpriteFrameWithFileName(szName);
    }
    //设置帧间隔时间。
    animation->setDelayPerUnit(2.8f / 14.0f);
	//设置动画结束后保持初始帧数据不进行释放。
    animation->setRestoreOriginalFrame(true);
	//创建序列帧动画。
    CCAnimate* action = CCAnimate::create(animation);
	//男一号动行一个动画序列,这个动画序列先播放一遍序列帧动画,然后再反向播放一遍序列帧动画。
    m_grossini->runAction(CCSequence::create(action, action->reverse(), NULL));
    
    //下面演示了通过一个plist文件来播放一个序列帧动画。
	//先取得序列帧动画管理器。
    CCAnimationCache *cache = CCAnimationCache::sharedAnimationCache();
	//加载一个plist文件
    cache->addAnimationsWithFile("animations/animations-2.plist");
	//取得plist文件中的对应序列帧动画信息
    CCAnimation *animation2 = cache->animationByName("dance_1");
	//以此信息创建一个序列帧动画。
    CCAnimate* action2 = CCAnimate::create(animation2);
	//女一号运行一个动画序列,这个动画序列先播放一遍序列帧动画,然后再反向播放一遍序列帧动画。
    m_tamara->runAction(CCSequence::create(action2, action2->reverse(), NULL));

	//产生一个plist文件中的对应序列帧动画信息的拷贝
    CCAnimation *animation3 = (CCAnimation *)animation2->copy()->autorelease();
	//设置动画信息中的动画循环次数
    animation3->setLoops(4);
	//以此信息创建一个序列帧动画。
    CCAnimate* action3 = CCAnimate::create(animation3);
	//女二号运行此动画。
    m_kathia->runAction(action3);
}

void ActionAnimate::onExit()
{
    ActionsDemo::onExit();
    //TODO:[[NSNotificationCenter defaultCenter] removeObserver:observer_];
}

std::string ActionAnimate::title()
{
    return "Animation";
}

std::string ActionAnimate::subtitle()
{
    return "Center: Manual animation. Border: using file format animation";
}

//第十三种动画演示的是多种动画如何组成动画序列。
class ActionSequence : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};

void ActionSequence::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要男一号上场
    alignSpritesLeft(1);
	//创建一个动画序列,先运行一个移动动画,再运行一个旋转动画。
    CCFiniteTimeAction*  action = CCSequence::create(
        CCMoveBy::create( 2, CCPointMake(240,0)),
        CCRotateBy::create( 2,  540),
        NULL);
	//男一号演示此动画。
    m_grossini->runAction(action);
}

std::string ActionSequence::subtitle()
{
    return "Sequence: Move + Rotate";
}

//第十四种动画演示表现的是如何使多种动画在组成动画序列中能够进行响应控制。
class ActionSequence2 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();

    void callback1();
    void callback2(CCNode* sender);
    void callback3(CCNode* sender, void* data);
};
void ActionSequence2::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要男一号上场
    alignSpritesLeft(1);
	//男一号设置不显示
    m_grossini->setVisible(false);
	//创建一个序列动画。这个序列动画包含了一些动画和回调函数, CCCallFunc为不带参数的回调函数,CCCallFuncN为以演示当前动画的演员为参数的回调函数,CCCallFuncND为以演示当前动画的演员和一个用户输入值为参数的回调函数。
    CCFiniteTimeAction*  action = CCSequence::create(
        CCPlace::create(CCPointMake(200,200)),
        CCShow::create(),
        CCMoveBy::create(1, CCPointMake(100,0)),
        CCCallFunc::create(this, callfunc_selector(ActionSequence2::callback1)),
        CCCallFuncN::create(this, callfuncN_selector(ActionSequence2::callback2)),
        CCCallFuncND::create(this, callfuncND_selector(ActionSequence2::callback3), (void*)0xbebabeba),
        NULL);
	//男一号运行此动画序列。
    m_grossini->runAction(action);
}
//不带参数的回调函数
void ActionSequence2::callback1()
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 1 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*1,s.height/2));

    addChild(label);
}
//以演示当前动画的演员为参数的回调函数
void ActionSequence2::callback2(CCNode* sender)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 2 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*2,s.height/2));

    addChild(label);
}
//以演示当前动画的演员和一个用户输入值为参数的回调函数
void ActionSequence2::callback3(CCNode* sender, void* data)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 3 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*3,s.height/2));

    addChild(label);
}

std::string ActionSequence2::subtitle()
{
    return "Sequence of InstantActions";
}

//第十五种动画演示表现的是几种动画的并行,即如何同时进行多种动画。
class ActionSpawn : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionSpawn::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要男一号上场
    alignSpritesLeft(1);
	//创建一个动画组合,使用方法与动画序列类似了,这里同时播放了跳跃和旋转的动画。
    CCAction*  action = CCSpawn::create(
        CCJumpBy::create(2, CCPointMake(300,0), 50, 4),
        CCRotateBy::create( 2,  720),
        NULL);
	//让男一行运行此动画组合。
    m_grossini->runAction(action);
}

std::string ActionSpawn::subtitle()
{
    return "Spawn: Jump + Rotate";
}

//第十六种动画演示表现的是动画的倒退重播,就像你看DVD按着后退键。
class ActionReverse : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionReverse::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要男一号上场
    alignSpritesLeft(1);
	//创建一个跳跃动画。
    CCActionInterval*  jump = CCJumpBy::create(2, CCPointMake(300,0), 50, 4);
	//创建一个动画序列,先运行上面的跳跃动画,再运其反向动画。
    CCFiniteTimeAction*  action = CCSequence::create( jump, jump->reverse(), NULL);
	//男一号运行动画。
    m_grossini->runAction(action);
}

std::string ActionReverse::subtitle()
{
    return "Reverse an action";
}

//第十七种动画演示表现的是动画的暂停与继续播放。
class ActionDelayTime : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionDelayTime::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要男一号上场
    alignSpritesLeft(1);
	//创建一个移动动画。
    CCActionInterval*  move = CCMoveBy::create(1, CCPointMake(150,0));
	//创建一个动画序列,先播放移动动画,再暂停2秒,然后再播放移动动画。
    CCFiniteTimeAction*  action = CCSequence::create( move, CCDelayTime::create(2), move, NULL);
	//男一行运行此动画序列。
    m_grossini->runAction(action);
}

std::string ActionDelayTime::subtitle()
{
    return "DelayTime: m + delay + m";
}


//第十八种动画演示表现的是动画的重复播放。
class ActionRepeat : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionRepeat::onEnter()
{	//动画演示的初始化
    ActionsDemo::onEnter();
	//两位演员上场
    alignSpritesLeft(2);
	//创建一个移动动画。
    CCActionInterval*  a1 = CCMoveBy::create(1, CCPointMake(150,0));
	//创建一个循环3次的序列动画。序列动画先设置精灵位置在60,60,然后播放上面的移动动画。
    CCActionInterval*  action1 = CCRepeat::create(
        CCSequence::create( CCPlace::create(CCPointMake(60,60)), a1, NULL) , 
        3); 
	//创建一个无限循环动画。这个无限循环的动画是一个动画序列,先播放第一个移动动画,再播放其反向动画。
    CCAction*  action2 = CCRepeatForever::create(
        (CCActionInterval*)(CCSequence::create((CCActionInterval*)(a1->copy()->autorelease()), a1->reverse(), NULL))
        );
	//女二号播放循环3次的序列动画
    m_kathia->runAction(action1);
	//女一号播放无限循环动画。
    m_tamara->runAction(action2);
}

std::string ActionRepeat::subtitle()
{
    return "Repeat / RepeatForever actions";
}

//第十九种动画演示表现的是动画的无限循环旋转。
class ActionRepeatForever : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();

    void repeatForever(CCNode* pTarget);
};
void ActionRepeatForever::onEnter()
{	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要男一号上场
    centerSprites(1);
	//创建一个动画序列,先暂停1秒,然后调用
    CCFiniteTimeAction*  action = CCSequence::create(
        CCDelayTime::create(1),
        CCCallFuncN::create( this, callfuncN_selector(ActionRepeatForever::repeatForever) ), 
        NULL);
	//男一号运行此动画。
    m_grossini->runAction(action);
}
//回调函数。
void ActionRepeatForever::repeatForever(CCNode* pSender)
{
	//创建一个无限循环的旋转动画。
    CCRepeatForever *repeat = CCRepeatForever::create( CCRotateBy::create(1.0f, 360) );
	//让男一号运行此无限循环动画。
    pSender->runAction(repeat);
}

std::string ActionRepeatForever::subtitle()
{
    return "CallFuncN + RepeatForever";
}


//第二十种动画演示表现的是动画的无限循环旋转到某个角度。
class ActionRotateToRepeat : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionRotateToRepeat::onEnter()
{	//动画演示的初始化
    ActionsDemo::onEnter();
	//需要两位演员
    centerSprites(2);
	//创建一个1秒内旋转到90度的动画
    CCActionInterval*  act1 = CCRotateTo::create(1, 90);
	//创建一个1秒内旋转到0度的动画
	CCActionInterval*  act2 = CCRotateTo::create(1, 0);
	//创建一个动画序列,先运行动动画1,再运行动画2
    CCActionInterval*  seq = (CCActionInterval*)(CCSequence::create(act1, act2, NULL));
	//创建一个无限循环播放动画序列的动画。
	CCAction*  rep1 = CCRepeatForever::create(seq);
	//创建一个循环10次播放动画序列的动画。
    CCActionInterval*  rep2 = CCRepeat::create((CCFiniteTimeAction*)(seq->copy()->autorelease()), 10);
	//两位演员分别播放相应的循环动画。
    m_tamara->runAction(rep1);
    m_kathia->runAction(rep2);
}

std::string ActionRotateToRepeat ::subtitle()
{
    return "Repeat/RepeatForever + RotateTo";
}

//第二十一种动画演示表现的是动画的旋转与反向旋转。
class ActionRotateJerk : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionRotateJerk::onEnter()
{	//动画演示的初始化
    ActionsDemo::onEnter();
	//需要两位演员
    centerSprites(2);
	//创建一个动画序列,先播放一个0.5秒旋转到-20度的动画,再播放一个0.5秒旋转到20度的动画。
    CCFiniteTimeAction*  seq = CCSequence::create(
        CCRotateTo::create(0.5f, -20),
        CCRotateTo::create(0.5f, 20),
        NULL);
	//创建一个循环播放10次上面的动画序列的循环动画。
	CCActionInterval*  rep1 = CCRepeat::create(seq, 10);
	//创建一个无限循环播放上面的动画序列的循环动画。
    CCAction*  rep2 = CCRepeatForever::create( (CCActionInterval*)(seq->copy()->autorelease()) );
	//两位演员分别播放各自的循环动画。
    m_tamara->runAction(rep1);
    m_kathia->runAction(rep2);
}

std::string ActionRotateJerk::subtitle()
{
    return "RepeatForever / Repeat + Rotate";
}

//第二十二种动画演示表现的是动画过程中的函数响应。
class ActionCallFunc : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();

    void callback1();
    void callback2(CCNode* pTarget);
    void callback3(CCNode* pTarget, void* data);
};
void ActionCallFunc::onEnter()
{	//动画演示的初始化
    ActionsDemo::onEnter();
	//需要三位演员
    centerSprites(3);
	//创建一个动画序列,先播放一个2秒横向移动200的动画,然后调用一个回调函数。
    CCFiniteTimeAction*  action = CCSequence::create(
        CCMoveBy::create(2, CCPointMake(200,0)),
        CCCallFunc::create(this, callfunc_selector(ActionCallFunc::callback1)), 
        NULL);
	//创建一个动画序列,先播放一个2秒放大2倍的动画,再播放一个2秒的淡出动画,之后调用一个回调函数。
    CCFiniteTimeAction*  action2 = CCSequence::create(
        CCScaleBy::create(2 ,  2),
        CCFadeOut::create(2),
        CCCallFuncN::create(this, callfuncN_selector(ActionSequence2::callback2)), 
        NULL);
	//创建一个动画序列,先播放一个3秒内旋转360度的动画,然后是一个2秒内淡出的动画,之后调用一个回调函数。
    CCFiniteTimeAction*  action3 = CCSequence::create(
        CCRotateBy::create(3 , 360),
        CCFadeOut::create(2),
        CCCallFuncND::create(this, callfuncND_selector(ActionSequence2::callback3), (void*)0xbebabeba), 
        NULL);
	//三位演员分别演示相应的动画。
    m_grossini->runAction(action);
    m_tamara->runAction(action2);
    m_kathia->runAction(action3);
}

//第一个回调函数。
void ActionCallFunc::callback1()
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 1 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*1,s.height/2));

    addChild(label);
}
//第二个回调函数。
void ActionCallFunc::callback2(CCNode* pSender)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 2 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*2,s.height/2));

    addChild(label);
}
//第三个回调函数。
void ActionCallFunc::callback3(CCNode* pTarget, void* data)
{
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    CCLabelTTF *label = CCLabelTTF::create("callback 3 called", "Marker Felt", 16);
    label->setPosition(CCPointMake( s.width/4*3,s.height/2));
    addChild(label);
}

std::string ActionCallFunc::subtitle()
{
    return "Callbacks: CallFunc and friends";
}

//第二十二种动画演示表现的是动画过程中的带参数的函数响应。
class ActionCallFuncND : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string title();
    virtual std::string subtitle();
    void removeFromParentAndCleanup(CCNode* pSender, void* data);
};
void ActionCallFuncND::onEnter()
{	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要男演员上场。
    centerSprites(1);
	//创建一个动画序列,首先播放一个2秒横向移动200的动画,然后调用一个回调函数,可带一个参数true。
    CCFiniteTimeAction* action = CCSequence::create(CCMoveBy::create(2.0f, ccp(200,0)),
        CCCallFuncND::create(this, callfuncND_selector(ActionCallFuncND::removeFromParentAndCleanup), (void*)true),
        NULL);
	//男演员演示动画
    m_grossini->runAction(action);
}

std::string ActionCallFuncND::title()
{
    return "CallFuncND + auto remove";
}

std::string ActionCallFuncND::subtitle()
{
    return "CallFuncND + removeFromParentAndCleanup. Grossini dissapears in 2s";
}
//带参数的回调函数。data在这里为true。
void ActionCallFuncND::removeFromParentAndCleanup(CCNode* pSender, void* data)
{
    bool bCleanUp = data != NULL;
    m_grossini->removeFromParentAndCleanup(bCleanUp);
}

//第二十三种动画演示表现的是动画的序列播放与反向序列播放。
class ActionReverseSequence : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionReverseSequence::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要男演员上场。
    alignSpritesLeft(1);
	//创建一个移动动画。
	CCActionInterval*  move1 = CCMoveBy::create(1, CCPointMake(250,0));
	//创建第二个移动动画。
	CCActionInterval*  move2 = CCMoveBy::create(1, CCPointMake(0,50));
	//创建一个动画序列,首先播放第一个移动动画,再播放第二个移动动画,最后播放第一个移动动画的反向动画。
    CCFiniteTimeAction*  seq = CCSequence::create( move1, move2, move1->reverse(), NULL);
	//创建一个动画序列,先播放第一个动画序列,然后播放这个动画序列的反向动画序列。
    CCFiniteTimeAction*  action = CCSequence::create( seq, seq->reverse(), NULL);
	//男演员演示这个动画序列。
    m_grossini->runAction(action);
}

std::string ActionReverseSequence::subtitle()
{
    return "Reverse a sequence";
}

//第二十四种动画演示表现的是动画的序列播放与反向序列播放。
class ActionReverseSequence2 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionReverseSequence2::onEnter()
{	//动画演示的初始化
    ActionsDemo::onEnter();
	//需要两位演员。
    alignSpritesLeft(2);
    //创建一个移动动画。
	CCActionInterval*  move1 = CCMoveBy::create(1, CCPointMake(250,0));
	//创建第二个移动动画。
	CCActionInterval*  move2 = CCMoveBy::create(1, CCPointMake(0,50));
	//创建两个精灵显示隐藏切换动画。这个动画会判断精灵显示状态,如果显示则切换为隐藏,如果隐藏则切换为显示。
    CCToggleVisibility*  tog1 = new CCToggleVisibility();
    CCToggleVisibility*  tog2 = new CCToggleVisibility();
    tog1->autorelease();
	tog2->autorelease();
	//创建动画序列,先播第一个移动动画,然后隐藏,然后播第二个移动动画,然后显示,再播第一个移动动画的反向动画。
	CCFiniteTimeAction*  seq = CCSequence::create( move1, tog1, move2, tog2, move1->reverse(), NULL);
	//创建第二个动画序列,先播放第一个动画序列,再播放它的反向动画序列。
    CCActionInterval*  action = CCRepeat::create((CCActionInterval*)(CCSequence::create( seq, seq->reverse(), NULL)), 3);



    //女二号播放第二个动画序列.
    m_kathia->runAction(action);
	//创建一个移动动画。
	CCActionInterval*  move_tamara = CCMoveBy::create(1, CCPointMake(100,0));
	//创建第二个移动动画。
	CCActionInterval*  move_tamara2 = CCMoveBy::create(1, CCPointMake(50,0));
	//创建一个隐藏动画,这个动画的过程中精灵是处于隐藏状态。
    CCActionInstant*  hide = new CCHide();
	hide->autorelease();
	//创建一个动画序列,先运行第一个移动动画,然后隐动画,最后第二个移动动画。
	CCFiniteTimeAction*  seq_tamara = CCSequence::create( move_tamara, hide, move_tamara2, NULL);
	//创建动画序列的反向动画序列。
	CCFiniteTimeAction*  seq_back = seq_tamara->reverse();
	//女一号运行一个动画序列,这个动画序列会先运行第一个动画序列,然后再运行它的反向动画序列。
    m_tamara->runAction( CCSequence::create( seq_tamara, seq_back, NULL));
}
std::string ActionReverseSequence2::subtitle()
{
    return "Reverse sequence 2";
}

//第二十五种动画演示表现的是旋转摄像机动画,这时会用到摄像机球型运动算法,摄像机会处在一个以目标物为球心的球体表面,其可以在球体表面上绕横向和纵向轴旋转。
class ActionOrbit : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionOrbit::onEnter()
{	//动画演示的初始化
    ActionsDemo::onEnter();
	//需要三位演员。
    centerSprites(3);
	//创建第一个旋转摄像机动画。
	//创建的这个动画为2秒内在半径为1的球面上绕纵向轴转180度。
	CCActionInterval*  orbit1 = CCOrbitCamera::create(2,1, 0, 0, 180, 0, 0);
	//创建第一个动画序列,先运行摄像机动画,再运行它的反向动画。
    CCFiniteTimeAction*  action1 = CCSequence::create(
        orbit1,
        orbit1->reverse(),
        NULL);
	//创建第二个旋转摄像机动画以及动画序列。
	//创建的这个动画为2秒内在半径为1的球面上,位置点在横向轴旋转-45度,然后动画过程会沿以旋转后的坐标系在纵向轴转180度。
    CCActionInterval*  orbit2 = CCOrbitCamera::create(2,1, 0, 0, 180, -45, 0);
    CCFiniteTimeAction*  action2 = CCSequence::create(
        orbit2,
        orbit2->reverse(),
        NULL);
	//创建第三个旋转摄像机动画及动画序列。
	//创建的这个动画为2秒内在半径为1的球面上,位置点在横向轴旋转90度,然后动画过程会沿以旋转后的坐标系在纵向轴转180度,注意,这时候在世界坐标系中看,其实是沿横向轴转180度~!
    CCActionInterval*  orbit3 = CCOrbitCamera::create(2,1, 0, 0, 180, 90, 0);
    CCFiniteTimeAction*  action3 = CCSequence::create(
        orbit3,
        orbit3->reverse(),
        NULL);

   	//三位演员分别播放相应的无限循环动画。 m_kathia->runAction(CCRepeatForever::create((CCActionInterval*)action1));
    m_tamara->runAction(CCRepeatForever::create((CCActionInterval*)action2));
    m_grossini->runAction(CCRepeatForever::create((CCActionInterval*)action3));
	//创建一个移动动画。
	CCActionInterval*  move = CCMoveBy::create(3, CCPointMake(100,-100));
	//创建这个移动动画的反向动画。
	CCActionInterval*  move_back = move->reverse();
	//将这两个动画放到一个动画序列中。
	CCFiniteTimeAction*  seq = CCSequence::create(move, move_back, NULL);
	//创建一个无限循环动画,播放这个动画序列。
	CCAction*  rfe = CCRepeatForever::create((CCActionInterval*)seq);
	//三位演员要同时播放这个无限循环动画。
    m_kathia->runAction(rfe);
    m_tamara->runAction((CCAction*)(rfe->copy()->autorelease()));
    m_grossini->runAction((CCAction*)(rfe->copy()->autorelease()));
}

std::string ActionOrbit::subtitle()
{
    return "OrbitCamera action";
}


//第二十六种动画演示表现的是跟随动画。
class ActionFollow : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
};
void ActionFollow::onEnter()
{
	//动画演示的初始化
    ActionsDemo::onEnter();
	//只需要一位演员上场
	centerSprites(1);
	//取得可视区域的大小
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//男一号设置位置。
	m_grossini->setPosition(CCPointMake(-200, s.height / 2));
	//创建一个移动动画。
	CCActionInterval* move      = CCMoveBy::create(2, CCPointMake(s.width * 3, 0));
	//创建这个移动动画的反向动画。
	CCActionInterval* move_back = move->reverse();
	//创建一个动画序列,先播放移动动画,再播放其反向动画。
	CCFiniteTimeAction* seq       = CCSequence::create(move, move_back, NULL);
	//创建一个无限循环动画,播放这个动画序列。
    CCAction* rep               = CCRepeatForever::create((CCActionInterval*)seq);
	//男一号演员这个无限循环动画。
    m_grossini->runAction(rep);
	//当前层运行一个跟随动画,跟随男一号,并设置其包围区域。
    this->runAction(CCFollow::create(m_grossini, CCRectMake(0, 0, s.width * 2 - 100, s.height)));
}

std::string ActionFollow::subtitle()
{
    return "Follow action";
}

//第二十七种动画演示表现的是控制目标动画。
class ActionTargeted : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string title();
    virtual std::string subtitle();
};
void ActionTargeted::onEnter()
{	
	//动画演示的初始化
	ActionsDemo::onEnter();
	//需要两位演员上场
	centerSprites(2);
	//先创建一个跳跃动画。
	CCJumpBy* jump1 = CCJumpBy::create(2,CCPointZero,100,3);
	//再创建一个相同的跳跃动画。
	CCJumpBy* jump2 = (CCJumpBy*)jump1->copy()->autorelease();
	//创建一个旋转动画。
	CCRotateBy* rot1 =  CCRotateBy::create(1, 360);
	//再创建一个相同的旋转动画。
    CCRotateBy* rot2 = (CCRotateBy*)rot1->copy()->autorelease();
	//创建第一个控制目标动画,让女二号播放第二个跳跃动画。
	CCTargetedAction *t1 = CCTargetedAction::create(m_kathia, jump2);
	//创建第二个控制目标动画,让女二号播放第二个旋转动画。
    CCTargetedAction *t2 = CCTargetedAction::create(m_kathia, rot2);

	//创建一个动画序列,先播放一个第一个跳跃动画,再播放第一个控制目标动画,再播放第一个旋转动画,再播放第二个控制目标动画。
	CCSequence* seq = (CCSequence*)CCSequence::create(jump1, t1, rot1, t2, NULL);
	//创建一个无限循环动画,播放上面的动画序列。
    CCRepeatForever *always = CCRepeatForever::create(seq);
	//女一号运行这个无限循环动画。
    m_tamara->runAction(always);
}

std::string ActionTargeted::title()
{
    return "ActionTargeted";
}

std::string ActionTargeted::subtitle()
{
    return "Action that runs on another target. Useful for sequences";
}

//第二十八种动画演示表现的是1305号动画。
class Issue1305 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual void onExit();
    void log(CCNode* pSender);
    void addSprite(float dt);
    virtual std::string title();
    virtual std::string subtitle();
private:
    CCSprite* m_pSpriteTmp;
};
void Issue1305::onEnter()
{	
	//动画演示的初始化
	ActionsDemo::onEnter();
	//空无一人
    centerSprites(0);
	//创建一个精灵
    m_pSpriteTmp = CCSprite::create("Images/grossini.png");
	//让精灵运行一个回调函数打印一个日志。注意:在这里没有让精灵加入当前Layer,所以它不会真正的runAction,必须等它被挂在Layer下后才能被遍历更新。
	
	m_pSpriteTmp->runAction(CCCallFuncN::create(this, callfuncN_selector(Issue1305::log)));
	//占用精灵,故引用计数加一。
    m_pSpriteTmp->retain();
	//当前结点在2秒后调用回调函数增加一个精灵。
    scheduleOnce(schedule_selector(Issue1305::addSprite), 2);
}
//精灵调用的回调函数。
void Issue1305::log(CCNode* pSender)
{
    CCLog("This message SHALL ONLY appear when the sprite is added to the scene, NOT BEFORE");
}

void Issue1305::onExit()
{
    m_pSpriteTmp->release();
    ActionsDemo::onExit();
}

void Issue1305::addSprite(float dt)
{
	//在这里设置精灵的位置并将其加入到当前的Layer下。
    m_pSpriteTmp->setPosition(ccp(250,250));
    addChild(m_pSpriteTmp);
}

上面这个动画运行后,等2秒创建出精灵,然后动作管理器才能执行精灵运行的函数打印日志,输出到Output窗口。

Cocos2d-x 2.0 之 Actions “三板斧” 之三

std::string Issue1305::title()
{
    return "Issue 1305";
}

std::string Issue1305::subtitle()
{
    return "In two seconds you should see a message on the console. NOT BEFORE.";
}
//第二十九种动画演示表现的是1305号动画二。
class Issue1305_2 : public ActionsDemo
{
public:
    virtual void onEnter();
    void log1();
    void log2();
    void log3();
    void log4();
    virtual std::string title();
    virtual std::string subtitle();
};
void Issue1305_2::onEnter()
{
	//动画演示的初始化
	ActionsDemo::onEnter();
	//不需要演员上场
    centerSprites(0);
	//创建一个精灵.加载一个图。
	CCSprite *spr = CCSprite::create("Images/grossini.png");
	//设置位置
	spr->setPosition(ccp(200,200));
	//加入当前Layer。
    addChild(spr);
	//创建一个移动动画。
    CCMoveBy* act1 = CCMoveBy::create(2 ,ccp(0, 100));
   	//创建一个回调函数。
	CCCallFunc* act2 = CCCallFunc::create(this, callfunc_selector(Issue1305_2::log1)) ;
	//创建第二个移动动画。
	CCMoveBy* act3 = CCMoveBy::create(2, ccp(0, -100));
	//创建第二个回调函数。
	CCCallFunc* act4 = CCCallFunc::create(this, callfunc_selector(Issue1305_2::log2)) ;
	//创建第三个移动动画。
	CCMoveBy* act5 = CCMoveBy::create(2, ccp(100, -100));
	//创建第三个回调函数。
	CCCallFunc* act6 = CCCallFunc::create(this, callfunc_selector(Issue1305_2::log3)) ;
	//创建第四个移动动画。
	CCMoveBy* act7 = CCMoveBy::create(2, ccp(-100, 0));
	//创建第四个回调函数。
    CCCallFunc* act8 = CCCallFunc::create(this, callfunc_selector(Issue1305_2::log4)) ;
	//创建一个动画序列,将前面的动画都顺序包含进来。
    CCFiniteTimeAction* actF = CCSequence::create(act1, act2, act3, act4, act5, act6, act7, act8, NULL);

   //通过动画管理器来指定精灵播放动画序列。    CCDirector::sharedDirector()->getActionManager()->addAction(actF ,spr, false);

}

void Issue1305_2::log1()
{
    CCLog("1st block");
}

void Issue1305_2::log2()
{
    CCLog("2nd block");
}

void Issue1305_2::log3()
{
    CCLog("3rd block");
}

void Issue1305_2::log4()
{
    CCLog("4th block");
}

std::string Issue1305_2::title()
{
    return "Issue 1305 #2";
}

std::string Issue1305_2::subtitle()
{
    return "See console. You should only see one message for each block";
}
//第三十种动画演示表现的是1288号动画。
class Issue1288 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string title();
    virtual std::string subtitle();
};
void Issue1288::onEnter()
{
	//动画演示的初始化
	ActionsDemo::onEnter();
	//不需要演员上场。
    centerSprites(0);
	//创建一个精灵,设置其位置并加入当前Layer。
    CCSprite *spr = CCSprite::create("Images/grossini.png");
    spr->setPosition(ccp(100, 100));
    addChild(spr);
	//创建两个移动动画。
    CCMoveBy* act1 = CCMoveBy::create(0.5, ccp(100, 0));
	CCMoveBy* act2 = (CCMoveBy*)act1->reverse();
	//将两个动画放入一个新创建的动画序列。
	CCFiniteTimeAction* act3 = CCSequence::create(act1, act2, NULL);
	//创建一个循环2次播放动画序列的动画。
    CCRepeat* act4 = CCRepeat::create(act3, 2);
	//让精灵播放这个循环2次播放动画序列的动画。
    spr->runAction(act4);
}

std::string Issue1288::title()
{
    return "Issue 1288";
}

std::string Issue1288::subtitle()
{
    return "Sprite should end at the position where it started.";
}
//第三十种动画演示表现的是1288号动画二。
class Issue1288_2 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string title();
    virtual std::string subtitle();
};
void Issue1288_2::onEnter()
{
	//动画演示的初始化
	ActionsDemo::onEnter();
	//不需要演员上场。
    centerSprites(0);
	//创建一个精灵,设置其位置并加入当前Layer。
    CCSprite *spr = CCSprite::create("Images/grossini.png");
    spr->setPosition(ccp(100, 100));
    addChild(spr);
	//创建一个移动动画。
	CCMoveBy* act1 = CCMoveBy::create(0.5, ccp(100, 0));
	//创建一个循环播放1次上面的移动动画,并让精灵运行它。
    spr->runAction(CCRepeat::create(act1, 1));
}

std::string Issue1288_2::title()
{
    return "Issue 1288 #2";
}

std::string Issue1288_2::subtitle()
{
    return "Sprite should move 100 pixels, and stay there";
}
//第三十一种动画演示表现的是1327号动画。
class Issue1327 : public ActionsDemo
{
public:
    virtual void onEnter();
    virtual std::string subtitle();
    virtual std::string title();
    void logSprRotation(CCNode* pSender);
};
void Issue1327::onEnter()
{
	//动画演示的初始化
	ActionsDemo::onEnter();
	//不需要演员上场。
    centerSprites(0);
	//创建一个精灵,设置其位置并加入当前Layer。
    CCSprite *spr = CCSprite::create("Images/grossini.png");
    spr->setPosition(ccp(100, 100));
    addChild(spr);
	//又是一堆回调函数和旋转动画。
    CCCallFuncN* act1 = CCCallFuncN::create(this, callfuncN_selector(Issue1327::logSprRotation));
    CCRotateBy* act2 = CCRotateBy::create(0.25, 45);
    CCCallFuncN* act3 = CCCallFuncN::create(this, callfuncN_selector(Issue1327::logSprRotation));
    CCRotateBy* act4 = CCRotateBy::create(0.25, 45);
    CCCallFuncN* act5 = CCCallFuncN::create(this, callfuncN_selector(Issue1327::logSprRotation));
    CCRotateBy* act6 = CCRotateBy::create(0.25, 45);
    CCCallFuncN* act7 = CCCallFuncN::create(this, callfuncN_selector(Issue1327::logSprRotation));
    CCRotateBy* act8 = CCRotateBy::create(0.25, 45);
    CCCallFuncN* act9 = CCCallFuncN::create(this, callfuncN_selector(Issue1327::logSprRotation));
	//创建一个动画序列,将上面9个动画顺序放入。
	CCFiniteTimeAction* actF = CCSequence::create(act1, act2, act3, act4, act5, act6, act7, act8, act9, NULL);
	//精灵运行这个动画序列。
    spr->runAction(actF);
}

std::string Issue1327::title()
{
    return "Issue 1327";
}

std::string Issue1327::subtitle()
{
    return "See console: You should see: 0, 45, 90, 135, 180";
}

void Issue1327::logSprRotation(CCNode* pSender)
{
    CCLog("%f", ((CCSprite*)pSender)->getRotation());
}
//第三十二种动画演示表现的是由点构成的曲线动画。
class ActionCatmullRom : public ActionsDemo
{
public:
    ~ActionCatmullRom();
    
    virtual void onEnter();
    virtual void draw();
    virtual std::string subtitle();
    virtual std::string title();
private:
    CCPointArray *m_pArray1;
    CCPointArray *m_pArray2;
};
void ActionCatmullRom::onEnter()
{	//动画演示初始化
    ActionsDemo::onEnter();
    //2位演员上场
    this->centerSprites(2);
    //取得可视区域大小。
    CCSize s = CCDirector::sharedDirector()->getWinSize();
    //女一号设置位置。
    m_tamara->setPosition(ccp(50, 50));
	//创建一个位置点数组,初始化数组大小为20.
    CCPointArray *array = CCPointArray::create(20);
    //放入一堆位置点。
    array->addControlPoint(ccp(0, 0));
    array->addControlPoint(ccp(80, 80));
    array->addControlPoint(ccp(s.width - 80, 80));
    array->addControlPoint(ccp(s.width - 80, s.height - 80));
    array->addControlPoint(ccp(80, s.height - 80));
    array->addControlPoint(ccp(80, 80));
    array->addControlPoint(ccp(s.width / 2, s.height / 2));
    //创建一个3秒钟按点数组构成的曲线移动的动画,位置点为相对位置。
	CCCatmullRomBy *action = CCCatmullRomBy::create(3, array);
	//创建它的反向动画。
    CCFiniteTimeAction *reverse = action->reverse();
	//创建一个动画序列,将原动画和反向动画顺序放入。
    CCFiniteTimeAction *seq = CCSequence::create(action, reverse, NULL);
	//女一号运行这个动画序列。
    m_tamara->runAction(seq);
	
	
	//再创建一个位置点数组。
    CCPointArray *array2 = CCPointArray::create(20);
    //又放入一堆位置点。
    array2->addControlPoint(ccp(s.width / 2, 30));
    array2->addControlPoint(ccp(s.width  -80, 30));
    array2->addControlPoint(ccp(s.width - 80, s.height - 80));
    array2->addControlPoint(ccp(s.width / 2, s.height - 80));
    array2->addControlPoint(ccp(s.width / 2, 30));
   //创建一个3秒钟按点数组构成的曲线移动的动画,位置点为绝对位置。
	CCCatmullRomTo *action2 = CCCatmullRomTo::create(3, array2);
	//创建它的反向动画。
    CCFiniteTimeAction *reverse2 = action2->reverse();
	//创建一个动画序列,将原动画和反向动画顺序放入。
    CCFiniteTimeAction *seq2 = CCSequence::create(action2, reverse2, NULL);
	
	//女二号运行这个动画序列。
    m_kathia->runAction(seq2);
    //将两个位置点数组的地址保存到成员指针变量,并对引用计数器加1防止被释放掉。
    m_pArray1 = array;
    m_pArray1->retain();
    m_pArray2 = array2;
    m_pArray2->retain();
}

ActionCatmullRom::~ActionCatmullRom()
{
	//当前演示层释放时,一并释放点数组。
    m_pArray1->release();
    m_pArray2->release();
}

void ActionCatmullRom::draw()
{
    ActionsDemo::draw();
    
	//绘制相对位置曲线
	//先将当前OPENGL的矩阵状态压栈
	kmGLPushMatrix();
	//移动到50,50点的位置
	kmGLTranslatef(50, 50, 0);
	//以这个点为原点绘制相对路径
	ccDrawCatmullRom(m_pArray1, 50);
	//恢复矩阵状态
	kmGLPopMatrix();

    //再绘制绝对位置的曲线
	ccDrawCatmullRom(m_pArray2,50);
}

string ActionCatmullRom::title()
{
    return "CatmullRomBy / CatmullRomTo";
}

string ActionCatmullRom::subtitle()
{
    return "Catmull Rom spline paths. Testing reverse too";
}
//第三十三种动画演示表现的是由点构成的贝塞尔曲线动画。
class ActionCardinalSpline : public ActionsDemo
{
public:
    ~ActionCardinalSpline();
    
    virtual void onEnter();
    virtual void draw();
    virtual std::string subtitle();
    virtual std::string title();
private:
    CCPointArray *m_pArray;
};
void ActionCardinalSpline::onEnter()
{
	//动画演示初始化
    ActionsDemo::onEnter();
    //2位演员上场
    this->centerSprites(2);
    //取得可视区域大小。
    CCSize s = CCDirector::sharedDirector()->getWinSize();
	//创建一个位置点数组,初始化数组大小为20.
    CCPointArray *array = CCPointArray::create(20);
    //放入一堆位置点。
    array->addControlPoint(ccp(0, 0));
    array->addControlPoint(ccp(s.width/2-30, 0));
    array->addControlPoint(ccp(s.width/2-30, s.height-80));
    array->addControlPoint(ccp(0, s.height-80));
    array->addControlPoint(ccp(0, 0));
    //创建一个3秒钟按点数组构成的贝塞尔曲线移动的动画,位置点为相对位置。
	CCCardinalSplineBy *action = CCCardinalSplineBy::create(3, array, 0);
	//创建它的反向动画。
    CCActionInterval *reverse = action->reverse();
	//创建一个动画序列,将原动画和反向动画顺序放入。
    CCFiniteTimeAction *seq = CCSequence::create(action, reverse, NULL);
	//女一号设置位置并运行此曲线动画。
    m_tamara->setPosition(ccp(50, 50));
    m_tamara->runAction(seq);
	
//创建一个3秒钟按点数组构成的贝塞尔曲线移动的动画,位置点为相对位置。    	CCCardinalSplineBy *action2 = CCCardinalSplineBy::create(3, array, 1);
	//创建它的反向动画。
    CCActionInterval *reverse2 = action2->reverse();
	//创建一个动画序列,将原动画和反向动画顺序放入。
    CCFiniteTimeAction *seq2 = CCSequence::create(action2, reverse2, NULL);
	//女二号设置位置并运行此曲线动画。
    m_kathia->setPosition(ccp(s.width/2, 50));
    m_kathia->runAction(seq2);
	//将位置点数组的地址保存到成员指针变量,并对引用计数器加1防止被释放掉。
    m_pArray = array;
    array->retain();
}

ActionCardinalSpline::~ActionCardinalSpline()
{
    m_pArray->release();
}

void ActionCardinalSpline::draw()
{
    ActionsDemo::draw();
	
	//绘制第一个相对位置曲线
	//先将当前OPENGL的矩阵状态压栈
	kmGLPushMatrix();
	//移动到50,50点的位置
	kmGLTranslatef(50, 50, 0);
	//以这个点为原点绘制相对路径
	ccDrawCardinalSpline(m_pArray, 0, 100);
	//恢复矩阵状态
	kmGLPopMatrix();

    CCSize s = CCDirector::sharedDirector()->getWinSize();
    //绘制第二个相对位置曲线
	//先将当前OPENGL的矩阵状态压栈
	kmGLPushMatrix();
	//移动到s.width/2, 50的位置
	kmGLTranslatef(s.width/2, 50, 0);
	//以这个点为原点绘制相对路径
	ccDrawCardinalSpline(m_pArray, 1, 100);
	//恢复矩阵状态
	kmGLPopMatrix();
}

string ActionCardinalSpline::title()
{
    return "CardinalSplineBy / CardinalSplineAt";
}

string ActionCardinalSpline::subtitle()
{
    return "Cardinal Spline paths. Testing different tensions for one array";
}
//第三十四种动画演示表现的是控制暂停和恢复动画。
class PauseResumeActions : public ActionsDemo
{
public:
    PauseResumeActions();
    virtual ~PauseResumeActions();
    virtual void onEnter();
    virtual std::string subtitle();
    virtual std::string title();
    
    void pause(float dt);
    void resume(float dt);
private:
    CCSet *m_pPausedTargets;
};
PauseResumeActions::PauseResumeActions()
: m_pPausedTargets(NULL)
{

}

PauseResumeActions::~PauseResumeActions()
{
    CC_SAFE_RELEASE(m_pPausedTargets);
}

void PauseResumeActions::onEnter()
{	//动画演示初始化
    ActionsDemo::onEnter();
	//两位演员上场。
    this->centerSprites(2);
    //女一号运行一个无限循环的动画。
    m_tamara->runAction(CCRepeatForever::create(CCRotateBy::create(3, 360)));
 	//男一行运行一个反方向无限循环的动画。   m_grossini->runAction(CCRepeatForever::create(CCRotateBy::create(3, -360)));
	//女二号的动画同女一号一样。
    m_kathia->runAction(CCRepeatForever::create(CCRotateBy::create(3, 360)));
    //当前层在3秒后调用回调函数暂停。
	this->schedule(schedule_selector(PauseResumeActions::pause), 3, false, 0);
	//当前层在5秒后调用回调函数恢复。
    this->schedule(schedule_selector(PauseResumeActions::resume), 5, false, 0);
}

string PauseResumeActions::title()
{
    return "PauseResumeActions";
}

string PauseResumeActions::subtitle()
{
    return "All actions pause at 3s and resume at 5s";
}
//暂停的回调函数,用于暂停动画。
void PauseResumeActions::pause(float dt)
{
	CCLog("Pausing");
	//取得显示设备
    CCDirector *director = CCDirector::sharedDirector();
	//如果原来有要暂停的目标容器,释放暂停的目标容器
	CC_SAFE_RELEASE(m_pPausedTargets);
	//调用显示设备的接口暂停所有的动画并将这些动画返回给容器
	m_pPausedTargets = director->getActionManager()->pauseAllRunningActions();
	//因为占用它,所以对此引用计数器加1
    CC_SAFE_RETAIN(m_pPausedTargets);
}
//恢复的回调函数,用于恢复暂停的动画。
void PauseResumeActions::resume(float dt)
{
	CCLog("Resuming");
	//取得显示设备
	
	CCDirector *director = CCDirector::sharedDirector();
	//调用显示设备的接口恢复所有的暂停的动画
    director->getActionManager()->resumeTargets(m_pPausedTargets);
}
#endif

每一个演示完毕!大家明白了么?当然CPP里还有一点东西还需要说一下。

#include "ActionsTest.h"
#include "../testResource.h"
#include "cocos2d.h"

//这里定义三个全局函数,用于动画演示控制
CCLayer* NextAction();//演示下一个动画
CCLayer* BackAction();//演示上一个动画
CCLayer* RestartAction();//重新演示当前动画
//要演示的动画索引
static int s_nActionIdx = -1;
//创建相应的动画
CCLayer* CreateLayer(int nIndex)
{
	//在头文件里我们看到大量的动画演示类,它们都是由CCLayer基类派生的。这里定义一个CCLayer类用于指向下面创建的相应动画演示实例。
    CCLayer * pLayer = NULL;
	//根据索引new出相应的动画演示实例。
    switch (nIndex)
    {
        case ACTION_MANUAL_LAYER:
            pLayer = new ActionManual(); break;
        case ACTION_MOVE_LAYER:
            pLayer = new ActionMove(); break;
        case ACTION_SCALE_LAYER:
            pLayer = new ActionScale(); break;
        case ACTION_ROTATE_LAYER:
            pLayer = new ActionRotate(); break;
        case ACTION_SKEW_LAYER:
            pLayer = new ActionSkew(); break;
        case ACTION_SKEWROTATE_LAYER:
            pLayer = new ActionSkewRotateScale(); break;
        case ACTION_JUMP_LAYER:
            pLayer = new ActionJump(); break;
        case ACTION_BEZIER_LAYER:
            pLayer = new ActionBezier(); break;
        case ACTION_BLINK_LAYER:
            pLayer = new ActionBlink(); break;
        case ACTION_FADE_LAYER:
            pLayer = new ActionFade(); break;
        case ACTION_TINT_LAYER:
            pLayer = new ActionTint(); break;
        case ACTION_ANIMATE_LAYER:
            pLayer = new ActionAnimate(); break;
        case ACTION_SEQUENCE_LAYER:
            pLayer = new ActionSequence(); break;
        case ACTION_SEQUENCE2_LAYER:
            pLayer = new ActionSequence2(); break;
        case ACTION_SPAWN_LAYER:
            pLayer = new ActionSpawn(); break;
        case ACTION_REVERSE:
            pLayer = new ActionReverse(); break;
        case ACTION_DELAYTIME_LAYER:
            pLayer = new ActionDelayTime(); break;
        case ACTION_REPEAT_LAYER:
            pLayer = new ActionRepeat(); break;
        case ACTION_REPEATEFOREVER_LAYER:
            pLayer = new ActionRepeatForever(); break;
        case ACTION_ROTATETOREPEATE_LAYER:
            pLayer = new ActionRotateToRepeat(); break;
        case ACTION_ROTATEJERK_LAYER:
            pLayer = new ActionRotateJerk(); break;    
        case ACTION_CALLFUNC_LAYER:
            pLayer = new ActionCallFunc(); break;
        case ACTION_CALLFUNCND_LAYER:
            pLayer = new ActionCallFuncND(); break;
        case ACTION_REVERSESEQUENCE_LAYER:
            pLayer = new ActionReverseSequence(); break;
        case ACTION_REVERSESEQUENCE2_LAYER:
            pLayer = new ActionReverseSequence2(); break;
        case ACTION_ORBIT_LAYER:
            pLayer = new ActionOrbit(); break;
        case ACTION_FLLOW_LAYER:
            pLayer = new ActionFollow(); break;
        case ACTION_TARGETED_LAYER:
            pLayer = new ActionTargeted(); break;
        case ACTION_ISSUE1305_LAYER:
            pLayer = new Issue1305(); break;
        case ACTION_ISSUE1305_2_LAYER:
            pLayer = new Issue1305_2(); break;
        case ACTION_ISSUE1288_LAYER:
            pLayer = new Issue1288(); break;
        case ACTION_ISSUE1288_2_LAYER:
            pLayer = new Issue1288_2(); break;
        case ACTION_ISSUE1327_LAYER:
            pLayer = new Issue1327(); break;
        case ACTION_CARDINALSPLINE_LAYER:
            pLayer = new ActionCardinalSpline(); break;
        case ACTION_CATMULLROM_LAYER:
            pLayer = new ActionCatmullRom(); break;
        case PAUSERESUMEACTIONS_LAYER:
            pLayer = new PauseResumeActions(); break;

    default:
        break;
    }

    return pLayer;
}
//演示下一个动画的函数实现
CCLayer* NextAction()
{
    ++s_nActionIdx;
    s_nActionIdx = s_nActionIdx % ACTION_LAYER_COUNT;

    CCLayer* pLayer = CreateLayer(s_nActionIdx);
    pLayer->autorelease();

    return pLayer;
}
//演示上一个动画的函数实现
CCLayer* BackAction()
{
    --s_nActionIdx;
    if( s_nActionIdx < 0 )
        s_nActionIdx += ACTION_LAYER_COUNT;    

    CCLayer* pLayer = CreateLayer(s_nActionIdx);
    pLayer->autorelease();

    return pLayer;
}
//重新演示当前动画的函数实现。
CCLayer* RestartAction()
{
    CCLayer* pLayer = CreateLayer(s_nActionIdx);
    pLayer->autorelease();

    return pLayer;
}

三板斧,威力十足,如果还有什么不懂的。那我真没得好说了。下课!


分类: cocos2d, cocos2d-x 标签:

【CSDN2012年度博客之星】大家多多支持下哦,喜欢本博客的朋友,希望能投下您的一票,多多支持~

2012年12月4日 没有评论

投票地址:http://vote.blog.csdn.net/item/blogstar/yanghuiliu


        喜欢本博客的朋友,希望多多支持,最近除了分享cocos2d-x的教程,也开始分享Unity3D的教程了。希望和广大朋友共同交流技术心得~


        请投下您的一票~

分类: 未分类 标签: