欢迎光临Software MyZone,有问题可留言或到站点论坛发帖,争取第一时间帮忙解决 || 站点论坛:火龙论坛 || 淘宝小店:应小心的易淘屋 【欢迎大家提建设性意见】

Cocos2d-x优化中纹理优化

欢迎热爱编程的朋友们参与到cocos2d-x编程中,为了给大家提供良好的交流环境,网站以开启QQ群
Software MyZone:66202765(群号,欢迎加入,若满,请加1群)
Software MyZone 1群(2dx):286504621
【加群请写:Software MyZone或者是firedragonpzy】
淘宝店:【应小心的易淘屋】初次开店,大家多多支持……
群论坛:火龙论坛正试运营阶段,欢迎大家多提些建设性意见……

摘自:http://cn.cocos2d-x.org/tutorial/show?id=1865

 
1.纹理像素格式

纹理优化工作的另一重要的指标是纹理像素格式,能够最大程度满足用户对保真度要求的情况下,选择合适的像素格式,可以大幅提高纹理的处理速度。而且纹理像素格式有与硬件有这密切的关系。

 

下面我们先了解一下纹理像素的格式,主要的格式有:

  • RGBA8888。32位色,它是默认的像素格式,每个通道8位(比特),每个像素4个字节。
  • BGRA8888。32位色,每个通道8位(比特),每个像素4个字节。
  • RGBA4444。16位色,每个通道4位(比特),每个像素2个字节。
  • RGB888。24位色,没有Alpha通道,所以没有透明度。每个通道8位(比特),每个像素3个字节。
  • RGB565。16位色,没有Alpha通道,所以没有透明度。R和B通道是各5位,G通道是6。
  • RGB5A1(或RGBA5551)。16位色,每个通道各4位,Alpha通道只用1位表示。
  • PVRTC4。4位PVR压缩纹理格式,PVR格式是专门为iOS设备上面的PowerVR图形芯片而设计的。它们在iOS设备上非常好用,因为可以直接加载到显卡上面,而不需要经过中间的计算转化。
  • PVRTC4A。具有Alpha通道的,4位PVR压缩纹理格式。
  • PVRTC2。2位PVR压缩纹理格式。
  • PVRTC2A。具有Alpha通道的,2位PVR压缩纹理格式。

此外,PVR格式在保存的时候还可以采用Gzip和zlib压缩格式进行压缩,对应的保存文件为pvr.gz和pvr.ccz。经过压缩文件会更小,加载的时候使用更少的内存!虽然是转化为纹理的时候,需要解压,但对于CPU影响很小。

 

2.纹理缓存异步加载

我们在启动游戏和进入场景时候,由于需要加载的资源过多就会比较“卡”,用户体验不好。我们可以采用纹理缓存(TextureCache)异步加载纹理图片,TextureCache类异步加载函数如下:

virtual void addImageAsync(const std::string &     filepath,
        std::function<  void(Texture2D *)> callback 
)

其中第一个参数文件路径,第二参数是回调函数。下面我们通过一个实例介绍一下纹理缓存异步加载使用,有200张小图片,加载到纹理缓存,加载过程会有一个进度显式在界面上,如图所示:

20141111195432638.jpg

纹理缓存异步加载实例

HelloWorldScene.cpp中主要代码如下:

bool HelloWorld::init()
{
    if ( !Layer::init() )
    {
        return false;
    }
 
 
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();
    auto closeItem = MenuItemImage::create(
        "CloseNormal.png",
        "CloseSelected.png",
        CC_CALLBACK_1(HelloWorld::menuCloseCallback, this));
 
 
    closeItem->setPosition(Vec2(origin.x + visibleSize.width - closeItem->getContentSize().width/2 ,
        origin.y + closeItem->getContentSize().height/2));
    auto menu = Menu::create(closeItem, NULL);
    menu->setPosition(Vec2::ZERO);
    this->addChild(menu, 1);
 
 
    _labelLoading = Label::createWithTTF ("loading...", "fonts/Marker Felt.ttf", 35);
    _labelPercent = Label::createWithTTF ("0%%", "fonts/Marker Felt.ttf", 35);
 
 
    _labelLoading->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2 - 20));
    _labelPercent->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2 + 20));
 
 
    this->addChild(_labelLoading);
    this->addChild(_labelPercent);
 
 
    _numberOfLoadedSprites = 0;
    _imageOffset = 0;
 
 
    auto sharedFileUtils = FileUtils::getInstance();
    std::string fullPathForFilename 
                = sharedFileUtils->fullPathForFilename("ImageMetaData.plist");              ①
 
 
    ValueVector vec = FileUtils::getInstance()->getValueVectorFromFile(fullPathForFilename);    ②
    _numberOfSprites = vec.size();                                            ③
    //加载纹理
    for( auto& e : vec)                                                   ④
    { 
        auto row = e.asValueMap();
        auto filename = "icons/" + row.at("filename").asString();      
        Director::getInstance()->getTextureCache()->addImageAsync(filename,
                CC_CALLBACK_1(HelloWorld::loadingCallBack, this));                 ⑤
    }
    return true;
}
 
 
void HelloWorld::loadingCallBack(Texture2D *texture)                              ⑥
{
    ++_numberOfLoadedSprites;
    __String* str = __String::createWithFormat("%d%%", 
                        (int)(((float)_numberOfLoadedSprites / _numberOfSprites) * 100));      ⑦
    _labelPercent->setString(str->getCString());                                  ⑧
 
 
    Size visibleSize = Director::getInstance()->getVisibleSize();
    int i = ++_imageOffset * 60;
 
 
    auto sprite = Sprite::createWithTexture(texture);                                ⑨
    sprite->setAnchorPoint(Vec2(0,0));
    addChild(sprite, -1);
    sprite->setPosition(Vec2( i % (int)visibleSize.width, (i / (int)visibleSize.width) * 60));
 
 
    if (_numberOfLoadedSprites == _numberOfSprites)                              ⑩
    {
        _numberOfLoadedSprites = 0;
    }
}

上述代码第①行代码是获得资源目录下ImageMetaData.plist 文件全路径,ImageMetaData.plist 文件是我们定义用来描述要加载图标文件名,文件内容如下:

< ?xml version="1.0" encoding="utf-8"?>
< !DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" 
                "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist  version="1.0">
  <array>
    <dict>
      <key>filename</key>
      <string>01-refresh.png</string>
    </dict>
    <dict>
      <key>filename</key>
      <string>02-redo.png</string>
    </dict>
    <dict>
      <key>filename</key>
      <string>03-loopback.png</string>
    </dict>
    <dict>
      <key>filename</key>
      <string>04-squiggle.png</string>
    </dict>
   … …  
  </array>
</plist>  

ImageMetaData.plist 文件是属性列表文件,内部结构是数组类型,我们可以通过第②行代码FileUtils 的getValueVectorFromFile函数读入到ValueVector类型变量vec中。第③行代码_numberOfSprites = vec.size()是获得数组的长度,然后赋值给成员变量_numberOfSprites为了能够计算加载进度。

第④行代码是循环遍历数组,数组结构中的每一个元素是键值对结构,取的键值对结构语句是auto row = e.asValueMap()。然后通过语句row.at(“filename”).asString()从键值对对象row中取出键为filename对应的值。

第⑤行代码是调用TextureCache的addImageAsync函数实现异步加载图片缓存,HelloWorld::loadingCallBack是回调函数,this参数表示回调函数的目标对象。

第⑥行是我们定义的回调函数实现。第⑦行代码在的表达式(int)(((float)_numberOfLoadedSprites / _numberOfSprites) * 100)可以计数出加装进度,”%d%%”可以显示百分号,其中的%d是格式化输出数字。%%是输出%,前面%起到转义作用。第⑧行代码_labelPercent->setString(str->getCString())是设置进度标签_labelPercent的内容。

第⑨行代码auto sprite = Sprite::createWithTexture(texture)是通过纹理对象texture创建精灵对象。第⑩行代码if (_numberOfLoadedSprites == _numberOfSprites)是判断是否完成任务,_numberOfLoadedSprites是已经加装的图片数,_numberOfSprites是要加装的全部图片数。

发表评论