本次教程的參考文章有:himi的博客文章關於CCSpriteBatchNode的, http://blog.csdn.net/xiaominghimi/article/details/6761811
子龍山人的翻譯文章:http://www.cnblogs.com/zilongshanren/archive/2011/04/11/2012770.html
如果你對cocos2d-x編程不瞭解,可以先閱讀《用cocos2d-x做一個簡單的windows phone 7遊戲》系列文章。不過,如果你有相關的經驗就另當別論了。
如果你從來沒有使用過spritesheet,你可以把它看作是一張巨大的圖片,你可以把許許多多的sprite放進去。與spritesheet對應的,還有一個plist文件,這個文件指定了每個獨立的sprite在這張“大圖”裏面的位置和大小,當你在代碼之間需要使用這個sprite的時候,就可以很方面地使用plist文件中的這些信息來獲取sprite。
使用CCSpriteBatchNode來獲取spritesheet裏面的精靈可以提高效率。
爲什麼這會提高效率呢?因爲cocos2d-x對它進行了優化!如果你使用spritesheet來獲取sprite,那麼當場景中有許多sprite的時候,如果這些sprite共享一個spritesheet,雖然在XNA裏面沒有OpenGL ES,不過渲染方式也差不多,以 XNA 爲基礎的遊戲可以在呼叫 spriteBatch 物件的 Begin 方法和呼叫 spriteBatch 物件的 End 方法之間執行多個繪製圖形和文字的文字,由 XNA Framework 以批次的方式一次顯示多個圖形內容。那麼cocos2d-x就會使用一次spriteBatch呼叫來繪製這些sprite。但是,如果是單個的sprite的話,那麼就會有N次spriteBatch呼叫,這個代價是相當昂貴的。其優化也不過在於減少了對spriteBatch的Begin和End方法的調用。
簡而言之--使用spritesheet會更快,尤其是當你有很多的sprite的時候!
Zwoptex To Victory!
雖說plist就是一個文件, 但是手動用圖片編輯器編輯圖片後再編輯plist文件也是相當麻煩的事情,這裏用到一個免費的工具,Zwoptex.我用的是flash版,安裝版是收費版的。畢竟我們就是編輯個圖片,flash版就夠了。
先下載這次教程需要的圖片,用的圖片是子龍山人翻譯的文章原作者ray的圖片,熊行走的圖片(用這圖片,主要是找圖片困難,而且最主要的原因,我的畫圖水平真的很菜,PS就是在會用的水平,哎,沒有美工的日子)
下面下載Zwoptex,http://zwopple.com/zwoptex/static/downloads/zwoptex-flashversion.zip,這個鏈接還真是在網站上有點難找,所以直接貼出鏈接。下載完畢,然後解壓後打開Zwoptex.html。
然後可以開始創建spritesheet了。點擊File/import images,把所有的bear圖片8張全部選中,然後點擊打開加入到工程中,你會發現所有圖片都重疊在一塊了。我們現在並不需要這麼大的圖片,點擊Modify/Canvas width,選中512px,這麼大就夠了,然後點擊Array/by Name &Height,這時發現熊是每兩個一排,總共4排,這時,對圖片的編輯就算是完了。然後就導出吧。點擊File/Export Texture.保存爲AnimBear.png。然後繼續點擊File/Export coordinates。保存爲AnimBear.plist.
現在打開VS2010,新建一個cocos2d-x的工程,命名爲cocos2dBearRunDemo,同樣的,OpenXLIve插件不用。和以前的工程一樣,修復DLL引用是必須的。由於這次示例比較簡單,所以直接在HelloWorldScene裏面修改了。那麼就把HelloworldScene裏面的init方法清理下吧。
在Content工程裏面新建一個resource文件夾,並且在resource文件夾裏面新建一個images文件夾,並且把AnimBear.png添加到resource/images裏面,AnimBear.plist添加到resource文件夾內。然後在解決方案管理器裏面選擇AnimBear.plist文件。選擇屬性。然後修改ContentImporter和ContentProcessor,如下:
如果你的不能出現這兩個選項,敬請查看Content的引用,確認cocos2d.Content.Pipeline.Importers的引用沒有顯示爲歎號。如果有,移除後重新添加。
然後直接打開AnimBear.plist文件。刪除下面紅色框的那行後保存。
爲什麼要刪除這麼一行呢,因爲XNA版的cocos2d-x是用XML的解析方法,這行不能跳過,會報錯。所以,直接刪除即可。
現在,打開HelloWorldScene文件。開始真正的動畫製作。下面都是在Init裏面修改.
爲了獲得動畫效果,我們有5個步驟需要做。接下,將會一個步驟一個步驟給大家講解。
1) 緩衝sprite幀和紋理
CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile(@"resource/AnimBear");
首先,調用CCSpriteFrameCache的addSpriteFramesWithFile方法,然後把Zwoptex生成的plist文件當作參數傳進去。這個方法做了以下幾件事:
- 尋找工程目錄下面和輸入的參數名字一樣,但是後綴是.png的圖片文件。然後把這個文件加入到共享的CCTextureCache中。(這我們這個例子中,就是加載AnimBear.png,由於XNA工程的AssetName的問題,兩個一樣名字的文件會發生衝突(這個與文件後綴無關),所以把AnimBear.png文件放在了下一級目錄中。)
- 解析plist文件,追蹤所有的sprite在spritesheet中的位置,內部使用CCSpriteFrame對象來追蹤這些信息。
CCSpriteBatchNode spritesheet = CCSpriteBatchNode.batchNodeWithFile(@"resource/images/AnimBear");
this.addChild(spritesheet);
接下來,創建CCSpriteBatchNode對象,把spritesheet當作參數傳進去。spritesheet在cocos2d中的工作原理如下:
- 你創建一個CCSpriteBatchNode對象,通過傳遞一個包含所有sprite的spritesheet的名字作爲參數,並把它加入到當前場景之中。接下來,你從spritesheet中創建的任何sprite,你應該把它當作CCSpriteBatchNode的一個孩子加進去。只要sprite包含在spritesheet中,那麼就沒問題,否則會出錯。
- CCSpriteBatchNode可以智能地遍歷它的所有的孩子結點,並通過一次spriteBatch的呼叫來渲染這些孩子,而不是以前每個sprite都需要一個spriteBatch呼叫,這樣渲染速度就會更快。
List<CCSpriteFrame> walkAnimFrames = new List<CCSpriteFrame>();
for (int i = 1; i <= 8; i++)
{
walkAnimFrames.Add(CCSpriteFrameCache.sharedSpriteFrameCache().spriteFrameByName(String.Format("bear{0}.png", i)));
}
爲了創建一系列的動畫幀,我們簡單地遍歷我們的圖片名字(它們是按照Bear1.png-->Bear8.png的方式命名的),然後使用共享的CCSpriteFrameCache來獲得每一個動畫幀。記住,它們已經在緩存裏了,因爲我們前面調用了addSpriteFramesWithFile方法。
4) 創建動畫對象
CCAnimation animation = CCAnimation.animationWithFrames(walkAnimFrames, 0.1f);
接下來,我們通過傳入sprite幀列表來創建一個CCAnimation對象,並且指定動畫播放的速度。我們使用0.1來指定每個動畫幀之間的時間間隔。
5) 創建sprite並且讓它run動畫action
CCSize winSize = CCDirector.sharedDirector().getWinSize();
CCSprite bear = CCSprite.spriteWithSpriteFrameName(@"bear1.png");
bear.position = new CCPoint(winSize.width / 2, winSize.height / 2);
var walkAction = CCRepeatForever.actionWithAction(CCAnimate.actionWithAnimation(animation, false));
bear.runAction(walkAction);
spritesheet.addChild(bear);
我們首先通過spriteframe來創建一個sprite,並把它放在屏幕中間。然後,生成CCAnimationAction,並賦值給場景的walkAction屬性,最後讓熊來運行這個action。
最後,我們把熊加個場景中--把它當作spritesheet的孩子加到spritesheet中去。注意,如果在這裏我們沒有把它加到spritsheet中,而是加到當前層裏面的話。那麼我們將得不到spritesheet爲我們帶來的性能提升!!!
完成了!
另外,由於我們只有一個場景,要添加一個label才能使sprite的背景透明,這個暫時不清楚是什麼原因。那麼就添加一個吧。
CCLabelTTF label = CCLabelTTF.labelWithString("Bear walk", "Arial", 32);
label.position = new CCPoint(winSize.width / 2, winSize.height - 80);
this.addChild(label);
現在運行,就能看到熊在走了。
那麼怎麼讓熊轉向呢,設置熊的屬性bear.IsFlipX = true;也就是X軸翻轉。就能使熊翻轉過來了。當然,也能豎直翻轉。
另外摘抄些注意事項:
使用CCSpriteBathNode雖然能達到優化,但是要注意一點:
初始化精靈集合CCSpriteBatchNode的時候會加載一張圖片資源(或者pvr文件等),那麼限制其精靈集合的子精靈都必須使用集合加載的這張圖纔行,否則會給出警告;
使用CCSpriteBatchNode還要注意一點,因爲精靈都存放在集合中,那麼這個集合CCSpriteBatchNode中的節點(精靈)都將在同一個z軸上,同一深度上;
本次教程就到此結束了。示例代碼下載:http://dl.dbank.com/c04ey6mse6