cocos2d精靈與動畫詳解

ps:雖說cocos2d的,但是cocos2d-x在架構及結構上與cocos2d大同小異,故此文亦適用於cocos2d-x。

通過對導演、場景、層和節點的剖析,現在我們已經可以寫出一個完整的遊戲體系了,在實際應用中,場景一般都是作爲遊戲的關卡,層作爲場景的組成元素(比如UI層,背景層), 導演根據遊戲的勝負來激活不同的場景,作爲關卡的切換。(以上是常規遊戲的流程,僅作參考)

但是,單憑這些還不能作出一款高質量的遊戲,優秀的遊戲不僅要能玩,最關鍵的還要好玩,好玩的遊戲自然少不了絢麗多彩的視覺效果。和其它主流2D引擎一樣,cocos2d的圖形顯示也是靠精靈實現的,就是說,遊戲中不論是UI還是人物、背景,只要是我們能看到的,都和精靈脫不了干係,因此它是我們在開發中打交道最多的類之一,本章咱們就重點研究一下cocos2d的精靈體系。

在研究代碼之前,我們先要搞清楚精靈是什麼,它的職能有哪些,這裏我先給沒有接觸過遊戲開發的童鞋普及一下,有過開發經驗的可自行跳過~

說白一點,精靈就是將圖形資源加載到內存中,並根據遊戲需要將其顯示到屏幕中的工具,遊戲中大到背景、UI,小到NPC、道具,只要是用圖片展示的,都是精靈或它的子類。從技術上講,精靈是一個可以不斷變化的圖片,這些變化包括:位置移動、旋轉、縮放、換幀(就是像動畫片一樣播放幾張連續的圖片,每幀換一張,形成一個動畫效果)。其實我在前兩章的例子中已經用到了精靈,當然只是使用了它的幾個基本方法,現在我就較爲系統的解釋一下它的工作原理。

 精靈相關類的關係圖

CCSprite

這個類就是cocos2d中的精靈類,它可以說是CCNode在遊戲中的主要表現形式(它繼承自CCNode),在代碼中我們可以這樣理解,CCSprite除了節點的功能外,還封裝了一張圖片,在遊戲中一個2D圖形就是一個精靈類的對象。還有一點我們需要注意,就是cocos2d是用3d的方式繪製2d圖形的,精靈繪製圖像用的是openGL ES(移動平臺用的3d引擎,android用的也是它),因此圖片在內存中實際上是以Texture(貼圖)的形式存在的。下面我們來看看它的方法有哪些:

+(id)spriteWithTexture:(CCTexture2D*)texture

根據一個CCTexture2D創建並返回一個精靈對象,就是封裝了alloc、init和autorelease的靜態初始化方法。前面說過,精靈是用Texture繪製的,CCTexture2D就是封裝了Texture的類,精靈必須被賦予一個CCTexture2D的對象才能工作。

+(id)spriteWithTexture:(CCTexture2D*)texture rect:(CGRect)rect

增加了讀取範圍的創建方法,該方法只會將範圍內的圖像加載到精靈中。

+(id)spriteWithFile:(NSString*)filename

根據圖片資源創建並返回精靈對象,filename是文件(通常是png)的相對路徑,即前面省略了bundle的路徑。

+(id)spriteWithFile:(NSString*)filename rect:(CGRect)rect

也是根據圖片資源創建並返回精靈對象,只是增加了讀取範圍,只會加載範圍內的圖像。

+(id)spriteWithSpriteFrame:(CCSpriteFrame*)spriteFrame

根據一個CCSPriteFrame對象創建並返回一個精靈對象,CCSPriteFrame是幀,它是組成動畫的一部分,CCSPriteFrame的成員變量中有一個Texture,用幀創建精靈,其實就是用幀的Texture創建精靈,當精靈切換幀時,Texture也會隨之更換,精靈就會呈現不同的形態,以次達到動畫的效果。這裏大家可以理解爲,Texture和Frame都可以構成一個精靈對象。

+(id)spriteWithSpriteFrameName:(NSString*)spriteFrameName

