溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

瘋狂ios講義之瘋狂打飛機(jī)(1)

發(fā)布時間:2020-08-02 16:01:02 來源:網(wǎng)絡(luò) 閱讀:628 作者:fkJava李剛 欄目:移動開發(fā)

瘋狂打飛機(jī)游戲

   本次我們將帶領(lǐng)大家手動完成一個簡單但功能完整的打飛機(jī)游戲,實(shí)現(xiàn)飛機(jī)飛行、飛機(jī)碰撞、發(fā)射×××、敵機(jī)發(fā)射大×××、背景音樂、×××音效、分?jǐn)?shù)統(tǒng)計(jì)、菜單管理等功能。它雖然不會為你贏得什么獎項(xiàng),但是可以總結(jié)前面所學(xué)的所有知識,幫助大家更好地掌握cocos2d基本對象的使用,同時體驗(yàn)cocos2d的強(qiáng)大以及易用性。

1開始前的準(zhǔn)備工作

首先打開Xcode,使用cocos2d iOS模板新建一個項(xiàng)目,命名為“AirfightGame”,然后選擇一個目錄,單擊“Create”按鈕。為cocos2d項(xiàng)目的源代碼添加-fno-objc-arc選項(xiàng)讓項(xiàng)目支持ARC。

接下來,將所需要的資源文件,包括圖片和聲音拖到項(xiàng)目的“Resources”組。在游戲開發(fā)當(dāng)中,通常都會使用精靈表單來優(yōu)化游戲性能,在這個小游戲當(dāng)中,雖然這種性能優(yōu)化并不會有特別明顯的效果,但是建議大家以后開發(fā)游戲時都使用精靈表單來提高游戲性能。使用Zwoptex將所有圖片制作成精靈表單,生成對應(yīng)的airfightSheet.pngairfightSheet.plist文件,并將這兩個文件拖到項(xiàng)目的“Resources”組。

2添加游戲菜單項(xiàng)功能

現(xiàn)在,我們來為游戲添加一個菜單設(shè)置功能,在這里可以完成開始游戲、游戲設(shè)置、退出游戲等操作。步驟如下。

選擇“AirfightGame”組并單擊右鍵,選擇“New File”,在左邊欄中選擇“cocos2d v2.x”模板,在右邊的模板類中選擇“CCNode class”模板類,“Subclass of”選擇“CCLayer”,然后單擊“Next”按鈕。命名為“MenuLayer”,然后單擊“Create”按鈕。

MenuLayer繼承自CCLayer,提供一個類方法sceneCCDirector對象調(diào)用。該類的作用是顯示一個菜單場景,讓用戶選擇。

打開MenuLayer.m文件,實(shí)現(xiàn)代碼如下。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/MenuLayer.m

-(id) init
{
    if( (self=[super init]) ) {
        CGSize winSize = [[CCDirector sharedDirector] winSize];
        // 創(chuàng)建“開始游戲”標(biāo)簽,當(dāng)觸碰該標(biāo)簽時,調(diào)用startGame:方法
        CCMenuItemFont* startItem = [CCMenuItemFont itemWithString:@"開始游戲"
            target:self selector:@selector(startGame:)];
        startItem.position=ccp(winSize.width/2, winSize.height*0.6);
        // 創(chuàng)建“游戲設(shè)置”標(biāo)簽,當(dāng)觸碰該標(biāo)簽時,調(diào)用setting:方法
        CCMenuItemFont* settingItem = [CCMenuItemFont itemWithString:@"游戲設(shè)置"
            target:self selector:@selector(setting:)];
        // 設(shè)置“游戲設(shè)置”標(biāo)簽位置
        settingItem.position=ccp(winSize.width/2, winSize.height*0.4);
        // 創(chuàng)建控制菜單,并將兩個標(biāo)簽添加進(jìn)去
        CCMenu* menu = [CCMenu menuWithItems:startItem,settingItem, nil];
        menu.position = CGPointZero;
        [self addChild:menu];
    }
    return self;
}

init方法比較簡單,創(chuàng)建了兩個CCMenuItemFont,選擇標(biāo)簽時會調(diào)用對應(yīng)的startGame:setting:方法,并將它們添加到CCMenu當(dāng)中,再將CCMenu添加為當(dāng)前層的子節(jié)點(diǎn)。

