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张小图片,加载到纹理缓存,加载过程会有一个进度显式在界面上,如图20-25所示。
html
纹理缓存异步加载实例数组
HelloWorldScene.cpp中主要代码以下:
缓存
[html] view plaincopy微信
bool HelloWorld::init() app
{ 异步
if ( !Layer::init() ) 函数
{ oop
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 文件是咱们定义用来描述要加载图标文件名,文件内容以下:
[html] view plaincopy
<?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是要加装的所有图片数。
更多内容请关注国内第一本Cocos2d-x 3.2版本图书《Cocos2d-x实战:C++卷》
本书交流讨论网站:http://www.cocoagame.net
更多精彩视频课程请关注智捷课堂Cocos课程:http://v.51work6.com
欢迎加入Cocos2d-x技术讨论群:257760386
欢迎关注智捷iOS课堂微信公共平台