根據幀的名字創建並返回一個精靈對象。這裏要引入一個概念,就是cocos2d中的幀是由一個單例對象統一管理的,這個單例的作用就是充當一個內存池,它將需要使用的CCSpriteFrame對象保存到自己內部的一個字典中,當有精靈需要用到它時,就從池中取出來傳遞過去,如果有多個精靈需要一個Frame的話,可以共用一個,而不必拷貝N份,這樣可以節約內存和創建對象的時間。這裏的參數spriteFrameName其實就是字典的Key,內存池先通過它找到Frame對象,再用它去創建精靈。

+(id)spriteWithCGImage:(CGImageRef)image key:(NSString*)key

根據一個CGImageRef對象創建並返回精靈對象,這個過程比較糾結,大家看仔細,千萬別造成誤解……

首先CCTexture2D和CCSpriteFrame一樣,都有內存池機制,參數key就是鍵值,該方法先在內存池中查找_和key匹配的Texture,如果有則直接用它創建精靈,如果沒有就根據參數中的image,先生成一個UIImage對象,再用這個對象生成CCTexture2D的對象,用它來創建精靈並將其存入內存池(鍵值爲key)。

+(id) spriteWithBatchNode:(CCSpriteBatchNode*)batchNode rect:(CGRect)rect

這裏又引入了一個新的類–CCSpriteBatchNode,它是一個批量處理精靈繪製的類,具體什麼意思呢?

精靈是用openGL的方法繪製圖形的,這點大家都清楚了,當場景中有100個精靈的時候,程序的執行是這樣的:for(int i= 0;i<100;i++){open-draw-close;},就是說執行了100次的open-draw-close;而用CCSpriteBatchNode繪製的話則是這樣執行的:open-for(int i= 0;i<100;i++){draw;}- close,即省略了99次的open和close,從而優化了精靈的繪製效率。這裏就是用CCSpriteBatchNode中的Texture創建精靈,並把精靈添加到batchNode中。

-(id) initWithTexture:(CCTexture2D*)texture rect:(CGRect)rect

最標準的精靈初始化方法,也是spriteWithTexture:rect:調用的方法,作用就是根據一個CCTexture對象對精靈進行初始化(只載入rect範圍內的圖形)。

-(id) initWithTexture:(CCTexture2D*)texture

缺省了rect參數的初始化,默認爲將Texture的全部載入。

-(id) initWithFile:(NSString*)filename

spriteWithFile調用的方法,根據資源的文件名初始化精靈,就是先用文件名裝載Texture,再用Texture初始化。

-(id) initWithFile:(NSString*)filename rect:(CGRect)rect

可自行設定圖片範圍的initWithFile方法。

- (id) initWithSpriteFrame:(CCSpriteFrame*)spriteFrame

-(id)initWithSpriteFrameName:(NSString*)spriteFrameName

- (id) initWithCGImage:(CGImageRef)image key:(NSString*)key

-(id) initWithBatchNode:(CCSpriteBatchNode*)batchNode rect:(CGRect)rect

這些都是上面介紹的靜態方法調用的初始化,原理相同,就不一一介紹了。

-(CCSpriteBatchNode*) batchNode

獲取精靈的批處理節點。

-(void) setBatchNode:(CCSpriteBatchNode *)batchNode

設置精靈的批處理節點。

-(void) setTextureRect:(CGRect)rect

設置Texture的區域,和初始化中rect的作用是一樣的,這裏是動態修改。

-(void) draw

繪製

-(void) addChild:(CCSprite*)child z:(NSInteger)z tag:(NSInteger) aTag

和CCNode的作用一樣,但加了一些限制:當精靈被批處理節點管理時,只能添加精靈作爲自己的子節點;精靈和它的子節點的Texture都必須和批處理節點相同。

-(void)removeChild: (CCSprite *)sprite cleanup:(BOOL)doCleanup

和CCNode的作用一樣,另外加了一個功能,如果精靈被一個批處理節點管理,則將其從批處理節點中刪除。

-(void)setPosition:(CGPoint)pos

-(void)setRotation:(float)rot

-(void)setSkewX:(float)sx

-(void)setSkewY:(float)sy

-(void)setScaleX:(float) sx

-(void)setScaleY:(float) sy

-(void)setScale:(float) s

-(void) setVertexZ:(float)z