添加startGame:setting:兩個方法,實(shí)現(xiàn)代碼如下(程序清單同上):

-(void) startGame:(id)sender{
    // 切換到PreloadLayer場景
    CCTransitionSlideInL* transitionScene = [CCTransitionSlideInL
        transitionWithDuration:2.0 scene:[PreloadLayer scene]];
    [[CCDirector sharedDirector] replaceScene:transitionScene];
}

startGame:方法非常簡單,當(dāng)用戶選擇“開始游戲”標(biāo)簽時,場景切換到PreloadLayer,在下一節(jié)中將重點(diǎn)介紹PreloadLayer(程序清單同上)。

-(void) setting:(id)sender{
    // 切換到SettingLayer場景
    CCTransitionSlideInL* transitionScene = [CCTransitionSlideInL
        transitionWithDuration:2.0 scene:[SettingLayer scene]];
    [[CCDirector sharedDirector] replaceScene:transitionScene];
}

當(dāng)用戶選擇“游戲設(shè)置”標(biāo)簽時,場景切換到SettingLayer,進(jìn)行游戲設(shè)置。

同上面的步驟一樣,使用“cocos2d v2.x”模板創(chuàng)建一個類并命名為“SettingLayer”,繼承自CCLayer。該類的實(shí)現(xiàn)代碼如下。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/SettingLayer.m

-(id) init
{
    if( (self=[super init]) ) {
        CGSize winSize = [[CCDirector sharedDirector] winSize];
        // 提示菜單項(xiàng)
        CCMenuItemFont* musicItem = [CCMenuItemFont itemWithString:@"背景音樂:"];
        musicItem.position = ccp(winSize.width*0.4, winSize.height*0.6);
        // 創(chuàng)建“開”和“關(guān)”菜單項(xiàng)
        CCMenuItemFont* musicOn = [CCMenuItemFont itemWithString:@"開"];
        CCMenuItemFont* musicOff = [CCMenuItemFont itemWithString:@"關(guān)"];
        // CCMenuItemToggle,默認(rèn)顯示“開”。開=0,關(guān)=1
        CCMenuItemToggle* musicToggle = [CCMenuItemToggle itemWithTarget:self
            selector:@selector(change:) items:musicOff,musicOn, nil];
        musicToggle.position = ccp(winSize.width*0.6, winSize.height*0.6);
        // 創(chuàng)建“返回主菜單“菜單項(xiàng)
        CCMenuItemFont* returnItem = [CCMenuItemFont itemWithString:@"返回主菜單"
            target:self selector:@selector(backToMainLayer:)];
        returnItem.position = ccp(winSize.width/2, winSize.height*0.4);
        // 創(chuàng)建控制菜單,并將3個標(biāo)簽添加進(jìn)去
        CCMenu* menu = [CCMenu menuWithItems:musicItem,musicToggle,returnItem, nil];
        menu.position = CGPointZero;
        [self addChild:menu];
        // NSUserDefaults用戶首選項(xiàng)可以用來保存用戶在操作應(yīng)用的過程中設(shè)置的首選項(xiàng)。
        NSUserDefaults* userDef = [NSUserDefaults standardUserDefaults];
        // 如果Bool為No,則顯示1=關(guān)
        if(![userDef boolForKey:@"music"]){
            musicToggle.selectedIndex = 1;
        }
    }
    return self;
}
-(void) change:(id)sender{
    // 判斷mute(靜音)屬性,根據(jù)屬性狀態(tài)進(jìn)行切換
    if([CDAudioManager sharedManager].mute == TRUE){
        [CDAudioManager sharedManager].mute = FALSE;
    }else{
        [CDAudioManager sharedManager].mute = TRUE;
    }
    NSUserDefaults* userDef = [NSUserDefaults standardUserDefaults];
    CCMenuItemToggle* tooggle = (CCMenuItemToggle*)sender;
    // 關(guān)=1,設(shè)置Bool為NO
    if(tooggle.selectedIndex == 1){
        [userDef setBool:NO forKey:@"music"];
    }else{
        [userDef setBool:YES forKey:@"music"];
    }
}
// 定義一個CCTransitionSlideInL場景切換效果,并使用CCDirector單例對象來切換場景
-(void) backToMainLayer:(id)sender{
    CCTransitionSlideInL* transitionScene =
        [CCTransitionSlideInL transitionWithDuration:2.0 scene:[MenuLayer scene]];
    [[CCDirector sharedDirector] replaceScene:transitionScene];
}

