瘋狂ios之瘋狂打飛機遊戲(3)

13.14.7添加敵機

遊戲當中怎麼能少了千軍萬馬的敵人呢?現在,我們來添加一些敵機,大量的敵機將從屏幕上方隨機出現,並以隨機的速度向下俯衝。這些敵機暫時不會發射子彈,之後讀者可以自己添加該功能。具體步驟如下。

自定義一個FKSprite類,繼承自CCSprite,因爲創建的敵機玩家會發射子彈去消滅,爲了增加遊戲的趣味性和難度,需要加入敵機的生命值、血條和爆炸效果等特效。在FKSprite類中定義了相關變量用於存儲數據。實現代碼如下。

程序清單:codes/13/13.14/AirfightGame/AirfightGame/FKSprite.h

@interface FKSprite : CCSprite {

}

// 精靈的生命值

@property int lifeValue;

// 精靈的名稱

@property NSString* name;

// 敵機的血條

@property CCProgressTimer* enemyPlaneHP;

// 血條的更新量

@property float HPInterval;

@end

打開HelloWorldLayer.m文件,添加兩個變量,實現代碼如下。

// 敵機數組

CCArray* enemyPlaneArray;

// 遊戲幀計數器

NSInteger count;

在私有分類中添加兩個和敵機相關的方法,實現代碼如下。

// 更新敵機

-(void) updateEnemySprite:(ccTime)delta;

// 敵機離開屏幕刪除

-(void) removeEnemySprite:(ccTime)delta;

updateEnemySprite:用於控制敵機的創建、俯衝。實現代碼如下。

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

-(void) updateEnemySprite:(ccTime)delta{

// 控制count100的倍數時添加一架敵機

if (count % 30 == 0)

{

// FKSprite精靈對象繼承自CCSprite,增加了生命值

FKSprite* enemyPlaneSprite;

// 根據rand隨機數添加不同的敵機

int rand = arc4random() % 2;

// 使用隨機數來設置敵機的X座標

int randX = arc4random() % (screenWidth - 40) + 20;

switch(rand)

{

case 0:

// 創建代表敵機

enemyPlaneSprite = [FKSprite spriteWithSpriteFrameName:@"e0.png"];

enemyPlaneSprite.position = ccp(randX,480+enemyPlaneSprite.contentSize.height);

enemyPlaneSprite.name = @"e0";

enemyPlaneSprite.lifeValue = 1;

break;

case 1:

// 創建代表敵機

enemyPlaneSprite = [FKSprite spriteWithSpriteFrameName:@"e2.png"];

enemyPlaneSprite.position = ccp(randX,480+enemyPlaneSprite.contentSize.height);

enemyPlaneSprite.name = @"e2";

enemyPlaneSprite.lifeValue = 1;

break;

}

// 獲取隨機時間(敵機俯衝的時間)

float durationTime = arc4random() %2 + 2;

// 敵機俯衝

id moveBy = [CCMoveBy actionWithDuration:durationTime

position:ccp(0,-enemyPlaneSprite.position.y-enemyPlaneSprite.contentSize.height)];

[enemyPlaneSprite runAction:moveBy];

// 將敵機精靈添加到敵機數組中

[enemyPlaneArray addObject:enemyPlaneSprite];

// 獲得精靈表單

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

[batchNode addChild:enemyPlaneSprite z:4];

}else{

if (count % 200 == 0)

{

int randX = arc4random() % (screenWidth - 40) + 20;

// FKSprite精靈對象繼承自CCSprite,增加了生命值

FKSprite* enemyPlaneSprite;

// 創建代表敵機

enemyPlaneSprite = [FKSprite spriteWithSpriteFrameName:@"e1.png"];

enemyPlaneSprite.position = ccp(randX,480+enemyPlaneSprite.contentSize.height);

enemyPlaneSprite.name = @"e1";

enemyPlaneSprite.lifeValue = 10;

// 獲取隨機時間(敵機掉落的時間)

float durationTime = arc4random() %2 + 2;

// 敵機俯衝

id moveBy = [CCMoveBy actionWithDuration:durationTime

position:ccp(0,-enemyPlaneSprite.position.y-enemyPlaneSprite.contentSize.height)];

[enemyPlaneSprite runAction:moveBy];

// 將敵機精靈添加到敵機數組中

[enemyPlaneArray addObject:enemyPlaneSprite];

// 獲得精靈表單

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

[batchNode addChild:enemyPlaneSprite z:4];

// 創建一個進度條精靈

CCSprite* barSprite = [CCSprite spriteWithFile:@"planeHP.png"];

// 初始化一個CCProgressTimer對象

CCProgressTimer* enemyPlaneHP = [CCProgressTimer progressWithSprite:barSprite];

// setPercentage:0.0f,表示並未加載任何資源,表現在畫面上就是什麼也看不見

[enemyPlaneHP setPercentage:0.0f];

// 由於圖片大小關係,把scale設置成0.15,即縮小一半

enemyPlaneHP.scale = 0.15;

enemyPlaneHP.midpoint = ccp(0,0.5);

enemyPlaneHP.barChangeRate = ccp(1, 0);

enemyPlaneHP.type = kCCProgressTimerTypeBar;

enemyPlaneHP.percentage = 100;

CGPoint pos = enemyPlaneSprite.position;

enemyPlaneHP.position = ccp(pos.x, pos.y+32);

[self addChild:enemyPlaneHP];

id moveBy2 = [CCMoveBy actionWithDuration:durationTime

position:ccp(0,-enemyPlaneSprite.position.y-enemyPlaneSprite.contentSize.height)];

[enemyPlaneHP runAction:moveBy2];

enemyPlaneSprite.enemyPlaneHP = enemyPlaneHP;

enemyPlaneSprite.HPInterval = 100.0 / (float)enemyPlaneSprite.lifeValue;

}

}

}

