遊戲當中怎麼能少了千軍萬馬的敵人呢?如今,咱們來添加一些敵機,大量的敵機將從屏幕上方隨機出現,並以隨機的速度向下俯衝。這些敵機暫時不會發射×××,以後讀者能夠本身添加該功能。具體步驟以下。數組
自定義一個FKSprite類,繼承自CCSprite,由於建立的敵機玩家會發射×××去消滅,爲了增長遊戲的趣味性和難度,須要加入敵機的生命值、血條和爆炸效果等特效。在FKSprite類中定義了相關變量用於存儲數據。實現代碼以下。dom
程序清單:codes/13/13.14/AirfightGame/AirfightGame/FKSprite.hide
@interface FKSprite : CCSprite {函數
}oop
// 精靈的生命值動畫
@property int lifeValue;spa
// 精靈的名稱.net
@property NSString* name;設計
// 敵機的血條code
@property CCProgressTimer* enemyPlaneHP;
// 血條的更新量
@property float HPInterval;
打開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{
// 控制count爲100的倍數時添加一架敵機
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.png和e2.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所示。
如今,大量的敵機向玩家飛機俯衝過來,不用多說,給玩家飛機添加×××射擊功能打爆它們。這裏咱們設計成×××自動發射,而且×××是無限的,這樣玩家就只須要專心控制飛機的飛行就能夠了。具體步驟以下。
打開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;
// 控制count爲8的倍數時發射一顆×××
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所示。
有了音效,有了爆炸效果,沒有背景音樂好像缺乏點熱血澎湃的遊戲感受,讓咱們立刻加入背景音樂吧。
找到onEnter方法,在遊戲的主循環代碼以前添加背景音樂播放功能,實現代碼以下(程序清單同上)。
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"s3.wav" loop:YES];
[[SimpleAudioEngine sharedEngine] setBackgroundMusicVolume:0.5];
再次編譯並運行遊戲,開始遊戲時就能夠聽見使人熱血澎湃的背景音樂了。讀者能夠按照13.13.2節的內容爲遊戲增長聲音設置功能選項,包括聲音開關、聲音大小調節等,這裏再也不贅述。