SettingLayer類代碼在13.13.2節(jié)中已經(jīng)詳細(xì)介紹過,這里不再贅述。

修改IntroLayer.m文件

IntroLayer默認(rèn)加載HelloWorldLayer,但此時我們不再使用HelloWorldLayer作為應(yīng)用的第一個場景,而是使用MenuLayer作為應(yīng)用的第一個場景,因此需要修改IntroLayer,將IntroLayer改為加載MenuLayer場景。修改如下。

IntroLayer.m文件的頂部添加所包含的頭文件:

#import "MenuLayer.h"

修改-(void) makeTransition:(ccTime)dt方法,將該方法改成下面的代碼。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/IntroLayer.m

-(void) makeTransition:(ccTime)dt
{
    [[CCDirector sharedDirector] replaceScene:
        [CCTransitionFade transitionWithDuration:1.0
        scene:[MenuLayer scene] withColor:ccWHITE]];
}

ios講義之瘋狂打飛機(jī)(1)

瘋狂打飛機(jī)游戲

   本次我們將帶領(lǐng)大家手動完成一個簡單但功能完整的打飛機(jī)游戲,實(shí)現(xiàn)飛機(jī)飛行、飛機(jī)碰撞、發(fā)射×××、敵機(jī)發(fā)射大×××、背景音樂、×××音效、分?jǐn)?shù)統(tǒng)計(jì)、菜單管理等功能。它雖然不會為你贏得什么獎項(xiàng),但是可以總結(jié)前面所學(xué)的所有知識,幫助大家更好地掌握cocos2d基本對象的使用,同時體驗(yàn)cocos2d的強(qiáng)大以及易用性。

1開始前的準(zhǔn)備工作

首先打開Xcode,使用cocos2d iOS模板新建一個項(xiàng)目,命名為“AirfightGame”,然后選擇一個目錄,單擊“Create”按鈕。為cocos2d項(xiàng)目的源代碼添加-fno-objc-arc選項(xiàng)讓項(xiàng)目支持ARC

接下來,將所需要的資源文件,包括圖片和聲音拖到項(xiàng)目的“Resources”組。在游戲開發(fā)當(dāng)中,通常都會使用精靈表單來優(yōu)化游戲性能,在這個小游戲當(dāng)中,雖然這種性能優(yōu)化并不會有特別明顯的效果,但是建議大家以后開發(fā)游戲時都使用精靈表單來提高游戲性能。使用Zwoptex將所有圖片制作成精靈表單,生成對應(yīng)的airfightSheet.pngairfightSheet.plist文件,并將這兩個文件拖到項(xiàng)目的“Resources”組。

2添加游戲菜單項(xiàng)功能

現(xiàn)在,我們來為游戲添加一個菜單設(shè)置功能,在這里可以完成開始游戲、游戲設(shè)置、退出游戲等操作。步驟如下。

選擇“AirfightGame”組并單擊右鍵,選擇“New File”,在左邊欄中選擇“cocos2d v2.x”模板,在右邊的模板類中選擇“CCNode class”模板類,“Subclass of”選擇“CCLayer”,然后單擊“Next”按鈕。命名為“MenuLayer”,然后單擊“Create”按鈕。

MenuLayer繼承自CCLayer,提供一個類方法sceneCCDirector對象調(diào)用。該類的作用是顯示一個菜單場景,讓用戶選擇。

打開MenuLayer.m文件,實(shí)現(xiàn)代碼如下。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/MenuLayer.m

