這篇文章主要會介紹一些cocos2d的基礎類,以及他們的用途。
cocos2d中,大量使用了單例(singleton)模式,單例其實就是一個普通的類,但是它在整個應用程序生命周期內只實例化一次,cocos2d中,要訪問單例對象,基本上都是使用shared開頭的方法(目前為止,我沒有發現過有不這樣使用的單例)。如果你還沒看懂單例是什么,那么看看下面這個例子你就知道了。
static MyManager *shareManager = nil;
+(MyManager) sharedManager
{
if(shareManager == nil)
{
shareManager = [[MyManager alloc] init];
}
return shareManager;
}
我覺得單例應該是包含了一些公用的方法,而且調用這些方法,不會去修改單例的屬性,否則其他的類來調用單例的時候,所遇到的結果就是未知的了。說完單例,我們先來說說一個重要的單例類——CCDirector。CCDiretor類是Cococs2d游戲引擎的核心,它存儲了cocos2d種大量的全局配置信息,而且管理着所有的cocos2d場景。Dirctor的主要作用有一下幾點:
- 切換場景
- 存儲cocos2d的配置信息
- 訪問試圖(包含OpenGL、UIView、UIWindow)
- 暫停、恢復以及終止游戲
- 在UIKit和OpenGL之間轉換坐標
- CCNode類
接下來,說說CCNode類。cocos2d中,所有的節點都繼承自CNode類,它是一個沒有具體顯示的抽象類,僅用於定義所有的公共屬性和方法。首先我們來看一下cocos文檔里面列舉出來的類的繼承關系,可以從中發現CCScene、CCSprite都繼承自CCNode,以前CCLayer也應該是繼承自CCNode,但是在1.0.1的文檔中查不到這個類,先記錄下,等下再去查。
再來看看這個類的部分公共函數,里面包含了各種對節點的操作,增加、刪除、獲取節點、調度(即隔多少秒執行一次,稍后會詳細說、取消調度、開始播放動作、停止動作等):
(void) |
- addChild: |
(void) |
- addChild:z: |
(void) |
- addChild:z:tag: |
(void) |
- removeFromParentAndCleanup: |
(void) |
- removeChild:cleanup: |
(void) |
- removeChildByTag:cleanup: |
(void) |
- removeAllChildrenWithCleanup: |
(CCNode *) |
- getChildByTag: |
(void) |
- reorderChild:z: |
(void) |
- cleanup |
(void) |
- draw |
(void) |
- visit |
(void) |
- transform |
(void) |
- transformAncestors |
(CGRect) |
- boundingBox |
(CGRect) |
- boundingBoxInPixels |
(CCAction *) |
- runAction: |
(void) |
- stopAllActions |
(void) |
- stopAction: |
(void) |
- stopActionByTag: |
(CCAction *) |
- getActionByTag: |
(NSUInteger) |
- numberOfRunningActions |
(void) |
- scheduleUpdate |
(void) |
- scheduleUpdateWithPriority: |
(void) |
- schedule: |
(void) |
- schedule:interval: |
(void) |
- unschedule: |
(void) |
- unscheduleAllSelectors |
(void) |
- resumeSchedulerAndActions |
(void) |
- pauseSchedulerAndActions |
- CCScene類
一個CCScene對象往往是場景圖種的第一個節點。通常來說,CCScene節點的第一層子節點一定是CCLayer的子類,而CCScene對象本身,通常是利用CCLayer對象種的靜態方法+(id)scene來創建,而且游戲中的各個對象,也通常是由這些子節點(CCLayer)來保存,而不是CCScene本身來保存,這樣做的好處,會在CCLayer部分介紹。
1、場景類跟app建立關系上
我們可以把要顯示的第一個場景,加在AppDelegate中applicationDidFinishLaunching方法的最后,類似如下:
[[CCDirector sharedDirector] runWithScene:[HelloWorld scene]];
HelloWold類是一個繼承自CCLayer的類,scene是其中的一個靜態方法,用來將layer加入scene里面,如下所示:
+(id)scene
{
CCScene *scene = [CCScene node];
CCLayer *layer = [HelloWord node];
[scene addChild:layer];
return scene;
}
2、內存使用
當進行場景替換的時候,cocos2d會把自己占用的內存清理干凈,它會刪除所有的節點,停止所有的動作,並且對所有用選擇器選中的方法取消調度。但是,由於在進行場景替換時,新場景往往在舊場景釋放之前就被加載到內存了,這會導致內存負荷瞬間加大,這個問題在使用場景轉換動畫的時候,顯得格外明顯。這時候,場景首先會被創建,然后過渡效果運行,一直要到過度效果運行完畢之后,舊場景才會從內存中釋放。
由於場景替換的時候,會停止所有的動作,那么可否在播放場景過渡動畫前先把前一個場景截屏,然后釋放掉前一個場景再播放動畫,這樣的話,就能節省不少內存。
3、場景的推進和彈出
cocos2d種有pushScene和popScene這兩個有用的方法,這兩個方法用來在不釋放舊場景內存的情況下運行新場景,可以加快場景替換的速度。由於很多場景可以互相疊加的存在於內存之中,很容易就會忘記彈出一個場景,或者對於同一個場景彈出太多遍。學過堆棧的同學,應該知道這種情況的危險性。但是這個用來切換setting還是不錯的選擇,因為setting一般都不怎么占內存,當然,特殊情況除外。
- CCTransitonScene
場景過渡動畫有時候能為游戲添色不少。在cocos2d中,要使用過度動畫還是比較簡單的,只要在場景轉換時添加兩行代碼就行了。比如下面這個淡入淡出效果:
CCFadeTransition *tran = [CCFadeTransition transitionWithDuration:1
scene:[HelloWorld scene]
withColor:ccWHITE];
[[CCDirector sharedDirector] replaceScene:tran];
CCTransitonScene定義了很多的場景轉換動畫,看下下面這張類圖應該能很清楚的知道:
- CCLayer
開始在CCScene里面提到過,CCLayer本質是對節點進行分組,游戲中的各個對象,一般是用CCLayer來保存的。這樣的好處是,可以很輕松的修改層的屬性或者在該層上運行一個動作來影響層上的所有子節點。例如你可以對某一層施加一個動作,然后這個動作會對該層上的所有對象產生影響。當然,不使用層也能達到這樣的效果,只要對每個對象分別進行操作即可,但是顯然,不使用層的做法是非常低效的。
CCLayer能夠接收觸摸事件和加速劑事件,但是接收觸摸或者加速計事件的開銷是很大的,這也就導致有人說使用多個層會影響性能。實際上你可以使用任意多個蹭,與其他的節點相比,他們對於性能並沒有太大的影響。如果太多的層需要接收和處理觸摸或者加速計事件,可以只用一個蹭來接收和處理這些輸入,然后在必要的情況下,通過這個層將輸入事件通知給其他節點或者類。
1、接收觸摸事件
使用self.isTouchEnabled = YES來顯示啟動接收觸摸事件,一般會在init方法中開啟此功能。下面列出幾個常用單點觸控的觸摸事件:
a)當手指接觸到屏幕時被調用:
-(BOOL) ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
b)當手指離開屏幕時候被調用:
-(void) ccTouchEnded:(UITouch *)touch withEvent:(UIEvent *)event
c)當觸摸時間被取消時調用:
-(void) ccTouchCancelled:(UITouch *)touch withEvent:(UIEvent *)event
d)當手指在屏幕上移動的時候被調用:
-(void) ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
在使用單點觸摸之前,要向層中添加以下方法來啟用有針對性的觸摸處理:
-(void) registerWithTouchDispatcher
{
[[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self
priority:INIT_MIN + 1
swallowsTouches:YES];
}
CCTouchBegan返回一個bool值,如果返回YES,就意味着不想讓這個觸摸被傳送到其他優先級更低的有針對性的觸摸處理,也就相當於你直接吞噬掉了這個觸摸事件。
由於觸摸事件是由Cocoa Touch API接收的,因此一定要吧觸摸位置轉換成cocos2d所用的OpenGL坐標:
-(CGPoint) locationFromTouch:(UITouch *)touch
{
CGPoint touchLocation = [touch locationInView:[touch view]];
return [[CCDirector sharedDirector] convertToGL:touchLocation];
}
2、接收加速計事件
同樣,需要self.isAccelerometerEnabled = YES來顯示啟動加速計來接收加速計事件,但是這個事件的處理比觸摸時間就簡單多了,只需要向層里面添加一個特定方法來接收加速計事件:
- (void)accelerometer:(UIAccelerometer*)accelerometer
didAccelerate:(UIAcceleration*)acceleration
{
//可以利用以下參數來決定三維中任意方向的加速度
//acceleration.x acceleration.y acceleration.z
}
- CCSprite
CCSprite是cocos2d種最為常用的類,它用一副圖像將精靈顯示到屏幕上。要創建一個精靈很簡單,比如你的工程的Resources分組下有一張叫做monster.png的圖,那么只需要使用如下方法,就能將精靈顯示在層上:
CCSpirt *sprite = [[CCSprite spriteWithFile:@"monster.png"]];
[self addChild:sprite];
通過上面的操作后,cocos2d內部會把該圖片加載到CCTexture2D類的圖像資源中。在這里,順便提一下,由於ios設備只支持尺寸為“2的n次冪”的紋理,即圖片的長寬只能偉:2、4、8等像素。如果你有一張貼圖,大小為260*260像素32位色的圖片,那么就比較悲劇了。你覺得它在內存中應該只占用260*260*4=270KB左右的空間,單實際上,它占用了512*512*4=1MB的內存。
CCSprite還有一個比較重要的就是位置問題,想象下現實生活中,如果你要把一張照片釘在牆上某個問題,你會怎么做?首先,你會把圖釘插在照片上的某個點(在cocos2d中稱為anchorPoint),然后你會確定要把這個圖釘訂在牆上的某個位置(在cocos2d種稱為positon),這兩個點就能確定照片在牆上的位置了。比如你想把照片放到左下角,那么你可以選擇將圖釘釘在照片的左下角(0,0),然后釘在牆的左下角(0,0).或者,你可以選擇把圖釘定在照片的右上角(1,1),然后把照片訂在牆的(照片長,照片寬)的位置。auchorPoint表示的其實是一個百分比,用來標明相對於圖片左下角的(長*百分比,寬*百分比)像素的位置,比如auchorPoint為(0.5, 0.5), 那么在圖片的坐標系里,它標明的位置就應該是(長*0.5, 寬*0.5)的位置,也就是圖片的中心點。最好好anchorPoint設置成(0.5, 0.5),也就是在圖片的中心,這樣,當你進行旋轉、縮放等動作的時候,會比較方便。幸運的是,anchorPoint的默認位置就是(0.5,0.5).
- CCLabelTTF
這個類的作用就是在屏幕上顯示文本。cocos2d內部會以制定的字體作為參數創建一個CCTexture2D對象,也就是一張紋理,然后再用改紋理渲染出最后顯示的文本.因為每次文本發生改變,就要做一次上述工作,所以cocos2d的文檔中也建議改用CCLabelAtlas或者CCLabelBMFont代替。
你可能會發現,每次修改標簽上的文本時候,這些文本都會自動中對齊,如果要改成左對齊,或者右對齊這些,只需要改變anchorPoint的屬性就可以了。
- 動作
動作是可以用來讓節點執行諸如移動、旋轉、縮放、變色、消失等很多動作。由於他們能作用在所有的節點上,因此可以對精靈、標簽甚至菜單或整個場景施加動作。動作在完成后,會自動從節點上清除並釋放它所占用的內存。
動作又分為即時動作和延時動作。延時動作就是我們一般理解上的動作,比如讓一個精靈移動到哪里。即時動作,一般就類似於設置精靈的屬性等,及時動作平時看起來是沒有多大意義的,一般要配合后文所述的動作序列。
1)重復動作
這個很容易理解,就是讓一個動作不停的重復,可以用這個方法創建無限循環的動畫。使用起來也很簡單,例如下面這個讓一個節點不停的旋轉:
CCRotateBy* rotateBy = [CCRotateBy actionWithDuration:2 angle:360];
CCRepeatForever *repeat = [CCRepeatForever actionWithAction:rotateBy];
[myNode runAction:repeat];
還有一個類CCRepeat是讓一個動畫重復多少次,函數原型如下:
actionWithAction:(CCFiniteTimeAction *)action times:(NSUInteger) times;
2、流暢動作(CCEaseAction)
一般的動作,比如你定義了一個物體是向哪個方向移動,那么它就會勻速的過去,但是很顯然,我們喜歡更有點變化的動作,比如加速進入,然后迅速一段時間,再減速停止,流暢動作就是用來做這個的。
3、動作序列
CCSequence,這個比較好理解,就是定義一組動作,然后讓他們按照這個順序執行。
上面介紹了cocos2d種一些重要的、常用的類,接下來的文章,會采用這些來做一個小demo,來溫習一下這一篇文章的內容,不正確的地方,還請各位斧正。