-(void)setAnchorPoint:(CGPoint)anchor

-(void)setIsRelativeAnchorPoint:(BOOL)relative

-(void)setVisible:(BOOL)v

-(void)setFlipX:(BOOL)b

-(void) setFlipY:(BOOL)b

這些都和CCNode中的功能一樣(其實到了這裏這些方法纔算真正有了用武之地),就不贅述了。

-(void) setOpacity:(GLubyte) anOpacity

這是精靈新擴展的方法,作用是設置透明度,0爲全透明,255爲不透明。

-(void) setColor:(ccColor3B)color3

設置精靈顏色,就是改變圖片的色相。

-(void) setDisplayFrame:(CCSpriteFrame*)frame

切換精靈當前顯示的圖象,之前說過精靈是可以播放動畫的,播放動畫的實質就是切換Frame,都是靠該接口實現的。

-(void) setDisplayFrameWithAnimationName: (NSString*) animationName index:(int) frameIndex

將動畫序列中的某一幀設置爲精靈當前的顯示幀。CCAnimation是封裝動畫功能的類,它可以看作是由若干個_CCSpriteFrame對象組成的序列,精靈按照順序切換它們,就形成了動畫。CCAnimation也有內存池,此處的animationName就是key,內存池通過它找到CCAnimation對象,再通過索引frameIndex找到動畫序列中的某一幀,將該幀設爲精靈的當前顯示幀。

-(BOOL) isFrameDisplayed:(CCSpriteFrame*)frame

判斷精靈當前顯示的幀是否爲參數frame,判斷的依據是它們的成員texture的名字和rect是否相同。

-(CCSpriteFrame*) displayedFrame

獲取精靈當前顯示的幀。

-(void) setTexture:(CCTexture2D*)texture

設置精靈當前顯示的貼圖,作用其實和setDisplayFrame,都是改變精靈的形態,只不過這個方法是直接改Texture(setDisplayFrame內部也調用了該方法)。

-(CCTexture2D*) texture

獲取精靈當前顯示的貼圖。

CCSpriteBatchNode

這個類在前面也介紹了一些,它的作用是優化精靈,提高精靈的繪製效率,精靈數量越多,效果越明顯。它的工作原理是:將所有該對象的子節點(只能是精靈)用openGL的渲染方法一次性繪製,這樣可以省去多次open-close的時間,_作爲CCSpriteBatchNode對象子節點的精靈不能用自己的Texture繪製,而是用CCSpriteBatchNode對象的Texture統一繪製,精靈只是提供座標、旋轉角度等信息,這就是它只需要open-close一次的原因,但也正因爲如此,導致批處理節點的所有子節點都必須和它用同一套Texture,即CCSpriteBatchNode對象繪製出的圖形都是一樣的,這點需要格外注意。CCSpriteBatchNode的用法和普通精靈沒什麼兩樣,都可以設置Texture,也都是用Texture來繪製,只要通過addChild方法成爲其子節點的精靈,都會得到它的優化,但是CCSpriteBatchNode只能添加精靈爲子節點。

+(id)batchNodeWithTexture:(CCTexture2D *)tex

和精靈的方法類似,根據一個CCTexture2D對象構建一個精靈批處理節點,封裝了alloc、init和autorelease方法。

+(id)batchNodeWithFile:(NSString*)fileImage capacity:(NSUInteger)capacity

根據文件名創建精靈批處理節點,fileImage是文件名,先通過它創建Texture,再將其添加進對象。

+(id)batchNodeWithFile:(NSString*) imageFile

根據文件名創建精靈批處理節點,缺省了capacity參數。

-(id)initWithTexture:(CCTexture2D *)tex capacity:(NSUInteger)capacity

根據Texture初始化。

-(id)initWithFile:(NSString *)fileImage capacity:(NSUInteger)capacity

根據文件名初始化。

-(void) addChild:(CCSprite*)child z:(NSInteger)z tag:(NSInteger) aTag

添加子節點,子節點必須是精靈,且精靈的Texture和批處理節點相同。

-(void) setTexture:(CCTexture2D*)texture

設置Texture。

-(CCTexture2D*) texture

獲取Texture。

CCTexture2D