01-(id) init
02{
03if( (self=[super init]) ) {
04CGSize winSize = [[CCDirector sharedDirector] winSize];
05// 創(chuàng)建“開始游戲”標(biāo)簽,當(dāng)觸碰該標(biāo)簽時,調(diào)用startGame:方法
06CCMenuItemFont* startItem = [CCMenuItemFont itemWithString:@"開始游戲"
07target:self selector:@selector(startGame:)];
08startItem.position=ccp(winSize.width/2, winSize.height*0.6);
09// 創(chuàng)建“游戲設(shè)置”標(biāo)簽,當(dāng)觸碰該標(biāo)簽時,調(diào)用setting:方法
10CCMenuItemFont* settingItem = [CCMenuItemFont itemWithString:@"游戲設(shè)置"
11target:self selector:@selector(setting:)];
12// 設(shè)置“游戲設(shè)置”標(biāo)簽位置
13settingItem.position=ccp(winSize.width/2, winSize.height*0.4);
14// 創(chuàng)建控制菜單,并將兩個標(biāo)簽添加進(jìn)去
15CCMenu* menu = [CCMenu menuWithItems:startItem,settingItem, nil];
16menu.position = CGPointZero;
17[self addChild:menu];
18}
19returnself;
20}

init方法比較簡單,創(chuàng)建了兩個CCMenuItemFont,選擇標(biāo)簽時會調(diào)用對應(yīng)的startGame:setting:方法,并將它們添加到CCMenu當(dāng)中,再將CCMenu添加為當(dāng)前層的子節(jié)點(diǎn)。

添加startGame:setting:兩個方法,實(shí)現(xiàn)代碼如下(程序清單同上):

1-(void) startGame:(id)sender{
2// 切換到PreloadLayer場景
3CCTransitionSlideInL* transitionScene = [CCTransitionSlideInL
4transitionWithDuration:2.0 scene:[PreloadLayer scene]];
5[[CCDirector sharedDirector] replaceScene:transitionScene];
6}

startGame:方法非常簡單,當(dāng)用戶選擇“開始游戲”標(biāo)簽時,場景切換到PreloadLayer,在下一節(jié)中將重點(diǎn)介紹PreloadLayer(程序清單同上)。

1-(void) setting:(id)sender{
2// 切換到SettingLayer場景
3CCTransitionSlideInL* transitionScene = [CCTransitionSlideInL
4transitionWithDuration:2.0 scene:[SettingLayer scene]];
5[[CCDirector sharedDirector] replaceScene:transitionScene];
6}

當(dāng)用戶選擇“游戲設(shè)置”標(biāo)簽時,場景切換到SettingLayer,進(jìn)行游戲設(shè)置。

同上面的步驟一樣,使用“cocos2d v2.x”模板創(chuàng)建一個類并命名為“SettingLayer”,繼承自CCLayer。該類的實(shí)現(xiàn)代碼如下。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/SettingLayer.m


01-(id) init
02{
03if( (self=[super init]) ) {
04CGSize winSize = [[CCDirector sharedDirector] winSize];
05// 提示菜單項(xiàng)
06CCMenuItemFont* musicItem = [CCMenuItemFont itemWithString:@"背景音樂:"];
07musicItem.position = ccp(winSize.width*0.4, winSize.height*0.6);
08// 創(chuàng)建“開”和“關(guān)”菜單項(xiàng)
09CCMenuItemFont* musicOn = [CCMenuItemFont itemWithString:@"開"];
10CCMenuItemFont* musicOff = [CCMenuItemFont itemWithString:@"關(guān)"];
11// CCMenuItemToggle,默認(rèn)顯示“開”。開=0,關(guān)=1
12CCMenuItemToggle* musicToggle = [CCMenuItemToggle itemWithTarget:self
13selector:@selector(change:) items:musicOff,musicOn, nil];
14musicToggle.position = ccp(winSize.width*0.6, winSize.height*0.6);
15// 創(chuàng)建“返回主菜單“菜單項(xiàng)
16CCMenuItemFont* returnItem = [CCMenuItemFont itemWithString:@"返回主菜單"
17target:self selector:@selector(backToMainLayer:)];
18returnItem.position = ccp(winSize.width/2, winSize.height*0.4);
19// 創(chuàng)建控制菜單,并將3個標(biāo)簽添加進(jìn)去
20CCMenu* menu = [CCMenu menuWithItems:musicItem,musicToggle,returnItem, nil];
21menu.position = CGPointZero;
22[self addChild:menu];
23// NSUserDefaults用戶首選項(xiàng)可以用來保存用戶在操作應(yīng)用的過程中設(shè)置的首選項(xiàng)。
24NSUserDefaults* userDef = [NSUserDefaults standardUserDefaults];
25// 如果Bool為No,則顯示1=關(guān)
26if(![userDef boolForKey:@"music"]){
27musicToggle.selectedIndex = 1;
28}
29}
30returnself;
31}
32-(void) change:(id)sender{
33// 判斷mute(靜音)屬性,根據(jù)屬性狀態(tài)進(jìn)行切換
34if([CDAudioManager sharedManager].mute == TRUE){
35[CDAudioManager sharedManager].mute = FALSE;
36}else{
37[CDAudioManager sharedManager].mute = TRUE;
38}
39NSUserDefaults* userDef = [NSUserDefaults standardUserDefaults];
40CCMenuItemToggle* tooggle = (CCMenuItemToggle*)sender;
41// 關(guān)=1,設(shè)置Bool為NO
42if(tooggle.selectedIndex == 1){
43[userDef setBool:NO forKey:@"music"];
44}else{
45[userDef setBool:YES forKey:@"music"];
46}
47}
48// 定義一個CCTransitionSlideInL場景切換效果,并使用CCDirector單例對象來切換場景
49-(void) backToMainLayer:(id)sender{
50CCTransitionSlideInL* transitionScene =
51[CCTransitionSlideInL transitionWithDuration:2.0 scene:[MenuLayer scene]];
52[[CCDirector sharedDirector] replaceScene:transitionScene];
53}

