OpenGL是一個基於C語言的三維圖形API,是一個開放的、跨平台的圖形接口。
OpenGL ES是OpenGL在移動設備上的版本。
Cocos2d-x是一個基於OpenGL的游戲引擎,渲染功能由OpenGL實現。
游戲中會用到許多圖片資源,對圖片資源渲染進行優化能明顯提高效率。
OpenGL中紋理的長和寬像素是2的冪,大小不足的紋理補充到2的冪大小;可以通過把多張小圖片合成一張大圖加載到游戲中,減少紋理加載次數,減少補齊2的冪大小的空白。
之前學習的紋理緩存、精靈幀緩沖可以把紋理等預先加載到內存中,訪問時候節省訪問時間;除此之外還可以通過CCSpriteBatchNode節省渲染次數來達到優化的目的。
CCSpriteBatchNode(精靈批處理類):
原理借鑒一下權威指南內容:
當你需要顯示兩個或兩個以上相同的精靈時,如果逐個渲染精靈,每一次渲染都會調用OpenGL的函數;
因為當系統在屏幕上渲染一張貼圖的時候,圖形處理硬件必須首先准備渲染,然后渲染圖形,最后完成渲染以后的清理工作。
以上是每次渲染固定的開銷,這樣幀率就會下降15%左右或者更多。
如果將所有需要渲染的同一張貼圖只進行一次准備,一次渲染,一次清理就可以解決這個問題了。
這時可以使用CCSpriteBatchNode類來批處理這些精靈。
CCSpriteBatchNode:
先來看看它的創建相關代碼:
class CC_DLL CCSpriteBatchNode : public CCNode, public CCTextureProtocol
{
public:
static CCSpriteBatchNode* create(const char* fileImage, unsigned int capacity);
static CCSpriteBatchNode* create(const char* fileImage)
{
return CCSpriteBatchNode::create(fileImage, kDefaultSpriteBatchCapacity);
}
static CCSpriteBatchNode* createWithTexture(CCTexture2D* tex, unsigned int capacity);
static CCSpriteBatchNode* createWithTexture(CCTexture2D* tex)
{
return CCSpriteBatchNode::createWithTexture(tex, kDefaultSpriteBatchCapacity);
}
} 由上述代碼可以看到CCSpriteBatchNode可以通過圖片文件直接創建,也可以通過紋理來創建。
CCSpriteBatchNode
(一)、通過圖片文件創建CCSpriteBatchNode並且使用它
static CCSpriteBatchNode* create(const char* fileImage, unsigned int capacity);
static CCSpriteBatchNode* create(const char* fileImage)
{
return CCSpriteBatchNode::create(fileImage, kDefaultSpriteBatchCapacity);
}
通過紋理圖片直接創建精靈批處理我們可以使用兩個創建函數,不過由上述代碼可以看出其實只有一個創建函數;
只指定紋理圖片路徑名稱時候,其第二個參數capacity(表示紋理圖像容量)為一個系統默認值,並且此函數調用的為兩個參數的create函數。
實例:
CCSpriteBatchNode* batchNode = CCSpriteBatchNode::create("HelloWorld.png");
for (int i = 0; i < 50; i++)
{
CCSprite* sprite = CCSprite::create("HelloWorld.png");
batchNode->addChild(sprite);
}
addChild(batchNode);首先,通過紋理圖片創建一個精靈批處理;
之后,通過循環創建50個精靈,把這50個精靈添加到批處理當中;
最后把批處理加入到父節點。
(二)通過CCTexture2D創建CCSpriteBatchNode並且使用它
實例一:通過紋理緩存中取得紋理創建精靈批處理,此后創建精靈時候可以使用紋理圖片名字創建。
CCTexture2D * texture = CCTextureCache::sharedTextureCache()->addImage("HelloWorld.png");
CCSpriteBatchNode* batchNode = CCSpriteBatchNode::createWithTexture(texture);
for (int i = 0; i < 29; i++)
{
CCSprite* sprite = CCSprite::create("HelloWorld.png");
batchNode->addChild(sprite);
}
addChild(batchNode);
CCTexture2D * texture = CCTextureCache::sharedTextureCache()->addImage("HelloWorld.png");
CCSpriteBatchNode* batchNode = CCSpriteBatchNode::createWithTexture(texture);
for (int i = 0; i < 50; i++)
{
CCSprite* sprite = CCSprite::createWithTexture(texture);
batchNode->addChild(sprite);
}
addChild(batchNode);
上訴兩種方式實際上使用起來同樣效果,解釋如下:
首先,通過紋理緩存獲取一個紋理;
之后,通過循環創建50個精靈,把這50個精靈添加到批處理當中,此時創建精靈的時候可以使用紋理圖片名稱,也可以使用之前從紋理緩沖中獲取的紋理;
最后把批處理加入到父節點。
實例二:通過直接創建一個紋理(CCTexture2D)來創建精靈批處理,此后精靈創建時候必須使用之前創建的紋理來創建精靈。
CCImage* image = new CCImage();
image->initWithImageFile("HelloWorld.png");
image->autorelease();
CCTexture2D* texture = new CCTexture2D();
texture->initWithImage(image);
texture->autorelease();
CCSpriteBatchNode* batchNode = CCSpriteBatchNode::createWithTexture(texture);
for (int i = 0; i < 50; i++)
{
CCSprite* sprite = CCSprite::createWithTexture(texture);
batchNode->addChild(sprite);
}
addChild(batchNode);
首先,通過new的方式獲取一個紋理;
之后,通過循環創建50個精靈,把這50個精靈添加到批處理當中,此時的精靈需要用到之前創建的紋理來創建;
最后把批處理加入到父節點。
實例三:加載多張圖片使用
CCSpriteFrameCache::sharedSpriteFrameCache()->addSpriteFramesWithFile("batch.plist");
CCSpriteBatchNode* batchNode = CCSpriteBatchNode::create("bach.png");
addChild(batchNode);
上訴代碼在精靈幀緩沖中加入一個plist文件;
利用plist對應的圖片創建CCSpriteBatchNode;
之后
static bool flag = true;
CCSprite * sprite;
for (int i = 0; i < 1000; i++)
{
if (flag)
{
sprite = CCSprite::createWithSpriteFrameName("one.png");
}
else{
sprite = CCSprite::createWithSpriteFrameName("two.png");
}
flag = !flag;
sprite->setPosition(ccp(CCRANDOM_0_1() * 480, CCRANDOM_0_1() * 320));
batchNode->addChild(sprite);
}之前把紋理圖片添加到精靈幀緩沖中后使用CCSpriteBatchNode創建同一張圖片;
此后通過精靈幀緩沖中的精靈幀創建精靈同樣為優化后的。
總結:
當我們需要多次使用同一張紋理創建的精靈時候使用它。
因為所有CCSprite節點都添加到同一個CCSpriteBatchNode中,所以所有CCSprite的zOrder相同。
添加到同一個CCSpriteBatchNode中的CCSprite必須使用同一個紋理圖片。
精靈幀緩沖(CCSpriteFrameCache)與精靈批處理(CCSpriteBatchNode)結合使用效果更好!
