`
yidongkaifa
  • 浏览: 4091996 次
文章分类
社区版块
存档分类
最新评论

Cocos2d-x 纹理优化实例:拼图优化与实测

 
阅读更多

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

红孩儿Cocos2d-X学习园地:249941957加群写:Cocos2d-x

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


纹理优化实例:拼图优化与实测



[注:本版使用Cocos2d-x 2.02版本]

Cocos2d-x优化方案一文发布一周了,这篇文章我介绍了一些纹理优化方面的方法原理。未来我将会逐步的将这些优化方案的具体制做实例讲解教授给大家。本节我先带领大家来进行拼图优化的具体制做与实测。

我们本节使用的小图为:



这一堆小图共有34张,都是PNG格式的RGBA8888。我们知道OpenGL ES在生成纹理时大小会扩展成2的幂次方。下面我们来统计一下它们生成纹理所占用的内存。

有15张图(grossini~grossini_dance_14.png)大小为85x121,实际纹理占用128x128, 一张128x128大小的RGBA8888格式纹理需要64K内存来存储像素数据。15x64K = 960K。

一张(grossinis_sister1.png)大小为52x139, 实际纹理占用64x256,64K

一张(grossinis_sister1-testalpha.png)是52x200, ,实际纹理占用64x256,64K

一张是(grossinis_sister2.png)大小为56x138, 实际纹理占用64x256,64K

六张(btn-about-normal.png~btn-play-selected.png)大小为125x42, 实际纹理占用128x64,6x32K = 192K

两张(b1.png~f1.png)大小为79x46,实际纹理占用128x64,2x32K = 64K

两张(b2.png~f2.png)大小为79x47,实际纹理占用128x64,2x32K = 64K

三张 (SpinningPeas.png ,SpookyPeas.png, Pea.png )大小为37x37。实际纹理占用64x64,3x16K=48K

一张(r1.png)大小为49x47, 实际纹理占用64x64,16k

一张(r2.png)大小为49x48, 实际纹理占用64x64,16k

一张(ball.png)大小为16x16, 实际纹理占用16x16,1K

所有图片在创建为纹理后总内存为1553K

我们来把这些小图加入到场景中。

在场景所在CCLayer中加入一个CCSprite指针容器用来存放生成的精灵.

private:

vector<CCSprite*> m_pSpriteVec;


然后在场景的init函数中加入:


int		nRepeat = 100;
	//建立一个bool变量做为是否使用批次处理的开关
	bool	nUseSprteBatchNod = false;
	//读取零散文件	
	if(false == nUseSprteBatchNod)
	{
		for(int i = 0 ; i < nRepeat ; i++)
		{
			CCSprite* tpSprite1 = CCSprite::create("grossini.png");
			m_pSpriteVec.push_back(tpSprite1);
			CCSprite* tpSprite2 = CCSprite::create("grossini_dance_01.png");
			m_pSpriteVec.push_back(tpSprite2);
			CCSprite* tpSprite3 = CCSprite::create("grossini_dance_02.png");
			m_pSpriteVec.push_back(tpSprite3);
			CCSprite* tpSprite4 = CCSprite::create("grossini_dance_03.png");
			m_pSpriteVec.push_back(tpSprite4);
			CCSprite* tpSprite5 = CCSprite::create("grossini_dance_04.png");
			m_pSpriteVec.push_back(tpSprite5);
			CCSprite* tpSprite6 = CCSprite::create("grossini_dance_05.png");
			m_pSpriteVec.push_back(tpSprite6);
			CCSprite* tpSprite7 = CCSprite::create("grossini_dance_06.png");
			m_pSpriteVec.push_back(tpSprite7);
			CCSprite* tpSprite8 = CCSprite::create("grossini_dance_07.png");
			m_pSpriteVec.push_back(tpSprite8);
			CCSprite* tpSprite9 = CCSprite::create("grossini_dance_08.png");
			m_pSpriteVec.push_back(tpSprite9);
			CCSprite* tpSprite10 = CCSprite::create("grossini_dance_09.png");
			m_pSpriteVec.push_back(tpSprite10);
			CCSprite* tpSprite11 = CCSprite::create("grossini_dance_10.png");
			m_pSpriteVec.push_back(tpSprite11);
			CCSprite* tpSprite12 = CCSprite::create("grossini_dance_11.png");
			m_pSpriteVec.push_back(tpSprite12);
			CCSprite* tpSprite13 = CCSprite::create("grossini_dance_12.png");
			m_pSpriteVec.push_back(tpSprite13);
			CCSprite* tpSprite14 = CCSprite::create("grossini_dance_13.png");
			m_pSpriteVec.push_back(tpSprite14);
			CCSprite* tpSprite15 = CCSprite::create("grossini_dance_14.png");
			m_pSpriteVec.push_back(tpSprite15);
			CCSprite* tpSprite16 = CCSprite::create("grossinis_sister1.png");
			m_pSpriteVec.push_back(tpSprite16);
			CCSprite* tpSprite17 = CCSprite::create("grossinis_sister2.png");
			m_pSpriteVec.push_back(tpSprite17);
			CCSprite* tpSprite18 = CCSprite::create("grossinis_sister1-testalpha.png");
			m_pSpriteVec.push_back(tpSprite18);
			CCSprite* tpSprite19 = CCSprite::create("r1.png");
			m_pSpriteVec.push_back(tpSprite19);
			CCSprite* tpSprite20 = CCSprite::create("r2.png");
			m_pSpriteVec.push_back(tpSprite20);
			CCSprite* tpSprite21 = CCSprite::create("btn-about-normal.png");
			m_pSpriteVec.push_back(tpSprite21);
			CCSprite* tpSprite22 = CCSprite::create("btn-play-normal.png");
			m_pSpriteVec.push_back(tpSprite22);
			CCSprite* tpSprite23 = CCSprite::create("btn-play-selected.png");
			m_pSpriteVec.push_back(tpSprite23);
			CCSprite* tpSprite24 = CCSprite::create("btn-about-selected.png");
			m_pSpriteVec.push_back(tpSprite24);
			CCSprite* tpSprite25 = CCSprite::create("btn-highscores-selected.png");
			m_pSpriteVec.push_back(tpSprite25);
			CCSprite* tpSprite26 = CCSprite::create("btn-highscores-normal.png");
			m_pSpriteVec.push_back(tpSprite26);
			CCSprite* tpSprite27 = CCSprite::create("b1.png");
			m_pSpriteVec.push_back(tpSprite27);
			CCSprite* tpSprite28 = CCSprite::create("f1.png");
			m_pSpriteVec.push_back(tpSprite28);
			CCSprite* tpSprite29 = CCSprite::create("b2.png");
			m_pSpriteVec.push_back(tpSprite29);
			CCSprite* tpSprite30 = CCSprite::create("f2.png");
			m_pSpriteVec.push_back(tpSprite30);
			CCSprite* tpSprite31 = CCSprite::create("SpinningPeas.png");
			m_pSpriteVec.push_back(tpSprite31);
			CCSprite* tpSprite32 = CCSprite::create("SpookyPeas.png");
			m_pSpriteVec.push_back(tpSprite32);
			CCSprite* tpSprite33 = CCSprite::create("Pea.png");
			m_pSpriteVec.push_back(tpSprite33);
			CCSprite* tpSprite34 = CCSprite::create("ball.png");
			m_pSpriteVec.push_back(tpSprite34);

		}
		//对容器进行一个随机排序
		random_shuffle(m_pSpriteVec.begin(),m_pSpriteVec.end());
		//初始化一下随机种子,后面用于产生随机位置
		srand(GetTickCount());
		//产生精灵
		for(int i = 0 ; i < nRepeat; i++)
		{
			for(int j = 0 ; j < 34; j++)
			{
				int	nIndex = i * 34 + j ;
				int	nPosX  = rand()%960;
				int	nPosY  = rand()%640;
				m_pSpriteVec[nIndex]->setPosition(ccp(origin.x + nPosX, origin.y + nPosY));
				this->addChild(m_pSpriteVec[nIndex], 1);
			}
		}

	}

运行程序后的画面在我的机器【五年前的笔记本,2G内存2GHzCPU】上大约在17帧左右.


左下角显示共有3400个批次,每帧平均耗时0.058秒,每秒大约17.4帧。

下面我们来进行拼图优化,我们使用红孩儿纹理打包器1.1版本”来进行拼图制做,它具有使用方便,拼图率高的特点。

下载地址:http://download.csdn.net/detail/honghaier/4671677


使用方法:先将要使用的图片放在Test目录,建立一个Export目录用来存放导出图片与信息,启动红孩儿纹理打包器1.1.exe,然后点击 “浏览源图片目录” 选择Test目录,点击“浏览目标目录”选择Export目录。之后打包器会自动进行记算,在Export目录中生成1张512的图以及几种格式的导出文件。

一张512x512的图的大小就是1024K,可以看出,在咱们这个测试例程中,在使用拼合图比散图省了约500K左右,另外也节省了IO的次数和时间呢!


blo格式为二进制文件。

//二进制文件头信息

struct SPackFileHeader

{

int m_Version; //版本

char m_szBigTexName[64]; //大图名称

int m_nImageSize; //大图的大小

int m_nBlockNum; //图块数量

};

//二进制文件数据块

struct SPackNode

{

RECT m_Rect; //对应图块矩形

POINT m_OffsetPt; //中心点偏移

bool m_bRotated; //是否顺时针旋转90

};

读取时先读入二进制文件头信息,然后根据m_nBlockNum遍历读入数据块信息

ini格式为Windows信息文件。

INI格式:

[BigTexture]

Name=大图名称

BlockSize=拼合到此大图的图块数量

[Block]

Block0=图块矩形left,图块矩形top,图块矩形宽right,图块矩形bottom,是否是否顺时针旋转90,中心点偏移x,中心点偏移y

plist格式为XML信息文件。


我们可以根据自已的实际需要来使用相应的信息格式文件来进行读取。

本节我以二进制信息文件来进行讲解:

if(false == nUseSprteBatchNod)
	{
}
else
{
		//创建拼图批次,里面共有34个图块
		CCSpriteBatchNode* pNewBatchNode = CCSpriteBatchNode::create("Big_0.png", 34 );
		//读取二进制文件,将数据读取到容器中
		this->addChild(pNewBatchNode,1);
		//读取二进制文件
		string	szResPath(CCFileUtils::sharedFileUtils()->getResourceDirectory());
		szResPath += "Big_0.blo";
		FILE*	hFile = fopen(szResPath.c_str(),"rb");
		if(hFile)
		{
			//先读取文件头
			SPackFileHeader	tFileHeader;
			fread(&tFileHeader,sizeof(SPackFileHeader),1,hFile);
			//遍历读取每个图块
			SPackNode			tPackNode;
			for(int b = 0 ; b < tFileHeader.m_nBlockNum ; ++b)
			{
				fread(&tPackNode,sizeof(SPackNode),1,hFile);
				for(int i = 0 ; i < nRepeat ; i++)
				{
					//创建精灵
                                        CCRect		tRect;
                                        if(tPackNode.m_bRotated)
					{
					     tRect = CCRect(tPackNode.m_Rect.left,tPackNode.m_Rect.top,tPackNode.m_Rect.bottom-tPackNode.m_Rect.top,tPackNode.m_Rect.right-tPackNode.m_Rect.left);
                                        }
                                        else
                                        {
                                             tRect = CCRect(tPackNode.m_Rect.left,tPackNode.m_Rect.top,tPackNode.m_Rect.right-tPackNode.m_Rect.left,tPackNode.m_Rect.bottom-tPackNode.m_Rect.top);
                                        }
					CCSize		tSize(tPackNode.m_Rect.right-tPackNode.m_Rect.left+tPackNode.m_OffsetPt.x,tPackNode.m_Rect.bottom-tPackNode.m_Rect.top+tPackNode.m_OffsetPt.y);
					//创建精灵并从拼合图中初始化纹理贴图。
					CCSprite*	tpSprite1 = CCSprite::create();
					tpSprite1->initWithTexture(pNewBatchNode->getTexture(), tRect,tPackNode.m_bRotated);
					//将精灵放入容器
					m_pSpriteVec.push_back(tpSprite1);


				}

			}
			fclose(hFile);
			random_shuffle(m_pSpriteVec.begin(),m_pSpriteVec.end());
			srand(GetTickCount());

			for(int i = 0 ; i < 2 * nRepeat; i++)
			{
				for(int j = 0 ; j < 17 ; j++)
				{
					int	nIndex = i * 17 + j ;
					int	nPosX  = rand()%960;
					int	nPosY  = rand()%640;
					m_pSpriteVec[nIndex]->setPosition(ccp(origin.x + nPosX, origin.y + nPosY));
					pNewBatchNode->addChild(m_pSpriteVec[nIndex]);
				}
			}
		}
}

nUseSprteBatchNod设为true,运行程序后的FPS大约在22帧左右.可以清楚的看到批次数为1。



最后做一下总结:

在进行2D游戏的开发时,图片绝对是重中之重,有图片才有画面,有图片才有动画,所以好的图片使用效率是一个成功游戏的重要技术保证,希望大家多研究一下。下课~




分享到:
评论

相关推荐

    Cocos2d-x实战:JS卷——Cocos2d-JS开发

    资源名称:Cocos2d-x实战:JS卷——Cocos2d-JS开发内容简介:本书是介绍Cocos2d-x游戏编程和开发技术书籍,介绍了使用Cocos2d-JS中核心类、瓦片地图、物理引擎、音乐音效、数据持久化、网络通信、性能优化、多平台...

    Cocos2d-x高级开发教程

    Cocos2d-x是移动跨平台开发最流行的游戏引擎,而本书是一本很全面的、比较‘接地气’的游戏开发教程。书中汇聚了热门手机游戏《捕鱼达人》开发的实战经验,作者从最基础的内容开始,逐步深入地介绍了Cocos2d-x的相关...

    Cocos2d-x高级开发教程:制作自己的《捕鱼达人》

    资源名称:Cocos2d-x高级开发教程:制作自己的《捕鱼达人》内容简介:Cocos2d-x是移动跨平台开发最流行的游戏引擎,而本书是一本很全面的、比较‘接地气’的游戏开发教程。书中汇聚了热门手机游戏《捕鱼达人》开发的...

    实例妙解Cocos2D-X游戏开发

    一线资深游戏开发工程师根据Cocos2D-X 最新版本撰写,Cocos2D-X创始人王哲、CSDN创始人蒋涛联袂推荐 完全通过真实游戏案例驱动,不仅将Cocos2D-X的各种功能、原理、技巧融入其中,而且还详细讲解了空战类、塔防类、...

    cocos2d-x-2.1.5

    cocos2d-x-2.1.5

    大富翁手机游戏开发实战基于Cocos2d-x3.2引擎

    资源名称:大富翁手机游戏开发实战基于Cocos2d-x3.2引擎内容简介:李德国编著的《大富翁手机游戏开发实战(基于 Cocos2d-x3.2引擎)》使用Cocos2d-x游戏引擎技术,带领读者一步一步从零开始进行大富翁移动游戏的开发...

    cocos2d-x实战 c++卷教程及完整源码

    cocos2d-x实战 c++卷教程及完整源码下载,使用最新cocos2d-x-3.14版本,在xcode7.3上已编译通过。 解决相关问题 1、解决源程序在高版本上无法编译问题 2、解决源程序中文注释部分,xcode上显示乱码问题 3、根据书籍...

    cocos2d-x-3.2旧版引擎下载

    cocos2d-x-3.2下载,不多说。或者可以下载另一个资源 cocos引擎老版本集合(cocos2d-x-2.2.1 - 3.5) http://download.csdn.net/download/crazymagicdc/9982656

    cocos2d-x事件类

    在使用cocos2d-x开发游戏的过程中,为了实现逻辑和显示相分离。 在下通宵了一个晚上,写出了该事件类。 谨记,该事件只能用于cocos2d-x中。 事件发送者需要继承EventDispatcher类 事件接收者需要继承EventHandle类...

    cocos2d-x性能优化

    cocos2d-x性能优化

    cocos2d-x手机游戏开发:跨iOS、Android和沃Phone平台.pdf

    cocos2d-x手机游戏开发:跨iOS、Android和沃Phone平台.pdf

    Cocos2d-x 3.x游戏开发之旅教程及完整源码下载

    Cocos2d-x 3.x游戏开发之旅教程及完整源码下载,使用最新cocos2d-x-3.14版本,在xcode7.3上已编译通过。 解决相关问题 1、解决源程序在高版本上无法编译问题 2、解决源程序中文注释部分,xcode上显示乱码问题 使用...

    cocos2d-x实战项目

    cocos2d-x实战项目 01.cocos2d-x原理及环境配置.rar 03.cocostudio使用方法及UI控制.rar 04.XML文件读取与骨骼动画.rarcocos2d-x实战项目 01.cocos2d-x原理及环境配置.rar 03.cocostudio使用方法及UI控制.rar 04.XML...

    经典版本 方便下载 源码 旧版本 3.8 官网找不到了 cocos2d-x-3.8.zip

    经典版本 方便下载 源码 旧版本 3.8 官网找不到了 cocos2d-x-3.8.zip

    Cocos2D-X游戏开发技术精解

    资源名称:Cocos2D-X游戏开发技术精解内容简介:Cocos2D-X是一款支持多平台的 2D手机游戏引擎,支持iOS、Android、BlackBerry等众多平台。当前,很多移动平台流行的游戏,都是基于Cocos2D-X开发的。 《Cocos2D-X...

    Cocos2d-x实战:C++卷(2版)源代码

    Cocos2d-x实战:C++卷(2版)源代码

    精通COCOS2D-X游戏开发 基础卷_2016.4-P399-13961841.pdf

    精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发 精通COCOS2D-X游戏开发

    Cocos2d-x 3.x游戏开发实战pdf含目录

    Cocos2d-x 3.x游戏开发实战pdf含目录,内容详细,强烈推荐给大家。

    Cocos2d-x实战 JS卷

    Cocos2d-x实战

    cocos2d-x-3.0 类图

    这是我重新弄的cocos2d-x-3.0的类图.之前别人兄台弄的,有些不全面,有些地方错误.我这个可以说是最新的了.每个类添加了中文的详细注解,同时也添加了中文的类名称翻译.这样对cocos2d-x-3.0的框架比较好上手. 有兴趣的...

Global site tag (gtag.js) - Google Analytics