SettingLayer類代碼在13.13.2節(jié)中已經(jīng)詳細(xì)介紹過,這里不再贅述。

修改IntroLayer.m文件

IntroLayer默認(rèn)加載HelloWorldLayer,但此時我們不再使用HelloWorldLayer作為應(yīng)用的第一個場景,而是使用MenuLayer作為應(yīng)用的第一個場景,因此需要修改IntroLayer,將IntroLayer改為加載MenuLayer場景修改如下。

IntroLayer.m文件的頂部添加所包含的頭文件:

1#import "MenuLayer.h"

修改-(void) makeTransition:(ccTime)dt方法,將該方法改成下面的代碼。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/IntroLayer.m

1-(void) makeTransition:(ccTime)dt
2{
3[[CCDirector sharedDirector] replaceScene:
4[CCTransitionFade transitionWithDuration:1.0
5scene:[MenuLayer scene] withColor:ccWHITE]];
6}

編譯并運(yùn)行游戲,運(yùn)行時模擬器顯示效果如圖13.58所示。

瘋狂ios講義之瘋狂打飛機(jī)(1)

3預(yù)加載游戲資源

在真實(shí)項(xiàng)目當(dāng)中,在游戲開始前,都會預(yù)先加載游戲所需要的圖片、背景音樂、音效等資源,這里介紹如何制作一個PreloadLayer來預(yù)加載游戲資源。

1. 創(chuàng)建PreloadLayer

選擇“AirfightGame”組并單擊右鍵,選擇“New File”,在左邊欄中選擇“cocos2d v2.x”模板,在右邊的模板類中選擇“CCNode class”模板類,“Subclass of”選擇“CCLayer”,然后單擊“Next”按鈕。命名為“PreloadLayer”,然后單擊“Create”按鈕。

PreloadLayer繼承自CCLayer,提供一個類方法sceneCCDirector對象調(diào)用。該類的作用是預(yù)加載游戲資源,在加載過程中會顯示一個進(jìn)度條,進(jìn)度條全部顯示完成代表加載完畢,加載完畢后顯示游戲主場景。

首先打開PreloadLayer.m文件,先在文件上方定義一個私有的Category。實(shí)現(xiàn)代碼如下。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/PreloadLayer.m

/**
 定義一個私有的Category,為了不讓API暴露給客戶端
 將一些類內(nèi)部所使用的方法和變量放在私有的擴(kuò)展里面,而不是直接聲明在頭文件當(dāng)中
 */
@interface PreloadLayer ()
- (void) loadMusics:(NSArray *) musicFiles;  // 加載背景音樂
- (void) loadSounds:(NSArray *) soundClips;  // 加載游戲音效
- (void) loadSpriteSheets:(NSArray *) spriteSheets;  // 加載精靈表單
- (void) loadingComplete;  // 資源全部加載完成,切換到另一個游戲場景
- (void) progressUpdate;  // 更新游戲進(jìn)度條,計(jì)算何時加載完成
@end;