該類封裝的就是一直提到的Texture(貼圖),在3D渲染中,它是必不可少的,因此雖然大部分情況下由於封裝的原因,被精靈蓋在底層,但重要性還是相當的高。不過反過來說,該類的方法幾乎都是被精靈或幀等類自動調用的,不太需要我們過問,因此咱們也沒必要花太多時間去仔細研究它是怎麼工作的,只要知道工作原理就可以了,除非你在學習openGL ES。我們可以把CCTextrue2D的對象看成圖片資源在內存中的存在形式,它是openGL渲染圖形的重要參數,通常情況下它是由UIImageRef到UIImage,再到CCTexture2D轉化而來的。

- (id) initWithData:(const void*)data pixelFormat:(CCTexture2DPixelFormat)pixelFormat pixelsWide:(NSUInteger)width pixelsHigh:(NSUInteger)height contentSize:(CGSize)size

初始化CCTexture2D對象,方法中的那一長串參數都是引擎幫我們運算出來的,它通常被下面的方法調用,因此先別急着去鑽研這些參數,即使你看到頭大它也不過是生成一張貼圖而已……

- (id) initWithImage:(UIImage *)uiImage resolutionType:(ccResolutionType)resolution

總的來說它就是將一個UIImage轉化爲一個CCTexture2D,這個方法被N多種方法封裝過(比如我們前面說的精靈的initWithFile方法),基本上我們也不會主動去用它。

- (id) initWithString:(NSString*)string fontName:(NSString*)name fontSize:(CGFloat)size

根據一個字符串生成一個Texture,這個方法不需要圖片資源。

CCTextureCache

該類的本質是一個內存池,用來緩存遊戲中用到的CCTexture2D對象,是個單例。當精靈從池中獲取對象時,如果存在,則將對象返回,如果不存在,則會生成一個,將其存入池中並返回,這樣同樣的Texture在池中最多隻會有一份,達到節約空間的目的。

+ (CCTextureCache *)sharedTextureCache

獲取單例,單例類的慣用模式。

+(void)purgeSharedTextureCache

釋放內存池,當遊戲結束時由導演調用。

CCSpriteFrame

這個類的最大作用就是作爲Texture的載體,將圖形數據傳遞給精靈,同時它還有offset_、rotated_等一系列參數,用來存儲Plist的數據。(plist是一種數據存儲格式,有專門的API可以將其讀取並保存到內存中,但這裏說的是一種動畫編輯器生成的、基於plist格式保存的數據,就是說cocos2d支持這種動畫編輯器,可以解析它的數據)使用Frame機制構建精靈,還可以支持精靈的動畫效果,因爲精靈除了做位移或旋轉等操作,還可能實時地改變自身顯示的圖形。cocos2d用CCAnimation保存一個Frame序列,然後用CCAnimate這個行爲類根據序列定時切換精靈的當前幀。

+(id) frameWithTexture:(CCTexture2D*)texture rect:(CGRect)rect

根據Texture構建一個CCSpriteFrame對象。

+(id) frameWithTextureFilename:(NSString*)filename rect:(CGRect)rect

根據字符串構建一個CCSpriteFrame對象,這個字符串其實是Texture內存池的key,通過它獲取Texture。

+(id) frameWithTexture:(CCTexture2D*)texture rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize

可自行設定顯示區域、偏移等參數的構建方法,參數一般是從plist中讀取。

+(id) frameWithTextureFilename:(NSString*)filename rectInPixels:(CGRect)rect rotated:(BOOL)rotated offset:(CGPoint)offset originalSize:(CGSize)originalSize

和上一個類似,只是改用key構建。

CCSpriteFrameCache

管理幀的內存池,作用和CCTextureCache一樣,就不贅述了。這裏說幾個比較特殊的接口。

-(void) addSpriteFramesWithDictionary:(NSDictionary*)dictionary textureFilename:(NSString*)textureFilename

根據一個字典和Texture的文件名構建CCSpriteFrame對象並添加到內存池中。一般來說這個字典都是從plist中讀取出來的,通過這種方法來支持動畫編輯器,當然我們也可以根據這個格式自己構建字典。

-(void) addSpriteFramesWithFile:(NSString*)plist textureFilename:(NSString*)textureFilename