這段代碼有點長,接下來爲大家詳細解釋。

首先,遊戲中出現的小敵機有3種,通過count變量來控制敵機出現的頻率(count變量在update方法中自增)。

count%30==0時,隨機創建兩種小飛機,對應e0.pnge2.png圖片,設置生命值爲1。接下來獲取一個隨機俯衝時間,根據該時間創建一個moveBy動作,讓飛機執行moveBy動作俯衝。同時將敵機精靈添加到敵機數組和精靈表單當中。

count%200==0時,創建一種小飛碟,對應e1.png圖片,設置生命值爲10。接下來獲取一個隨機俯衝時間,根據該時間創建一個moveBy動作,讓飛機執行moveBy動作俯衝。同時將敵機精靈添加到敵機數組和精靈表單當中。之後使用前面用過的CCProgressTimer類創建了一個血條,遊戲中血條會隨着敵機被玩家飛機的子彈打中而減少,從而實現非常炫的射擊效果。

removeEnemySprite的作用是當敵機已經移出屏幕外時刪除敵機精靈。實現代碼如下。

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

-(void) removeEnemySprite:(ccTime)delta{

// 獲得精靈表單

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

// 定義循環變量

CCSprite* enemyPlaneSprite;

// 遍歷所有的敵機精靈

CCARRAY_FOREACH(enemyPlaneArray, enemyPlaneSprite){

// 如果敵機已經移出屏幕外,則刪除敵機精靈

if (enemyPlaneSprite.position.y <= -enemyPlaneSprite.contentSize.height)

{

// 從精靈表單中刪除該敵機精靈

[batchNode removeChild:enemyPlaneSprite cleanup:YES];

// 從敵機數組中刪除該敵機精靈

[enemyPlaneArray removeObject:enemyPlaneSprite];

}

}

}

removeEnemySprite:比較簡單,首先調用getChildByTag:方法獲取精靈表單,然後遍歷敵機數組,判斷敵機的y軸若超出屏幕範圍,則從精靈表單和敵機數組中刪除敵機精靈。

找到onEnter方法,在⑤部分代碼後初始化敵機數組,實現代碼如下(程序清單同上)。

enemyPlaneArray = [[CCArray alloc] init];

修改update方法,實現代碼如下(程序清單同上)。

-(void) update:(ccTime)delta{

count++;

[self updateBackground:delta];

[self updateEnemySprite:delta];

[self removeEnemySprite:delta];

}

再次編譯並運行遊戲,大量的敵機會隨機出現,並向屏幕下方俯衝。模擬器顯示效果如圖13.63所示。

090208_or0X_262659.jpg


13.14.8玩家飛機添加子彈並射擊

現在,大量的敵機向玩家飛機俯衝過來,不用多說,給玩家飛機添加子彈射擊功能打爆它們。這裏我們設計成子彈自動發射,並且子彈是無限的,這樣玩家就只需要專心控制飛機的飛行就可以了。具體步驟如下。

打開HelloWorldLayer.m文件,添加變量,實現代碼如下(程序清單同上)。

// 代表子彈精靈數組

CCArray* bulletArray;

在私有分類中添加3個和敵機相關的方法,實現代碼如下(程序清單同上)。

// 更新子彈

-(void) updateShooting:(ccTime)delta;

// 子彈離開屏幕,刪除

-(void) removeBulletSprite:(ccTime)delta;

// 碰撞檢測

-(void) collisionDetection:(ccTime)delta;

updateShooting:方法用於不斷髮射子彈。實現代碼如下(程序清單同上)。