這里定義了一系列的load方法,每個方法接收一個NSArray數(shù)組作為參數(shù)。這些參數(shù)代表一些具體資源的文件名,參數(shù)值會從一個配置文件中讀取出來,該配置文件在之后的代碼實(shí)現(xiàn)時會給出。

然后定義3個變量,其中sourceCount用來保存游戲需要加載的資源總數(shù);progress用于顯示進(jìn)度條,CCProgressTimer 類是cocos2d中對進(jìn)度條的一個封裝,用來實(shí)現(xiàn)各種進(jìn)度條功能,非常方便,之后我們還會使用該類來實(shí)現(xiàn)游戲的自定義血條量;progressInterval代表進(jìn)度條更新的次數(shù)。實(shí)現(xiàn)代碼如下:

@implementation PreloadLayer
// 用來保存游戲需要加載的資源總數(shù)
int sourceCount;
// 顯示進(jìn)度條的成員變量
CCProgressTimer* progress;
// 代表進(jìn)度條更新的次數(shù)
float progressInterval;
2. PreloadLayer的具體實(shí)現(xiàn)

創(chuàng)建一個preloadResources.plist文件,該文件用于保存項(xiàng)目需要的所有資源文件,文件內(nèi)容如圖13.59所示。

瘋狂ios講義之瘋狂打飛機(jī)(1)


可以看出,加載的音效是b0.mp3,精靈表單是airfightSheet.plist,背景音樂是s3.wav。

瘋狂ios講義之瘋狂打飛機(jī)(1)

PreloadLayer.m文件中添加代碼。實(shí)現(xiàn)代碼如下。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/PreloadLayer.m