根據一個plist文件名和Texture的文件名構建CCSpriteFrame對象並添加到內存池中。先通過文件名找到plist文件的路徑,然後用字典的API把它加載到內存中,最後調用addSpriteFramesWithDictionary:textureFilename:方法。

-(void) addSpriteFramesWithFile:(NSString*)plist

缺省了Texture文件名的構建方法,缺省的文件名先在_plist中查找,如果沒有則查找和plist同名的文件。

-(void) addSpriteFrame:(CCSpriteFrame*)frame name:(NSString*)frameName

將CCSpriteFrame對象添加到內存池中。

-(void) removeSpriteFrameByName:(NSString*)name

根據key從內存池中刪除Frame。

- (void) removeSpriteFramesFromFile:(NSString*) plist

從內存池刪除plist中列出的Frame,相當於addSpriteFramesWithFile的逆向操作。

- (void) removeSpriteFramesFromDictionary:(NSDictionary*) dictionary

從內存池刪除字典中列出的Frame,相當於addSpriteFramesWithDictionary的逆向操作。

-(CCSpriteFrame*) spriteFrameByName:(NSString*)name

根據key在內存池中查找Frame並返回。

- (void) removeSpriteFramesFromTexture:(CCTexture2D*) texture

從內存池中刪除和所給texture相同的Frame。

CCAnimation

其實這個類就是封裝了一個Frame序列,作爲精靈播放動畫的參數,沒有別的功能。

+(id) animation

構建一個空的動畫(沒有任何幀),就是封裝了alloc、init和autorelease。

+(id) animationWithFrames:(NSArray*)frames

根據一個Frame數組構建CCAnimation對象,在CCAnimation中Frame序列就是用數組保存的,所以這裏很好理解。

+(id) animationWithFrames:(NSArray*)frames delay:(float)delay

除了構建對象外,還設置了換幀的時間間隔。

-(void) addFrame:(CCSpriteFrame*)frame

向Frame序列中添加一個CCSpriteFrame對象。

-(void) addFrameWithFilename:(NSString*)filename

根據資源的文件名創建一個Frame並添加到序列中。

-(void) addFrameWithTexture:(CCTexture2D*)texture rect:(CGRect)rect

根據一個Texture創建一個Frame並添加到序列中。

CCAnimationCache

單例,CCAnimation的內存池,不多說了。

+ (CCAnimationCache *)sharedAnimationCache

獲取單例。

-(void) addAnimation:(CCAnimation*)animation name:(NSString*)name

向池中添加一個CCAnimation對象。

-(void) removeAnimationByName:(NSString*)name

根據key從池中刪除CCAnimation對象。

-(CCAnimation*) animationByName:(NSString*)name

根據key從池中獲取CCAnimation對象。

-(void)addAnimationsWithDictionary:(NSDictionary *)dictionary

根據一個字典創建CCAnimation對象,並存入內存池。字典中保存的是每個動畫的名字,動畫中包含哪些幀,換幀間隔是多長。

-(void)addAnimationsWithFile:(NSString *)plist

根據一個plist文件創建CCAnimation對象,並存入內存池。先用文件中的信息生成一個字典,再調用addAnimationsWithDictionary方法來實現。

CCAnimate

這是一個持續型行爲類,父類是CCActionInterval,它的作用就是根據CCAnimation中的序列及間隔時間,不斷地切換精靈的幀,使其產生動畫效果。

+(id) actionWithAnimation: (CCAnimation*)anim

根據CCSpriteFrame對象生成一個動畫播放行爲,持續的時間由幀數和間隔時間相乘算出。

+(id) actionWithAnimation: (CCAnimation*)anim restoreOriginalFrame:(BOOL)b

b爲yes時,當動畫播放完畢後會切換回播放前顯示的幀。

+(id) actionWithDuration:(ccTime)duration animation: (CCAnimation*)anim restoreOriginalFrame:(BOOL)b

手動設置動畫的播放時間,時間到動畫纔算結束。

OK,到這裏我們就可以使用精靈來豐富我們的遊戲世界了,這次我們再做一個練習,和之前的靜態圖片不同,這回我們做一個動態播放動畫的工程。

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