-(void) updateShooting:(ccTime)delta{

// 獲得精靈表單

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

// 飛機精靈座標

CGPoint pos = planeSprite.position;

// 控制count8的倍數時發射一顆子彈

if(count % 8 == 0)

{

// 創建代表子彈的精靈

CCSprite* bulletSprite = [CCSprite spriteWithSpriteFrameName:@"bullet.png"];

// 設置子彈座標

CGPoint bulletPos = ccp(pos.x, pos.y +

planeSprite.contentSize.height/2 + bulletSprite.contentSize.height);

bulletSprite.position = bulletPos;

// 子彈移動時間爲0.4秒,移動距離爲屏幕高度-子彈的y

id moveBy = [CCMoveBy actionWithDuration:0.4f position:ccp(0, screenHeight-bulletPos.y)];

[bulletSprite runAction:moveBy];

// 將子彈精靈添加到精靈表單中

[batchNode addChild:bulletSprite z:4];

// 將子彈精靈添加到子彈精靈數組中

[bulletArray addObject:bulletSprite];

}

}

updateShooting:方法並不複雜,首先獲取精靈表單,然後獲取玩家飛機的座標位置,當count%8==0時創建一顆子彈精靈,並執行moveBy動作達到發射子彈的效果,最後將子彈精靈添加到精靈表單和子彈精靈數組當中。

removeBulletSprite:方法的作用是當子彈精靈已經移出屏幕外時刪除子彈精靈。實現代碼如下(程序清單同上)。

-(void) removeBulletSprite:(ccTime)delta{

// 獲得精靈表單

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

CCSprite* bulletSprite;

// 遍歷所有的子彈

CCARRAY_FOREACH(bulletArray, bulletSprite){

// 如果子彈已經移出屏幕外,則刪除子彈

if (bulletSprite.position.y >=screenHeight){

// 從精靈表單中刪除該子彈精靈

[batchNode removeChild:bulletSprite cleanup:YES];

// 從子彈數組中刪除該子彈精靈

[bulletArray removeObject:bulletSprite];

}

}

}

removeBulletSprite:方法也比較簡單,首先調用getChildByTag:方法獲取精靈表單,然後遍歷子彈數組,判斷子彈的y軸若超出屏幕範圍,則從子彈表單和子彈數組中刪除子彈精靈。

collisionDetection:是檢查玩家飛機和敵機碰撞或者子彈和敵機碰撞的方法。實現代碼如下(程序清單同上)。

-(void) collisionDetection:(ccTime)dt{

// 獲得精靈表單

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

// 定義循環變量

FKSprite* enemyPlaneSprite;

CCSprite* bulletSprite;

// 遍歷敵機數組

CCARRAY_FOREACH(enemyPlaneArray, enemyPlaneSprite){

// 玩家飛機和敵機發生碰撞

if(CGRectIntersectsRect(planeSprite.boundingBox,enemyPlaneSprite.boundingBox)){

// 播放爆炸動畫

[self bombAnimate:@"blast" :enemyPlaneSprite.position ];

// 刪除敵機精靈

[enemyPlaneArray removeObject:enemyPlaneSprite];

[batchNode removeChild:enemyPlaneSprite cleanup:YES];

[planeSprite stopAllActions];

// 刪除玩家精靈

[batchNode removeChild:planeSprite cleanup:YES];

[self gameOver:@"遊戲結束!"];

}

// 遍歷子彈數組

CCARRAY_FOREACH(bulletArray, bulletSprite){

// 如果敵機與子彈發生碰撞

if(CGRectIntersectsRect(enemyPlaneSprite.boundingBox, bulletSprite.boundingBox)){

// 播放子彈音效

[[SimpleAudioEngine sharedEngine] playEffect:@"bullet.mp3"];

// 刪除子彈精靈

[bulletArray removeObject:bulletSprite];

[batchNode removeChild:bulletSprite cleanup:YES];

// 敵機生命值減1

enemyPlaneSprite.lifeValue--;

// 血條減少

if (enemyPlaneSprite.enemyPlaneHP != nil) {

enemyPlaneSprite.enemyPlaneHP.percentage

= enemyPlaneSprite.HPInterval * enemyPlaneSprite.lifeValue;

}

// 判斷敵機的生命值

if (enemyPlaneSprite.lifeValue <= 0) {

// 刪除敵機精靈

[enemyPlaneArray removeObject:enemyPlaneSprite];

[batchNode removeChild:enemyPlaneSprite cleanup:YES];

// 播放爆炸動畫

[self bombAnimate:@"blast" :enemyPlaneSprite.position ];

// 播放爆炸音效

[[SimpleAudioEngine sharedEngine] playEffect:@"b0.mp3"];

}

break;

}

}

}

}