+ (CCScene *) scene
{
    CCScene* scene = [CCScene node];
    PreloadLayer* layer = [PreloadLayer node];
    [scene addChild:layer];
    return scene;
}
- (id) init{
    if((self = [super init])){
        // 獲取屏幕大小
        CGSize winSize = [[CCDirector sharedDirector] winSize];
        // 創(chuàng)建一個進(jìn)度條精靈
        CCSprite* barSprite = [CCSprite spriteWithFile:@"progressbar.png"];
        // 初始化一個CCProgressTimer進(jìn)度條對象
        progress = [CCProgressTimer progressWithSprite:barSprite];
        // setPercentage:0.0f,表示并未加載任何資源,表現(xiàn)在屏幕上就是什么也看不見
        [progress setPercentage:0.0f];
        // 由于圖片大小關(guān)系,把scale設(shè)置成0.5,即縮小一半
        progress.scale = 0.5;
        // 設(shè)置進(jìn)度條動畫的起始位置,默認(rèn)在圖片的中點(diǎn)
        // 如果想要顯示從左到右的一個動畫效果,必須改成(0,y)
        progress.midpoint = ccp(0,0.5);
        // barChangeRate表示是否改變水平或者垂直方向的比例,設(shè)置成1表示改變,0表示不改變
        progress.barChangeRate = ccp(1,0);
        // 本例制作一個從左至右的水平進(jìn)度條,所以midpoint應(yīng)該是(0,0.5)
        // 因?yàn)閤方向需要改變,而y方向不需要改變,所以barChangeRate = ccp(1, 0)
        // kCCProgressTimerTypeBar表示為條形進(jìn)度條
        progress.type = kCCProgressTimerTypeBar;
        // 設(shè)置position在中心點(diǎn)
        [progress setPosition:ccp(winSize.width/2,winSize.height/2)];
        // 將進(jìn)度條添加為當(dāng)前層的子節(jié)點(diǎn)
        [self addChild:progress];
    }
    return self;
}
- (void) onEnterTransitionDidFinish{
    [super onEnterTransitionDidFinish];
    // 加載preloadResources.plist配置文件
    NSString* path = [[CCFileUtils sharedFileUtils]
        fullPathFromRelativePath:@"preloadResources.plist"];
    // 讀取配置文件中的游戲資源名稱列表,返回一個NSDictionary對象
    NSDictionary* resources = [NSDictionary dictionaryWithContentsOfFile:path];
    // 通過key值取出每種不同類型資源的數(shù)組
    NSArray *spriteSheets = [resources objectForKey:@"SpriteSheets"];
    NSArray *sounds = [resources objectForKey:@"Sounds"];
    NSArray *musics = [resources objectForKey:@"Musics"];
    // 調(diào)用數(shù)組的count方法得到總共需要加載的資源數(shù)量
    sourceCount = [spriteSheets count]  + [sounds count] + [musics count];
    // 設(shè)置進(jìn)度條更新次數(shù)=100/需要加載的資源數(shù)量
    progressInterval = 100.0 / (float) sourceCount;
    // 調(diào)用performSelectorOnMainThread在主線程上依次加載每種類型的游戲資源
    // waitUntilDone的值為YES能保證所有的資源按照序列依次加載
    if(sounds){
        [self performSelectorOnMainThread:@selector(loadSounds:)
            withObject:sounds waitUntilDone:YES];
    }
    if(spriteSheets){
        [self performSelectorOnMainThread:@selector(loadSpriteSheets:)
            withObject:spriteSheets waitUntilDone:YES];
    }
    if(musics){
        [self performSelectorOnMainThread:@selector(loadMusic:)
            withObject:musics waitUntilDone:YES];
    }
}
// 加載背景音樂
- (void) loadMusics:(NSArray *)musicFiles{
    for (NSString *music in musicFiles) {
        [[SimpleAudioEngine sharedEngine] preloadBackgroundMusic:music];
        [self progressUpdate];
    }
}
// 加載聲音
- (void) loadSounds:(NSArray *)soundClips{
    for (NSString *soundClip in soundClips) {
        [[SimpleAudioEngine sharedEngine] preloadEffect:soundClip];
        [self progressUpdate];
    }
}
// 加載精靈表單
- (void) loadSpriteSheets:(NSArray *)spriteSheets{
    for (NSString *spriteSheet in spriteSheets) {
        // 該方法會加載與該plist文件名稱相同但后綴為.png的紋理圖片
        // 把該plist的所有spriteFrame信息讀取出來
        // 在之后的代碼中可以通過spriteFrameWithName獲取相應(yīng)的精靈幀
        // 本例中airfightSheet.plist對應(yīng)airfightSheet.png
        [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile: spriteSheet];
        [self progressUpdate];
    }
}
- (void) progressUpdate{
    // 每次調(diào)用該方法說明加載一個資源,自減更新資源總數(shù)
    if (--sourceCount) {
        [progress setPercentage:100.0f-(progressInterval * sourceCount)];
    }else{
        // CCProgressFromTo動作用于以漸進(jìn)的方式顯示圖片
        // actionWithDuration表示持續(xù)0.5秒,from表示進(jìn)度條百分百從開始一直到100
        CCProgressFromTo *ac = [CCProgressFromTo actionWithDuration:0.5
            from:progress.percentage to:100];
        // 當(dāng)資源全部加載完畢時調(diào)用loadingComplete方法
        CCCallBlock *callback = [CCCallBlock actionWithBlock:^() {
            [self loadingComplete];
        }];
        // CCSequence組合動作
        id action = [CCSequence actions:ac.callback.nil];
        // 進(jìn)度條執(zhí)行動作
        [progress runAction:action];
    }
}
// 延遲2秒之后運(yùn)行一個場景切換特效跳轉(zhuǎn)到游戲主場景,即HelloWorldLayer
- (void) loadingComplete{
    CCDelayTime *delay = [CCDelayTime actionWithDuration:2.0f];
    CCCallBlock *callblock = [CCCallBlock actionWithBlock:^(void) {
        [[CCDirector sharedDirector] replaceScene:
        [CCTransitionFade transitionWithDuration:1.0f scene:[HelloWorldLayer scene]]];
    }];
    CCSequence *sequence = [CCSequence actions:delay.callblock.nil];
    [self runAction:sequence];
}
@end

下面依次解釋以上代碼中的每一個方法。

+(CCScene *) scene方法很簡單,和前面的一樣,首先創(chuàng)建了一個scene場景,然后創(chuàng)建了一個PreloadLayer層,將PreloadLayer層作為scene場景的子節(jié)點(diǎn),最后返回scene場景。

init方法首先獲取屏幕窗口大小,然后創(chuàng)建了一個進(jìn)度條。這里使用progressbar.png圖片初始化一個精靈,再通過該精靈初始化一個CCProgressTimer對象,設(shè)置setPercentage屬性為0,表示當(dāng)前未加載任何資源,表現(xiàn)在屏幕上就是什么也看不見。由于圖片大小關(guān)系,把scale設(shè)置成0.5,即縮小一半。

