關於cocos2d-x幾種畫圖方法的用法與思考




CCRenderTexture

自己的理解
CCRenderTexture類似一張空白的“畫布“,用戶通過自定義筆刷(CCSprite*),在touch事件中把筆刷的移動痕跡“記錄”起來,從而“畫”出各種藝術效果。記錄方法很簡單,首先CCRenderTexture調用自己的begin()函數,開啓“記錄”功能,然後調用筆刷->visit()把自己”畫“在這張畫布上,最後CCRenderTexture調用end()結束記錄,那就OK了。

這裏我想CCRenderTexture是通過把筆刷的紋理疊加到自己的紋理(Texture)裏,而不是不斷創建新紋理,所以消耗比較低,即使畫得很頻繁,幀數也能保持穩定,是個很讚的類。

CCRenderTexture由於只要begin()開啓“記錄”功能後,任何之後的CCNode*對象只要調用了visit(),就能將自己“畫”在其身上。所以,一般遊戲的截屏功能,完全可以使用CCRenderTexture的來實現,具體可以看tests裏例子,cocos2d-x已經提供了相關例子,看看源代碼就能搞明白的。

優點
用CCRenderTexture可以很簡單的實現出理想的畫圖效果(只要搞一張很小的筆刷圖,然後用CCSprite載入來,再適當調用一個CCSprite的visit()就行了),幀數消耗低,還很方便實現出遊戲的截屏功能,做《你畫我猜》這種項目,第一想到的應該就是它了。

缺點
由於每個Android手機的硬件或者OpenGL版本不一樣,導致有些手機用CCRenderTexture會出現花屏,比如HTC。就算是官方提供的tests例子也難逃一花屏,這個致命的缺點導致用它來實現的《你畫我猜》不能跨手機,比較坑爹…

這個Bug我想不是cocos2d-x引擎的問題,有牛人說是因爲Texture在重複畫導致的(只畫一次沒問題,所以截屏功能應該不受影響),也許是每臺Android手機的OpenGL不一樣吧,所以問題一直沒得到解決,只能等cocos2d-x或者有其他牛人以後可以把它Fixed掉。

因爲花屏問題,現階段不推薦使用(如果有牛人解決了花屏問題,請教教我,謝謝)


[ 花屏參考圖 ] 


例子
CCRenderTexture大概是大家比較熟悉的,tests裏也有相關例子,要知道用法直接看tests的源代碼就可以了,效果如圖:

 用OpenGL-ES實現畫圖

自己的理解
OpenGL-ES是OpenGL的精簡版,由於太精簡,很多OpenGL常用的函數都被“簡”掉了,導致有很多網上一搜一大把的畫圖算法用不上。所以用OpenGL-ES畫圖,這個感覺難度非常高。
在cocos2d-x中,OpenGL-ES一般在draw()這個函數裏面調用其相關函數。當然cocos2d-x也封裝了幾個常用的畫圖函數:ccDrawLine,ccDrawCircle等,當然cocos2d-x也提供了例子,在tests裏可以輕鬆找到。

優點
暫時沒想到,因爲我本身對OpenGL-ES不熟…

缺點
實現難度大可以攔截一大批人了,感覺。因爲不能像CCRenderTexture那樣在touch事件中進行繪圖,所以一般會把要畫的CCPoint在touch事件的記錄下來,然後在draw()這個函數裏遍歷之,以實現繪圖效果。
移動過的點一般都要保存下來,注意的是要全部保存,如果只保存當前點的話,draw()就只會畫一個點,畫出來的效果就像一個“光點”跟隨的鼠標移動,而不是繪圖。一般畫一幅畫,鼠標都會拖動出N個點,如果只是簡單的vector<CCPoint>保存的話,vector會超大,draw中遍歷它也很耗時,導致沒一會幀數就掉光了。具體怎麼保存看數據結構吧,同事以線段作爲數據結構來記錄點,這樣消耗不大,幀數也能保持穩定。

另外一個缺點就是如果算法實現不好,畫出來的效果很坑爹,同事的線段法雖然能很流暢的畫線,但是鋸齒問題很嚴重,開了OpenGL的抗鋸齒也沒效果。如果對OpenGL-ES很熟而且算法也很牛的話,也許draw()是最快最好的一種畫圖法了。
最後還一個超坑爹的缺點:draw()在Google那臺三星手機上,始終畫在最頂層顯示,然後線條就會把遊戲UI遮蓋住了,無論怎麼設置z-Order都沒用,估計是Google的三星手機的OpenGL-ES做過什麼特殊處理吧,導致“坑爹啊…”