collisionDetection:方法首先調用getChildByTag:方法獲取精靈表單,然後循環遍歷敵機數組。CGRectIntersectsRect(rect 1.feet 2)函數可以判斷矩形結構是否交叉,兩個矩形對象是否重疊,常用來檢測兩個圖標是否發生碰撞。CCNode有一個屬性boundingBox,會返回精靈的邊界框。使用這個屬性比自己計算要好,因爲這樣做更簡單,同時也考慮了精靈的變形。通過CGRectIntersectsRect(rect 1.feet 2)函數判斷玩家飛機和敵機是否發生碰撞,如果發生碰撞,則播放一段爆炸動畫,然後從敵機數組和精靈表單中刪除敵機精靈,再從精靈表單中刪除玩家飛機精靈,最後調用gameOver:方法結束遊戲。

如果玩家飛機和敵機沒有發生碰撞,則不循環遍歷子彈數組,判斷子彈和敵機是否發生碰撞,如果發生碰撞,則播放子彈音效,刪除子彈精靈,將敵機生命值減去1;如果敵機有血條,則更新血條(小飛碟生命值爲10,有血條)。接下來判斷敵機的生命值,如果敵機生命值爲0,則從敵機數組和精靈表單中刪除敵機精靈,播放爆炸動畫和爆炸音效。

在私有分類中添加兩個方法,實現代碼如下(程序清單同上)。

// 播放爆炸動畫

-(void) bombAnimate:(NSString*) name : (CGPoint) position;

// 遊戲結束

-(void) gameOver:(NSString*) labelString;

bombAnimate: name:方法用於播放爆炸動畫。實現代碼如下(程序清單同上)。

-(void) bombAnimate:(NSString*) name : (CGPoint) position {

NSString* bombName = [NSString stringWithFormat:@"%@0.png",name];

float delay = 0.08f;

CCSpriteBatchNode *batchNode = (CCSpriteBatchNode*)[self getChildByTag:kTagBatchNode];

CCSprite* blastSprite = [CCSprite spriteWithSpriteFrameName:bombName];

blastSprite.position = position;

// 獲得動畫幀

CCAnimation* blastAnimation = [self getAnimationByName:name delay:delay animNum:4];

// 組合動作:1.播放動畫 2.刪除動畫精靈對象

id action = [CCSequence actions: [CCAnimate actionWithAnimation:blastAnimation],

[CCCallBlock actionWithBlock:^() {

[batchNode removeChild:blastSprite cleanup:YES];

}],nil];

[blastSprite runAction:action];

[batchNode addChild:blastSprite z:4];

}

bombAnimate: name:方法接收傳進來的爆炸效果名稱,獲取爆炸動畫幀,先播放動畫,動畫播放完畢後刪除動畫。

gameOver:方法用於遊戲結束時清除精靈對象並提示遊戲信息。實現代碼如下(程序清單同上)。

-(void) gameOver:(NSString*) labelString{

// 停止所有動作

[self unscheduleUpdate];

// 遊戲結束

CCMenuItemFont* gameItem = [CCMenuItemFont itemWithString:labelString

target:self selector:@selector(onRestartGame:)];

gameItem.position=ccp(screenWidth/2, screenHeight/2);

CCMenu* menu = [CCMenu menuWithItems:gameItem, nil];

menu.position = CGPointZero;

[self addChild:menu];

}

找到onEnter方法,在⑤部分代碼後初始化子彈數組,實現代碼如下。

bulletArray = [[CCArray alloc] init];

修改update方法,實現代碼如下(程序清單同上)。

-(void) update:(ccTime)delta{

count++;

[self updateBackground:delta];

[self updateEnemySprite:delta];

[self removeEnemySprite:delta];

[self updateShooting:delta];

[self removeBulletSprite:delta];

self collisionDetection:delta];

}

再次編譯並運行遊戲,大量的敵機會隨機出現,並向屏幕下方俯衝,控制玩家飛機發射子彈,子彈擊中敵機顯示爆炸效果。模擬器顯示效果如圖13.64所示。

090328_LNsf_262659.jpg

13.14.9添加背景音樂

有了音效,有了爆炸效果,沒有背景音樂好像缺少點熱血澎湃的遊戲感覺,讓我們馬上加入背景音樂吧。

找到onEnter方法,在遊戲的主循環代碼之前添加背景音樂播放功能,實現代碼如下(程序清單同上)。

[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"s3.wav" loop:YES];

[[SimpleAudioEngine sharedEngine] setBackgroundMusicVolume:0.5];

再次編譯並運行遊戲,開始遊戲時就可以聽見令人熱血澎湃的背景音樂了。讀者可以按照13.13.2節的內容爲遊戲增加聲音設置功能選項,包括聲音開關、聲音大小調節等,這裏不再贅述。


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