接下來設(shè)置CCProgressTimer對象最重要的3個參數(shù)。

qmidpoint:表示進(jìn)度條動畫的起始位置,默認(rèn)在圖片的中點(diǎn),如果想要顯示從左到右的一個動畫效果,則必須改成(0,y)。

qbarChangeRate:表示是否改變水平或者垂直方向的比例,設(shè)置成1表示改變,0表示不改變。本例制作一個從左至右的水平進(jìn)度條,所以midpoint應(yīng)該是(0,0.5)。因?yàn)?/span>x方向需要改變,而y方向不需要改變,所以設(shè)置barChangeRateccp(1,0)

qtype:設(shè)置為kCCProgressTimerTypeBar,表示條形進(jìn)度條。

關(guān)于CCProgressTimer類的使用可以參考官方文檔,讀者也可以找到cocos2d的示例項(xiàng)目cocos2d-tests-ios.xcodeproj,并運(yùn)行ActionProgressTest這個TARGET。感興趣的讀者也可以仔細(xì)分析該項(xiàng)目中的ActionProgressTest.m源文件(位于項(xiàng)目的tests目錄下)來掌握不同progress的用法示例。

最后設(shè)置CCProgressTimer對象的位置,并添加為當(dāng)前層的子節(jié)點(diǎn)。

onEnterTransitionDidFinish方法加載配置文件preloadResources.plist,讀取配置文件中的游戲資源名稱列表并存儲在不同的數(shù)組中。首先使用CCFileUtil獲得plist文件的具體路徑,調(diào)用NSDictionarydictionaryWithContentsOfFile方法把該文件轉(zhuǎn)換成一個字典對象。然后通過字典的key值取出不同類型資源的數(shù)組,調(diào)用每個數(shù)組的count方法累加得到總共需要加載的資源總數(shù)量,使用100除以資源總數(shù)量獲得進(jìn)度條需要更新次數(shù)用于之后計(jì)算進(jìn)度條顯示的百分比。最后將數(shù)組作為參數(shù)調(diào)用performSelectorOnMainThread: withObject: waitUntilDone:方法在主線程中依次加載每種類型的游戲資源,將waitUntilDone的值設(shè)置為“YES”能保證所有的資源按照序列依次加載。

loadMusics:loadSounds:方法比較簡單,通過循環(huán)遍歷數(shù)組,預(yù)加載背景音樂和音效,加載完后調(diào)用progressUpdate方法更新進(jìn)度條。

這里需要注意的是loadSpriteSheets:方法,該方法循環(huán)遍歷數(shù)組,數(shù)組的每個元素是一個plist文件名稱,調(diào)用CCSpriteFrameCacheaddSpriteFramesWithFile時,該方法會加載與該plist文件名稱相同但后綴為.png的紋理圖片(本例中airfightSheet.plist對應(yīng)airfightSheet.png),把該plist的所有spriteFrame信息讀取出來,之后在項(xiàng)目當(dāng)中就可以通過spriteFrameWithName獲取相應(yīng)的精靈幀了。

progressUpdate方法比較簡單,每次被調(diào)用時自減更新資源總數(shù)變量,修改進(jìn)度條的百分比。當(dāng)資源全部加載完畢時調(diào)用loadingComplete方法。

loadingComplete方法被調(diào)用說明資源加載完畢,延遲2秒后運(yùn)行一個場景切換特效跳轉(zhuǎn)到游戲主場景HelloWorldLayer。

編譯并運(yùn)行游戲,選擇“開始游戲”菜單項(xiàng),模擬器首先會顯示一個進(jìn)度條,進(jìn)度條全部顯示完畢切換到HelloWorldLayer顯示經(jīng)典的Hello World畫面。恭喜你!資源文件加載成功,進(jìn)度條功能實(shí)現(xiàn)。運(yùn)行時模擬器顯示效果如圖13.60所示。

瘋狂ios講義之瘋狂打飛機(jī)(1)
   ————本文節(jié)選自《瘋狂ios講義(下)》   瘋狂ios講義之瘋狂打飛機(jī)(1)


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI