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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6


另:本章所用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及其派生CCGrid3D和CCTiledGrid3D,CCGridBase的关键是处理了将屏幕渲染到纹理这个功能。

它有两个重要的函数:

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

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 网格动画深入分析_2d



//绕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 网格动画深入分析_投影矩阵_02



//绕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 网格动画深入分析_投影矩阵_03



//球体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 网格动画深入分析_投影矩阵_04

//涟漪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 网格动画深入分析_投影矩阵_05


//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 网格动画深入分析_2d_06


//流体效果的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 网格动画深入分析_初始化_07


//波浪效果的网格动画,与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 网格动画深入分析_2d_08


//盘旋扭曲效果的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 网格动画深入分析_2d_09


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

 

打开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 网格动画深入分析_初始化_10




//随机抖动效果的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 网格动画深入分析_初始化_11



//重新排列格子效果的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 网格动画深入分析_投影矩阵_12



//从右上角开始渐隐格子的动画。
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 网格动画深入分析_投影矩阵_13



//从左下角渐隐格子的动画。
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 网格动画深入分析_投影矩阵_14



//从左下角渐隐格子的动画。
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 网格动画深入分析_初始化_15


//向上部渐隐格子的动画。
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 网格动画深入分析_初始化_16



//向下部渐隐格子的动画。
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 网格动画深入分析_2d_17



//格子的消失动画
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 网格动画深入分析_初始化_18



//波浪状的格子动画。
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 网格动画深入分析_2d_19



//跳动的格子动画。
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 网格动画深入分析_投影矩阵_20



//横向分割的格子动画。
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 网格动画深入分析_初始化_21



//纵向切分的格子运动动画。
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 网格动画深入分析_2d_22



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

 

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

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“Cocos2d-x 2.0 网格动画深入分析” 的相关文章