【玩转cocos2d-x之二十三】多线程和同步03-图片异步加载
转自http://cocos2d.cocoachina.com/bbs/forum.php?mod=viewthread&tid=775&extra=page%3D1 (内容重点: CCSprite,CCSpriteFrameCache,CCSpriteBatchNode,TexturePacker) 很早就开始留意 cocos2d,但不太习惯用 Objective C,同时也考虑到跨平台的问题,所以一直没有正式用过,後来有了 cocos2d-x,就更为关注,老想有空时拿来玩玩写点东西. 之前下载了 cocos2d-x 看了一下附带的例子,被里边的 scene,layer,CCTextureCache,CCSpriteFrameCache 等等弄得很是混乱,再加上工作上的事情,就放下了,直到上周无意中下载了一本书的 PDF,决定再好好地学习一下,而我发现有关 cocos2d-x 的教程并不多,所以我就班门弄斧的和大家分享一下我的学习过程吧. (附带一提,这本书叫Learn cocos2D Game Development with iOS 5,这麽好的书当然要买正版支持,我已经在 amazon 定购了,正在运送途中) 学习一种新技术,一般我会找一本较好的参考书(或资料),先了解一下它的基本概念,再通过实习应用来熟识. 我想不少童鞋可能是被cocos2d 超多的功能所吸引而选用它,但其实写个一般的小遊戏并不需要知道得太多,以下就是我想先了解的东西: 1) cocos2d 的基本架构 (像scene,layer 等的概念) 这里我略为说一下关於怎样在萤幕画东西吧. 首先如往常般的建立一个 cocos2d 项目在 VC2010 Express 里 (为方便起,我会在 Windows 平台上写和测试,有机会再移植到 iOS 和Android): new_project.jpg 建立了这个叫 Demo 的项目後,我们再把一些图抄到 Resources 里: 把这些图像画到萤幕上,最简单就是把每个图放进一个个的 CCSprite然後加到当前的 Layer 上. 以下这段代码就是把 Background.png,Grass Block.png 和 p8.png 显示在画面: CCSize size = CCDirector::sharedDirector()->getWinSize(); CCSprite* pSprite = CCSprite::spriteWithFile("Background.png"); CC_BREAK_IF(! pSprite); pSprite->setPosition(ccp(size.width/2,size.height/2)); this->addChild(pSprite,0); pSprite = CCSprite::spriteWithFile("Grass Block.png"); CC_BREAK_IF(! pSprite); pSprite->setPosition(ccp(size.width/2,0); pSprite = CCSprite::spriteWithFile("p8.png"); CC_BREAK_IF(! pSprite); CCSize dim = pSprite->getContentSize(); pSprite->setPosition(ccp(size.width/2,size.height/2+dim.height/2)); this->addChild(pSprite,0); 复制代码 程序跑起来就会看到下边这个画面: 不过我们最终的目标是把遊戏放到 iOS 或 Android 机子上玩,所以我们不能不考虑一下有关OpenGL ES 优化的问题,两大关键问题就是内存(显存)运用和速度. 再看看关於渲染速度方面,OpenGL ES 上来说我们应该尽量减少渲染时切换纹理和 glDrawArray 的呼叫,刚才的例子每画一个图像都会切换一次纹理并呼叫一次 glDrawArray,我们这里只画3样东西,所以不会看到有什麽问题,但如果我们要渲染几十个甚至几百个图像,速度上就会被拖慢. 很明显这并不是我们所想要的. 那我们应该怎麽解决这些问题呢? 答案就是利用纹理地图(texture atlas),比如下面这张纹理就是把我们想用的图像都合併在一起,而它的大小正好是 512x512: images.png 如果人手去做这个合併工作就太痛苦了,这里要向大家推荐一个十分好用的工具: TexturePacker! (http://www.texturepacker.com/) 这个工具直接支持 cocos2d,实在是太方便了! 首先我们把想要用的图像都放到一个目录里,再用TexturePacker 的 “Add Folder” 功能把目录加进去,TexturePacker 的默认输出格式就是 cocos2d: texturepacker1.jpg 为了节省位置,我们可以把Border padding 和Shape Padding 都设为1,而选了 Allow rotation 可以让 TexturePacker 更为有效率的摆放图像在纹理里: texturepacker2.jpg 在键入了输出的档案名字後,我们就可以用 Publish 把纹理输出. 接下来,我们把输出的两个档案(我们这里的例子是images.plist 和 images.png) 放到 Resources 里,就可以在程序里用 CCSpriteFrameCache 把纹理和有关资料载入: cache->addSpriteFramesWithFile("images.plist","images.png"); 复制代码 但现在我们只有一张叫 “images.png” 的纹理,那麽怎样去调用比如是 Background.png 呢? 当然我们还是用 CCSprite 做渲染图像的工作,但在建立一个 CCSprite 时,我们换为用 spriteWithSpriteFrameName 而不是 spriteWithFile: CCSprite* pSprite = CCSprite::spriteWithSpriteFrameName(" Background.png"); CCSpriteFrameCache *cache = CCSpriteFrameCache::sharedSpriteFrameCache(); cache->addSpriteFramesWithFile("images.plist","images.png"); // Get window size and place the label upper. CCSize size = CCDirector::sharedDirector()->getWinSize(); CCSprite* pSprite = CCSprite::spriteWithSpriteFrameName("Background.png"); CC_BREAK_IF(! pSprite); pSprite->setPosition(ccp(size.width/2,0); pSprite = CCSprite::spriteWithSpriteFrameName("Grass Block.png"); CC_BREAK_IF(! pSprite); pSprite->setPosition(ccp(size.width/2,0); pSprite = CCSprite::spriteWithSpriteFrameName("p8.png"); CC_BREAK_IF(! pSprite); CCSize dim = pSprite->getContentSize(); pSprite->setPosition(ccp(size.width/2,0); 复制代码 来到这里,我们已经逹到了节省内存和减少纹理切换,最後一个我们想做的优化是减少 glDrawArray 的次数,而我们所运用的技巧,就是批次渲染(Batch Rendering),cocos2d 提供了CCSpriteBatchNode 来方便大家做有关的处理,CCSpriteBatchNode 里的CCSprite 都是要用同一个纹理的,所以我们在建立一个 CCSpriteBatchNode 是要给它一个纹理,再把它加到 Layer 里 : CCTexture2D *texture = CCTextureCache::sharedTextureCache()->textureForKey("images.png"); CCSpriteBatchNode *spriteBatch = CCSpriteBatchNode::batchNodeWithTexture(texture); addChild(spriteBatch); 复制代码 接下来我们如常的建立各个 CCSprite,但不同的地方是我们不把它们加在 Layer 里而是把它们直接加到 CCSpriteBatchNode 上: CCSpriteFrameCache *cache = CCSpriteFrameCache::sharedSpriteFrameCache(); cache->addSpriteFramesWithFile("images.plist","images.png"); CCTexture2D *texture = CCTextureCache::sharedTextureCache()->textureForKey("images.png"); CCSpriteBatchNode *spriteBatch = CCSpriteBatchNode::batchNodeWithTexture(texture); addChild(spriteBatch); // Get window size and place the label upper. CCSize size = CCDirector::sharedDirector()->getWinSize(); CCSprite* pSprite = CCSprite::spriteWithSpriteFrameName("Background.png"); pSprite->setPosition(ccp(size.width/2,size.height/2)); spriteBatch->addChild(pSprite,0); pSprite = CCSprite::spriteWithSpriteFrameName("Grass Block.png"); pSprite->setPosition(ccp(size.width/2,0); pSprite = CCSprite::spriteWithSpriteFrameName("p8.png"); CCSize dim = pSprite->getContentSize(); pSprite->setPosition(ccp(size.width/2,size.height/2+dim.height/2)); spriteBatch->addChild(pSprite,0); 复制代码 大功告成! (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |