1.紋理控制。
Sprite *pSprite = Sprite::create("background.png"); TexParams params = {GL_NEAREST,GL_NEAREST,GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE}; pSprite->getTexture()->setTexParameters(params);
上面最重要的函數就是setTexParameters();他就是根據ccTexParameters來控制紋理圖像的紋理如何對應到屏幕的像素。根據什么來實現紋理的縮放和紋理的重復(重復紋理)等效果。
/** Extension to set the Min / Mag filter */ typedef struct _TexParams { GLuint minFilter;//紋理過濾器:縮小過濾器 GLuint magFilter;//紋理過濾器:放大過濾器 GLuint wrapS;//橫向紋理尋址模式 GLuint wrapT;//縱向紋理尋址模式 }TexParams;
先看看TexParams這個結構體,他的前兩個成員變量叫做基本過濾器。用來指定按照什么規則來控制紋理的縮放效果。
兩個基本的紋理過濾規則:
(1)GL_LINEAR:“當顯示紋理時,顯示的大小大於或者小於原紋理的尺寸時,使用鄰近像素點來插值補點”
特點:圖像拉伸或者縮小后,看起來失真了,但是效果比GL_NEAREST好,看起來沒有人工操作后的痕跡.
(2)GL_NEAREST:(最鄰近過濾)最簡單最快捷的過濾方式。
特點:當紋理拉伸到特別大的時候,會出現大片斑駁狀像素。
TexParameters后面的兩個成員變量叫做紋理環繞模式.是用來控制當繪制紋理邊界范圍之外的像素點的時候應該怎么去處理。openGL紋理的坐標范圍是(0.0f, 1.0f).意思就是當紋理坐標大於1.0f或者紋理坐標小於0.0f的時候怎么去處理紋理。
兩個常用的紋理環繞模式:
(1)GL_REPEAT:在紋理超過1.0f的方向上對紋理進行重復。如果你想顯示紋理邊界之外的像素點時,把它旁邊的紋理像素點平鋪過去 .
cocos2d::Texture2D::TexParams tp ; tp.minFilter = GL_LINEAR; tp.magFilter = GL_LINEAR; tp.wrapS = GL_REPEAT; tp.wrapT = GL_REPEAT; matteLayer=Sprite::create("middle_background.png"); matteLayer->retain(); matteLayer->setPosition(s.width/2,s.height/2); matteLayer->setScale(4.0f, 4.0f); matteLayer->getTexture()->setTexParameters(tp); this->addChild(matteLayer); this->schedule(schedule_selector(BackgroundLayer::changColor), 1.0f); this->schedule(schedule_selector(BackgroundLayer::scrollBackground), 0.01f);
在scrollBackground()中:
void BackgroundLayer::update(float dt){ int nLen = 100; static int nOffset = 0; nOffset += nLen*dt; matteLayer->setTextureRect(Rect(0,-nOffset, matteLayer->getTexture()->getPixelsWide(),matteLayer->getTexture()->getPixelsHigh())); }
上面的代碼通過不斷增加nOffset來繪制精靈的紋理邊界之外的區域。由於之前設置了環繞模式為GL_REPEAT。則繪制精靈之外的區域的時候把旁邊的紋理像素進行平鋪。形成重復紋理的效果。
程序中這個精靈的紋理不斷的會從右向左滾動。注意:精靈的位置不會發生變化.這就用GL_REPEAT來實現了重復紋理的效果.
還需要注意的是RepeatSprite.png的寬和高必須是2的N次方大小。否則的話當你用GL_REPEAT來作為環繞模式的時候會出現警告提示:GL_REPEAT mode must be POT.意思就是用GL_REPEAT模式圖片大小必須是2的指數冪(POT).警告提示完了之后就是崩潰.
(2)GL_CLAMP:作用就是紋理的繪制坐標大於1.0則就設置成1.0, 小於0.0則設置成0.0;
如果繪制的x坐標大於了紋理寬度,則就用紋理最右邊的一個像素來繪制后面的區域.
2.紋理緩沖區.(TextureCache)
Sprite::create()這個函數里面有句代碼:auto TexureCache=Director::getInstance()->getTextureCache();
精靈就是用這句代碼來根據提供的圖片生成精靈的紋理對象。所以,不難看出用圖片創建了精靈對象時,圖片數據被加載到內存中,這塊內存就叫做紋理緩沖區(TextureCache),只要不手動就從紋理緩沖區中把圖片數據刪除則圖片數據永遠占着內存不釋放。所以這就帶出了針對紋理緩沖區的一些議題.cocos2d中存放被加載的圖片數據的緩沖區(內存)分兩類:存放由多個小圖拼接成的大圖的區域 和 存放單個圖片的區域。具體分別對應於SpriteFrameCache和 TextureCache這兩個類。
為什么會存在這兩個類呢?從名字就知道他們是緩沖區,存在的唯一理由是下次如果需要同一個圖片數據的時候直接從緩沖區去取,而不需要再次把圖片文件載入到內存中去。這樣的話節省了內存還提高了渲染速度。
假設有一張圖片example.png被加載到緩沖區中去,如果這張圖片是第一次被加載到內存,則它首先被加載到緩沖區中去,然后再從緩沖區中讀取出來,用於創建紋理對象。
如果這個圖片的數據在內存中沒有被刪除,則在隨后程序員又想用圖片example.png來創建紋理對象的時候,cocos2d首先從紋理緩沖區中查找一下看是否存在這個圖片的數據。如果存在就直接從緩沖區中讀取。就不需要再次從硬盤載入到內存。多么方便啦!難道不是嗎?這樣為你節省了內存和提高了效率。
釋放:
如果游戲有很多場景,在切換場景的時候可以把前一個場景的內存全部釋放,防止總內存過高.
Director::getInstance()->getTextureCache()->removeAllTextures(); 釋放到目前為止所有加載的圖片
Director::getInstance()->getTextureCache()->removeUnusedTextures();將引用計數為1的圖片釋放掉
Director::getInstance()->getTextureCache()->removeTexture();單獨釋放某個圖片
SpriteFrameCache 與 TextureCache 釋放的方法差不多。
值得注意的是釋放的時機,一般在切換場景的時候釋放資源,如果從A場景切換到B場景,調用的函數順序為B::init()---->A::exit()---->B::onEnter() 可如果使用了切換效果,比如CTransitionJumpZoom::transitionWithDuration這樣的函數,則函數的調用順序變為B::init()---->B::onEnter()---->A::exit() 而且第二種方式會有一瞬間將兩個場景的資源疊加在一起,如果不采取過度,很可能會因為內存吃緊而崩潰。
有時強制釋放全部資源時,會使某個正在執行的動畫失去引用而彈出異常,可以調用Director::getInstance()->getActionManager()->removeAllActions();來解決。