[ 萬惡的鋸齒…]

例子
Cocos2d-x提供的相關例子(DrawPrimitivesTest),常見的畫直線、畫圓、畫Bezier線等,都有函數提供,具體還是自己打開tests看看源代碼吧,這裏就不詳述了。

[ DrawPrimitivesTest ]
 

CCSpriteBatchNode

自己的理解
用CCSpriteBatchNode生成的CCSprite共用一個紋理,這樣的好處是生成很多相同的CCSprite很高效,幀數可以很高很穩定。由於這個特點,用來實現粒子效果是一個很好的選擇,不過我還沒有看過cocos2d-x粒子系統的實現,這裏不做推測,以免誤導大家。關於CCSpriteBatchNode的用法當然還是tests裏面有,有興趣的朋友可以自己看看。

優點
由於draw()實現難度太高,而CCRenderTexture又有花屏的問題,所以嘗試用CCSpriteBatchNode來實現畫圖,繪圖效果很不錯,因爲是使用CCSprite做自定義筆刷嘛。幀數保持58-60,很穩定(如果只是單純的創建CCSprite*,然後addChild到Layer裏,掉幀會很嚴重的)

缺點
雖然CCSpriteBatchNode效果很不錯,不過也有一個致命的缺點,就是CCSpriteBatchNode*對象不能addChild太多的CCSprite*對象,同事做了一下實驗,大概addChild到16000+個CCSprite後,CCSpriteBatchNode就不能addChild了,也就是說,畫圖畫到16000+個點後,畫筆就“沒墨水”,導致鼠標再怎麼拖都沒效果。
查看了一下源代碼,大概是CCSpriteBatchNode在addChild時會重新分配內存,當需要分配的內存很大時,回導致內存分配失敗,從而CCSpriteBatchNode會將這次addChild無效掉。
解決思路有一個,就是來個計數,當CCSpriteBatchNode它addChild到10000個後,用CCRenderTexture截個圖保存當前的畫圖記錄,然後清空CCSpriteBatchNode和把計數置零,再來畫圖。這個操作會有延遲,所以沒有實現。

CCRibbon

自己的理解
CCRibbon應該說是一個線段集吧,與上述方法不同的是,它只能是單一顏色。就是說,你將它setColor爲紅,那麼你畫過的線條就全部爲紅,爲藍的話,則線條全部爲藍。
生成一個CCRibbon*對象需要指定:筆刷的寬度,筆刷的圖片,線段的長度,筆刷的顏色等參數(Fade最後這個參數暫時還沒搞懂意思…)。

CCRibbon提供addPointAt(CCPoint location, float width),將點以多寬加入到CCRibbon中,這裏cocos2d-x對這個點的大小進行計算,從而使線條達到“頭尾窄,身體寬”的效果。這個可以說是優點也可以說是缺點吧,“頭尾窄,身體寬”看起來比較像筆刷,不過想做出均勻的畫筆就不行了。

優點
幀數穩定,筆刷效果不錯。因爲CCRibbon也是用draw()進行畫圖,所以不用擔心CCRenderTexture那樣的花屏問題,CCRibbon目前感覺是比較理想的畫圖方法了。

缺點
如果在(100,100)點上一個點,然後跑去(400,400)再點一個點,CCRibbon會自動將兩個點連起來,如果用戶想做出平常畫圖那種“刷刷刷“的排線法,CCRibbon就不行了。解決方法就是每次TouchBegan都生成一個CCRibbon,這樣就不會出現這個問題了,不過生成太多的CCRibbon不知道會不會出現其他問題,比如CCSpriteBatchNode那個…
由於CCRibbon是單一顏色的,所以想畫彩色圖是不行的。解決方法當然還是像上面那樣,生個多個CCRibbon*對象,每個CCRibbon*對象的顏色不同就行了。

最後感覺不太人性化的就是畫筆只能“頭尾窄,身體寬“,如果想畫出”頭身尾均勻“的線條,用CCRibbon也許做不了。

例子
Cocos2d-x沒有直接給出CCRibbon的例子,所以這個不能夠在tests上看到使用方法,不過自己稍稍嘗試一下就行了,用法挺簡單。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章