【玩转cocos2d-x之二十三】多线程和同步03-图片异步加载

前端之家收集整理的这篇文章主要介绍了【玩转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 等的概念)
2) 怎样在萤幕画东西 (texture 处理,sprite 等)
3) 操控
4) 声效
5) 菜单处理

这里我略为说一下关於怎样在萤幕画东西吧. 首先如往常般的建立一个 cocos2d 项目在 VC2010 Express 里 (为方便起,我会在 Windows 平台上写和测试,有机会再移植到 iOS 和Android):

new_project.jpg

建立了这个叫 Demo 的项目後,我们再把一些图抄到 Resources 里:
res.jpg

把这些图像画到萤幕上,最简单就是把每个图放进一个个的 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);

复制代码

程序跑起来就会看到下边这个画面:
hello.jpg

不过我们最终的目标是把遊戏放到 iOS 或 Android 机子上玩,所以我们不能不考虑一下有关OpenGL ES 优化的问题,两大关键问题就是内存(显存)运用和速度.
先看一下内存问题,OpenGL ES 纹理的宽和高都要是2的倍数,以刚才的例子来说,虽然 Background.png 本身是 480x320,但在载入内存後,它其实会被变成一张 512x512 的纹理,而Grass Block.png 则由 101x131 变成 128x256,我们可以看到如此这样会造成不少浪费.

再看看关於渲染速度方面,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);

复制代码

大功告成!

原文链接:https://www.f2er.com/cocos2dx/341967.html

猜你在找的Cocos2d-x相关文章