這一節将向遊戲開發者介紹HelloWorld項目的目錄結構,以及各個部分是如何協同工作的。通過本節的學習,你會對各個部分之間的聯系有個大緻的了解。
圖13.22顯示了HelloWorld項目的項目導航面闆。

圖13.22
cocos2d項目引用兩類不同的檔案:源碼檔案和資源檔案(包括圖像檔案、聲音檔案和屬性檔案等)。Default.png檔案是在iOS加載應用程式時顯示的圖像,Icon.png是應用程式部署在裝置上的圖示。不同裝置上可能使用這些檔案類型的不同版本。例如,Retina 裝置上會加載帶有@2x字尾的圖像檔案。關于應用程式圖示、啟動圖像等圖像尺寸和格式的完整清單,可以參考蘋果公司的開發者文檔中的Custom Icon and Image Creation Guidelines,具體網址是:http://developer.apple.com/library/ios/ documentation/userexperience/conceptual/ mobilehig/IconsImages/IconsImages.html#//apple_ref/doc/uid/TP40006556-CH14-SW1。
fps_images.png檔案用于顯示幀率,是不允許删除或修改的。
Info.plist檔案包含了一些與項目相關的配置資訊,同時也可以在這個檔案中修改一些重要的設定,如項目圖示、支援裝置的方向等。
任何一個使用Xcode開發的應用程式或遊戲都是從main.m開始的。在導航區域的“Supporting Files”組下面可以找到main.m檔案。main.m的代碼如下。
程式清單:codes/13/13.3/HelloWorld/HelloWorld/main.m
#import <UIKit/UIKit.h>
int main(int argc,char *argv[]) {
@autoreleasepool {
int retVal = UIApplicationMain(argc,argv,nil,@"AppController");
return retVal;
}
簡單來說,main函數建立了@autoreleasepool(自動釋放池),然後調用UIApplicationMain來啟動程式。其中,AppController是實作UIApplicationDelegate協定的類,AppController類的實作包含在AppDelegate檔案中。在啟用了ARC的cocos2d應用程式中,Autorelease Pool(自動釋放池)可以確定記憶體的對象最終被釋放。
該組中的另一個檔案Prefix.pch是預編譯頭檔案,用于加快編譯速度。pch表示Pre-Compiled Header,遊戲開發者應該把不常變化的架構(Frameworks)頭檔案添加到該檔案中。這樣做可以使架構的代碼提前被編譯,并對所有類可見。
不過,這樣做要注意一個問題:如果pch字首頭檔案中的一個頭檔案發生了變化,項目中的所有代碼都将會重新編譯。是以,pch字首頭檔案中隻應該添加那些極少或者從來都不發生變化的頭檔案。
遊戲開發者可以将cocos2d.h頭檔案添加到pch字首頭檔案中,因為它幾乎不會改變。而且,一開始就将cocos2d.h添加到預編譯頭檔案中是一個非常好的習慣,這樣在其他源檔案中就不必再寫“#import "cocos2d.h"”了。在預編譯頭檔案中加入cocos2d.h,代碼如下。
程式清單:codes/13/13.3/HelloWorld/HelloWorld/Prefix.pch
#import <Availability.h>
#ifndef __IPHONE_3_0
#warning "This project uses features only available in iPhone SDK 3.0 and later."
#endif
#ifdef __OBJC__
#import <Foundation/Foundation.h>
#import "cocos2d.h"
每個iOS程式都有一個AppDelegate類,用于實作UIApplicationDelegate協定。AppDelegate實作的方法用于處理iOS應用程式的狀态改變。例如,可以通過它來處理使用者來電或者系統記憶體不足時程式需要采取的措施。在檢視AppDelegate方法的具體實作代碼前,先要了解AppDelegate.h中的類定義。在AppDelegate.h中定義了AppController這個類,它直接繼承自NSObject類,并且遵循UIApplicationDelegate和CCDirectorDelegate兩個協定。
程式加載完成後,立即執行的方法就是applicationDidFinishLaunchingWithOptions:,在該方法中,通常都是應用啟動後需要執行的初始化代碼。
在Xcode中打開AppDelegate.m檔案,找到applicationDidFinishLaunchingWithOptions方法,代碼如下。
程式清單:codes/13/13.3/HelloWorld/HelloWorld/AppDelegate.m
-(BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// 建立程式主視窗
window_ = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// 建立CCGLView對象,用于遊戲中的渲染
// 從cocos2d v2.0之後,CCGLView替代了之前的EAGLView
// 使用CCGLView将OpenGL ES指令發送給OpenGL ES驅動
CCGLView *glView =[CCGLView viewWithFrame:[window_ bounds]
pixelFormat:kEAGLColorFormatRGB565depthFormat:0
preserveBackbuffer:NOsharegroup:nilmultiSampling:NO
numberOfSamples:0];
// ①建立導演對象
director_ =(CCDirectorIOS*) [CCDirector sharedDirector];
director_.wantsFullScreenLayout = YES;
// 将FPS(Frames Per Second)和SPF(Second Per Frame)顯示設定為開
// cocos2d會自動計算遊戲的目前幀數,并顯示在螢幕的左下角
// 在調試過程中FPS顯示對我們調試會非常有用
// 在遊戲正式上傳到裝置時可以将其設定為NO,則FPS和SPF不會再顯示在裝置中
[director_ setDisplayStats:YES];
// 将動畫間距設定為每秒60次,這也是cocos2d中的預設設定
// 在正常情況下,cocos2d每秒最高會重新整理螢幕中的顯示60次
[director_ setAnimationInterval:1.0/60];
// 将openglView綁定到director_導演對象上
[director_ setView:glView];
// 将director_的代理對象設定為self(自身),用于擷取螢幕資訊
[director_ setDelegate:self];
// 設定2D或3D投射
[director_ setProjection:kCCDirectorProjection2D];
// [director setProjection:kCCDirectorProjection3D];
// 啟用Retina高清顯示模式
if(! [director_ enableRetinaDisplay:YES] )
CCLOG(@"Retina Display Not supported");
// 設定cocos2d的紋理格式
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA8888];
// 在iPad或Retina高清顯示模式下,使用CCFileUtils自動添加圖檔的字尾
CCFileUtils *sharedFileUtils = [CCFileUtils sharedFileUtils];
[sharedFileUtils setEnableFallbackSuffixes:NO];
[sharedFileUtils setiPhoneRetinaDisplaySuffix:@"-hd"];
[sharedFileUtils setiPadSuffix:@"-ipad"];
[sharedFileUtils setiPadRetinaDisplaySuffix:@"-ipadhd"];
// 設定PVR圖像具備多重透明度
[CCTexture2D PVRImagesHavePremultipliedAlpha:YES];
// ②初始化IntroLayer場景,并使用pushScene方法切換到該場景
[director_ pushScene: [IntroLayer scene]];
// 使用director_建立NavigationController導航控制器
navController_ = [[UINavigationController alloc] initWithRootViewController:director_];
// 設定navigationBarHidden為YES
navController_.navigationBarHidden = YES;
// 将NavigationController導航控制器設定為根視圖控制器
[window_ setRootViewController:navController_];
// 設定主視窗可見
[window_ makeKeyAndVisible];
return YES;
在applicationDidFinishLaunchingWithOptions方法中,①号代碼建立了一個CCDirector導演對象,在cocos2d中,CCDirector導演對象負責遊戲的循環運作,并且在遊戲中渲染所有的圖像,它會掌控遊戲的運作、暫停或停止。AppController中包括了CCDirector響應iOS作業系統在内的暫停或繼續等各個事件。代碼如下。
程式清單:codes/13.3/HelloWorld/HelloWorld/AppDelegate.m
// 當作業系統暫停應用時執行,調用此方法來暫停遊戲和所有的計時器
// 當玩家在玩遊戲的過程中鎖定了iPad或iPhone,或者有電話打進來
// 或者其他類似事件發生需要強迫遊戲進入背景時,會調用此方法
-(void)applicationWillResignActive:(UIApplication *)application
if([navController_ visibleViewController] == director_ )
[director_ pause];
// 當玩家解鎖iPad或iPhone,或電話已接聽完畢時,會調用此方法來繼續遊戲和所有的計時器
-(void)applicationDidBecomeActive: (UIApplication *)application
if( [navController_ visibleViewController] == director_ )
[director_ resume];
// 在iOS 4.0及以後的版本中,開始支援應用在背景運作,此時會停止運作螢幕中的動畫
-(void)applicationDidEnterBackground: (UIApplication*)application
[director_ stopAnimation];
// 當應用重新回到前台來運作時,重新啟動螢幕中的動畫
-(void)applicationWillEnterForeground: (UIApplication*)application
[director_ startAnimation];
// 應用程式即将中止時調用此方法
// 該方法會終止CCDirector的控制,并從應用程式的UIWindow中解除對CCGLView的綁定
// 同時還将結束遊戲循環,從記憶體中清除所有的紋理和計時器
-(void)applicationWillTerminate: (UIApplication *)application
CC_DIRECTOR_END();
// 當系統收到記憶體不足的警告時,會調用此方法從記憶體中清除未在螢幕中顯示的紋理圖。
-(void)applicationDidReceiveMemoryWarning: (UIApplication *)application
[[CCDirector sharedDirector] purgeCachedData];
// 将上一次時間調用和目前事件調用間的增量時間設定為0。
// 該方法的調用場景是:兩次調用之間已經過了太長的時間。
// 這通常是由于iPhone重新調整了系統時間而導緻。
-(void)applicationSignificantTimeChange: (UIApplication *)application
[[CCDirector sharedDirector] setNextDeltaTimeZero:YES];
在applicationDidFinishLaunchingWithOptions方法中,編号②代碼初始化IntroLayer場景,并使用pushScene方法切換到該場景。下面我們來看看IntroLayer類的實作。
IntroLayer類繼承自CCLayer,因為CCDirector隻能運作CCScene對象,是以需要實作IntroLayer的scene方法,它會把IntroLayer當作唯一的子節點添加進去,并傳回一個CCScene。打開IntroLayer.m檔案,找到scene方法,代碼如下。
程式清單:codes/13/13.3/HelloWorld/HelloWorld/IntroLayer.m
+(CCScene *)scene
// 建立CCScene場景對象
CCScene *scene = [CCScene node];
// 建立IntroLayer層對象
IntroLayer *layer = [IntroLayer node];
// 将layer添加為scene的子節點
[scene addChild: layer];
// 傳回scene對象
return scene;
以前的cocos2d版本中是不存在IntroLayer類的,這是cocos2d 2.0新加的類,它的主要目的就是在進入遊戲之前,可以顯示遊戲制作公司的Logo等資訊。顯示Logo的實作代碼在onEnter方法當中,代碼如下(程式清單同上)。
-(void)onEnter
[super onEnter];
// 獲得裝置支援的視窗大小
CGSize size = [[CCDirector sharedDirector] winSize];
CCSprite *background;
// 判斷裝置是iPhone還是iPad,并據此來加載不同的背景資源圖檔
if(UI_USER_INTERFACE_IDIOM()== UIUserInterfaceIdiomPhone ){
background = [CCSprite spriteWithFile:@"Default.png"];
background.rotation = 90;
} else {
background = [CCSprite spriteWithFile:@"Default-Landscape~ipad.png"];
// 設定背景圖檔的位置居中
background.position = ccp(size.width/2,size.height/2);
// 把背景圖檔添加到IntroLayer中
[self addChild: background];
// 觸發一個定時器方法調用,在1秒後會調用makeTransition函數
[self scheduleOnce:@selector(makeTransition:)delay:1];
接下來看看makeTransition方法的實作,代碼如下(程式清單同上)。
-(void)makeTransition: (ccTime)delta
[[CCDirector sharedDirector] replaceScene:
[CCTransitionFade transitionWithDuration:1.0
scene:[HelloWorldLayer scene] withColor:ccWHITE]];
該方法隻有一句代碼調用,就是使用CCDirector配合CCTransitionFade場景切換特效類,把HelloWorldLayer類在1秒螢幕變白後展示出來。最後來看看HelloWordLayer類的實作。
HelloWorldLayer類繼承自CCLayer。因為CCScene隻是一個抽象的接口,而預設設定場景的方法通常是在類裡使用一個靜态初始化方法+(id)scene。此方法會建立一個CCScene對象,并且将HelloWorldLayer的對象添加為場景的子節點。代碼如下。
程式清單:codes/13/13.3/HelloWorld/HelloWorld/HelloWorldLayer.m
// 建立HelloWorldLayer層對象
HelloWorldLayer *layer = [HelloWorldLayer node];
接下來再看看-(id)init初始化方法的實作,代碼如下(程式清單同上)。
-(id) init
if((self=[super init])) {
// 建立和初始化一個标簽對象
CCLabelTTF *label = [CCLabelTTF labelWithString:@"Hello World"
fontName:@"Marker Felt" fontSize:64];
// 執行個體化得到一個CCDirector的單例,并獲得視窗的尺寸
// 将标簽位置設定在螢幕中央,ccp是cocos2d對于CGPointMake的宏定義
label.position = ccp(size.width /2,size.height/2);
// 将label添加為scene的子節點
[self addChild: label];
// 下面是初始化遊戲中心的成就榜和高分榜的代碼,此處先略去暫時不讨論
return self;
以上就是HelloWorld項目的詳細實作過程。讀者之前已經學習過iOS基礎知識,是以這裡并沒有對所有類的所有實作代碼進行逐行解釋和分析。但通過以上詳細代碼分析,我們初步了解了一個cocos2d應用的啟動和運作過程,這将為以後開發更複雜的遊戲或應用程式打下紮實的基礎。
在HelloWorld項目中,使用了場景(CCScene)、層(CCLayer)、導演(CCDirector)等核心類,在cocos2d的開發中,幾乎任何一款cocos2d遊戲中都會用到這些類,是以了解它們的作用、屬性和方法,以及如何将這些類組織在一起,是我們學習cocos2d遊戲開發的必修課。掌握了這些基本知識之後,大家就會發現使用cocos2d開發遊戲其實很簡單。接下來重點介紹cocos2d中的核心類。