你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> iOS_31_cocos2d_微信飛機

iOS_31_cocos2d_微信飛機

編輯:IOS開發綜合
最終效果圖:

\

紋理素材

\

\

場景

//
//  GameScene.m
//  31_cocos2D入門
//
//  Created by beyond on 14-9-27.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  雷電,游戲場景

#import "GameScene.h"
#import "Hero.h"
// 背景音樂
//#import "SimpleAudioEngine.h"
#import "OALSimpleAudio.h"
// 子彈精靈
#import "Pellet.h"
// 敵機
#import "Enemy.h"




// 一次性初始化的子彈的最大數量
#define kPelletMaxCount 10
// 子彈兩次出現之間的總的累計時間間隔
#define kPelletTotalIntervalTime 0.3

// 敵機的最大數量
#define kEnemyMaxCount 5

@interface GameScene()
{
    // 因為一個spriteBatchNode對應一個紋理(圖片),因此,從紋理相冊裁剪出來的小精靈(幀),全部交給spriteBatchNode統一管理,場景只需要 與 spriteBatchNode打交道
    CCSpriteBatchNode *_batch;
    // 背景2圖片 始終在背景1圖片的頭頂上
    CCSprite *_bg1, *_bg2;
    
    // 英雄,主角
    Hero *_hero;
    // 標記 是否正在運行
    BOOL _isGameRuning;
    

    // 重要~~~~子彈緩存
    NSMutableArray *_pelletArr;
    // 成員變量 用於記住 累加的間隔時間,它當達到一定量時(如0.3秒),才發射一串子彈
    // 子彈兩次出現之間的總的間隔(累積)時間
    CGFloat _pelletTotalIntervalTime;
    
    // 重要~~~~敵人緩存
    NSMutableArray *_enemyArr;
   
}
@end

@implementation GameScene

#pragma mark - 覆蓋父類方法
-(id)init
{
    if (self=[super init]) {
        
        // 1.基本初始化
        [self setupBasic];
        
        // 2.初始化背景
        // 初始化背景 ,並添加到batchNode中,統一管理,在時鐘方法裡,滾動背景
        [self setupBg];
        
        // 3.初始化英雄
        // 初始化英雄 ,並添加到batchNode中,統一管理,在時鐘方法裡,碰撞檢測
        [self setupPlayer];

        // 4.初始化子彈
        // 初始化指定數量的子彈 ,並添加到batchNode中,統一管理,在時鐘方法裡,射出子彈
        [self setupPelletArr];

        // 5.初始化敵機
        [self setupEnemyArr];

        // 6.開始游戲
        [self startGame];
    }
    return self;
}

#pragma mark - 初始化

#pragma mark 1.基本初始化
- (void)setupBasic
{
    
    
    // 1.加載紋理相冊 到精靈幀緩存
    [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"gameArts.plist"];
    
    // 2.創建sprite批處理
    _batch = [CCSpriteBatchNode batchNodeWithFile:@"gameArts.png"];
    [self addChild:_batch];
    
    // 3.添加一個按鈕,暫停或繼續游戲
    [self setupPauseButton];
}
// 4.添加一個按鈕,暫停或繼續游戲
- (void)setupPauseButton
{
    // 調用父類封裝的方法,綁定監聽方法:gameControlBtnClicked
     [self addBtn:@"暫停/繼續" position:ccp(0.5, 0.5) target:self sel:@selector(gameControlBtnClicked)];
    
}
#pragma mark 2.初始化背景
- (void)setupBg
{

    NSString *bgPicName = @"background_2.png";
    _bg1 = [CCSprite spriteWithImageNamed:bgPicName];
    _bg1.anchorPoint = CGPointZero;
    
    // 背景2圖片 始終在背景1圖片 的頭頂上
    _bg2 = [CCSprite spriteWithImageNamed:bgPicName];
    _bg2.anchorPoint = CGPointZero;
    
    [_batch addChild:_bg1];
    [_batch addChild:_bg2];
}
#pragma mark 3.初始化玩家
- (void)setupPlayer
{
    _hero = [Hero node];
    // 因為是從同一個大紋理中,根據key裁剪出來的,所以可以加到同一個精靈batchNode,由它統一管理
    [_batch addChild:_hero];
}
#pragma mark 4.初始化子彈緩存
// 初始化指定數量的子彈 ,並添加到batchNode中,統一管理,在時鐘方法裡,射出子彈
- (void)setupPelletArr
{
    _pelletArr = [NSMutableArray array];
    // 初始化指定數量的子彈 ,並添加到batchNode中,統一管理,在時鐘方法裡,射出子彈
    for (int i = 0; i= kPelletTotalIntervalTime) {
        
        Pellet *pellet;
        for (pellet in _pelletArr) {
            // 如果數組中,還有 子彈不可見,說明在屏幕外;因此,可回收循環使用;只需重新調整位置 發射出去
            if (pellet.visible == NO) {
                CGPoint from = ccp(_hero.position.x, CGRectGetMaxY(_hero.boundingBox));
                [pellet emitFrom:from velocity:ccp(0, 200)];
                break;
            }
            // 如果,數組中沒有一個可以用的....那麼遍歷完後,只能創建新的了,(記得也要加到數組中去哦~)
            pellet = nil;
        }
        
        // 如果,數組中沒有一個可以用的....那麼遍歷完後,只能創建新的發射了,(記得也要加到數組中去哦~)
        // 沒有可循環利用的子彈
        if (pellet == nil) {
            // 其實,內部已經封裝了,默認創建出來的新子彈是不可見,只有在發射emit時,才可見
            Pellet *p = [Pellet node];
            // 大子彈
            p.type = kPelletTypeBig;
            // 重要~~~一定要,記得,添加到數組中
            [_pelletArr addObject:p];
             
            
            // 添加到精靈batchNode
            [_batch addChild:p];
            
            // 射出新子彈
            CGPoint from = ccp(_hero.position.x, CGRectGetMaxY(_hero.boundingBox));
            [p emitFrom:from velocity:ccp(0, 200)];
        }
        // 用於記錄的成員變量,清零
        _pelletTotalIntervalTime = 0;
    }
}

#pragma mark 3.敵機出場作戰
- (void)enemyAnimation:(CCTime)delta
{
    Enemy *enemy;
    for (enemy in _enemyArr) {
        // 如果數組中,還有 敵機不可見,說明在屏幕外;因此,可回收循環使用;只需重新調整位置 參加戰場
        if (enemy.visible == NO) {
            // 具體如何 運動,內部自己決定
            [enemy attendTheBattle];
            // 一次時鐘周期,送一個敵機上戰場
            break;
        }
    }
    
}

#pragma mark 碰撞\邊界檢測
- (void)collsionAndBoundaryCheck
{
    // 子彈檢測
    Pellet *pellet;
    for (pellet in _pelletArr) {
        // 只有在屏幕范圍內,可見的,才需要進行碰撞檢測;如不可見,直接,分析下一個子彈
        if (pellet.visible == NO) continue;
        
        // 1.子彈 與 屏幕 檢測
        // 2.子彈 與 敵機 檢測
        [self checkPellet:pellet];
        
    }// 遍歷子彈緩存數組 結束
    
}
// 1.子彈 與 屏幕 檢測
// 2.子彈 與 敵機 檢測
- (void)checkPellet:(Pellet *)pellet
{
    // 子彈邊框與屏幕邊框 進行交集檢測
    if (!CGRectIntersectsRect(self.boundingBox, pellet.boundingBox)) {
        // 1.離開屏幕了(再無交集),子彈消失
        [pellet dismiss];
         
    } else {
        // 2.子彈還在屏幕內,才要進行,與敵機的 碰撞檢測
        // 敵機檢測
        Enemy *enemy;
        for (enemy in _enemyArr) {
            // 如果不可見,不需要檢測
            // 只有在屏幕范圍內,可見的,才需要進行碰撞檢測;如不可見,直接,分析下一個
            if (enemy.visible == NO) continue;
            // 1.敵機與屏幕rect檢測
            // 2.敵機與子彈檢測
            // 3.敵機與英雄檢測
            [self enemy:enemy checkWithPellet:pellet];
            
        }// 遍歷子彈緩存數組 結束
    }// 子彈 和 敵機的 碰撞檢測
}

// 1.敵機與屏幕rect檢測
// 2.敵機與子彈檢測
// 3.敵機與英雄檢測
- (void)enemy:(Enemy *)enemy checkWithPellet:(Pellet *)pellet
{
    // 敵機 邊框與屏幕rect邊框 進行交集檢測
    if (!CGRectIntersectsRect(self.boundingBox, enemy.boundingBox)) {
        // 如果 沒有交集,代表,敵機 逃離屏幕范圍,故隱藏 敵機;
        [enemy hide];
         
    } else if (CGRectIntersectsRect(pellet.boundingBox, enemy.boundingBox)) {
        // 只有在屏幕范圍內的敵機,才需要 和 (在屏幕范圍內的)子彈 進行交集檢測
        // 首先,隱藏子彈
        [pellet dismiss];
        
        // 然後,敵機中彈
        [enemy gotHit];
    } else {
        // 自定義方法,英雄與敵機 交集檢測
        [self enemyCheckWithHero:enemy];
    }
}
// 自定義方法,英雄與敵機 交集檢測
- (void)enemyCheckWithHero:(Enemy *)enemy
{
    // 子彈 雖然 沒有打中,但是 英雄與敵機 相撞,結果還是,game over
    if (CGRectContainsRect(_hero.boundingBox, enemy.boundingBox)) {
        [_hero dieWithEnemyTogether];
        
        // game over,結束游戲
        [self endGame];
    }
}
#pragma mark - 觸摸事件
// 必須有 touch began ,否則 不能響應
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
     
}
- (void)touchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    // 1.當前點
    CGPoint curPoint = [[CCDirector sharedDirector] convertToGL:[touch locationInView:touch.view]];
    
    // 2.上一個點
    CGPoint prePoint = [[CCDirector sharedDirector] convertToGL:[touch previousLocationInView:touch.view]];
    
    
     
    // 3.設置飛機的位置
    CGPoint newPosition = ccpAdd(_hero.position, ccpSub(curPoint, prePoint));
    
     
    
    // 4.拖動過程中,邊界檢測,不能出屏幕
    CGFloat _heroWidth = _hero.contentSize.width;
    CGFloat _heroHeight = _hero.contentSize.height;
    if (newPosition.x <  _heroWidth*0.5) {
        return;
    } else if(newPosition.x > self.contentSize.width - _heroWidth*0.5){
        return;
    }else if (newPosition.y < 0){
        return;
    }else if(newPosition.y > self.contentSize.height - _heroHeight){
        return;
    }
    _hero.position = newPosition;
}
@end


子彈Pellet

//
//  Pellet.h
//  31_cocos2D入門
//
//  Created by beyond on 14-9-28.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "CCSprite.h"

typedef enum {
    // 小子彈
    kPelletTypeSmall,
    // 大子彈
    kPelletTypeBig
}PelletType;

@interface Pellet : CCSprite
// 子彈類型
@property (nonatomic,assign) PelletType type;
// 子彈速度 (Y方向,和X方向)
@property (nonatomic, assign) CGPoint velocity;

// 發射 emit,參數:射出的點  射出的速度 
- (void)emitFrom:(CGPoint)from velocity:(CGPoint)velocity;
// 消失/隱藏
- (void)dismiss;


@end


//
//  Pellet.m
//  31_cocos2D入門
//
//  Created by beyond on 14-9-28.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "Pellet.h"

// 精靈幀 用到
#import "cocos2d.h"
// 音效
//#import "SimpleAudioEngine.h"
#import "OALSimpleAudio.h"

@implementation Pellet

#pragma mark - 父類方法

-(id)init
{
    if (self=[super init]) {
        // 子彈創建時,默認隱藏,只有當調用發射emit方法時,才顯示
        self.visible = NO;
    }
    return self;
}
#pragma mark - 攔截setter
- (void)setType:(PelletType)type
{
    _type = type;
    
    // 更換子彈精靈的 圖片
    NSString *imgName = _type == kPelletTypeSmall ? @"bullet1.png" : @"bullet2.png";
    CCSpriteFrame *frame = [CCSpriteFrame frameWithImageNamed:imgName];
    [self setSpriteFrame:frame];
}

#pragma mark - 供外界調用
// 發射 emit,參數:射出的點  射出的速度
- (void)emitFrom:(CGPoint)from velocity:(CGPoint)velocity{
    self.visible = YES;
    
    // 設置位置
    self.position = from;
    
    // 設置速度
    self.velocity = velocity;
    // 音效播放
    //    [[SimpleAudioEngine sharedEngine] playEffect:@"Pellet.mp3"];
    [[OALSimpleAudio sharedInstance]playEffect:@"bullet.mp3"];
}
// 消失/隱藏
- (void)dismiss
{
    self.visible = NO;
    
    [self unscheduleAllSelectors];
}


#pragma mark - 時鐘方法(飛行)
- (void)update:(CCTime)delta
{
    // 當子彈消失後,不再更新position...
    if (!self.visible) {
        return;
    }
    // deltaTime 時間內,移動(飛行)一段距離
    // 路程s = 速度v * 時間t
    CGPoint s = ccpMult(self.velocity, delta);
    self.position = ccpAdd(self.position, s);
}
@end


英雄Hero

//
//  Hero.h
//  31_cocos2D入門
//
//  Created by beyond on 14-9-27.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "CCSprite.h"

@interface Hero : CCSprite


// 簡單處理,英 雄與敵機 相撞,結果還是,game over
- (void)dieWithEnemyTogether;
@end


//
//  Hero.m
//  31_cocos2D入門
//
//  Created by beyond on 14-9-27.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//  主角,代表玩家的 英雄

#import "Hero.h"
#import "cocos2d.h"
#import "CCDirector.h"
#import "CCAnimation.h"
@implementation Hero



// 初始化玩家(的飛機)
- (id)init
{
    // 其實,磁盤裡沒有hero_fly_1.png 圖片,它是到大圖片的幀緩存中,根據key取出(裁剪)小圖片
    if (self = [super initWithImageNamed:@"hero_fly_1.png"]) {
        // 1.初始化位置,底部,中間
        self.anchorPoint = ccp(0.5, 0);
        // 從導演那兒拿到viewSize就是屏幕的size
        CGSize fullScreenSize = [[CCDirector sharedDirector] viewSize];
        self.position = ccp(fullScreenSize.width * 0.5, 0);
        
        // 2.創建 幀動畫 需要的兩個精靈幀
        CCSpriteFrameCache *cache = [CCSpriteFrameCache sharedSpriteFrameCache];
        CCSpriteFrame *frame1 = [cache spriteFrameByName:@"hero_fly_1.png"];
        CCSpriteFrame *frame2 = [cache spriteFrameByName:@"hero_fly_2.png"];
        
        NSArray *spriteFramesArr = @[frame1, frame2] ;

        
        // 3.為精靈添加動畫
        CCAnimation *animation = [CCAnimation animationWithSpriteFrames:spriteFramesArr delay:0.1];
        CCActionAnimate *animate = [CCActionAnimate actionWithAnimation:animation];
        // 4.播放幀動畫
        [self runAction:[CCActionRepeatForever actionWithAction:animate]];
    }
    return self;
}
// 簡單處理,英 雄與敵機 相撞,結果還是,game over
- (void)dieWithEnemyTogether
{
    // 停止之前的幀動畫
    [self stopAllActions];
    
    // 直接播放 爆炸 幀動畫
    NSMutableArray *frames = [NSMutableArray array];
    
    for (int i = 1; i<=4; i++) {
        NSString *name = [NSString stringWithFormat:@"hero_blowup_%d.png", i];
        CCSpriteFrame *f = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:name];
        [frames addObject:f];
    }
    
    CCAnimation *animation = [CCAnimation animationWithSpriteFrames:frames delay:0.1];
    [self runAction:[CCActionAnimate actionWithAnimation:animation]];
}
@end


敵機Enemy(有待發散)

//
//  Enemy.h
//  31_cocos2D入門
//
//  Created by beyond on 14-9-28.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "CCSprite.h"
//對應plist文件中 5種圖片
typedef enum {
    kEnemyType_1 = 1,
    kEnemyType_2 = 2,
    kEnemyType_3 = 3,
    kEnemyType_4 = 4,
    kEnemyType_5 = 5
} EnemyType;

@interface Enemy : CCSprite

@property (nonatomic, assign) EnemyType type;
// 出現在游戲中,出場,加入戰斗
- (void)attendTheBattle;
- (void)hide;
// 被擊中
- (void)gotHit;
@end


//
//  Enemy.m
//  31_cocos2D入門
//
//  Created by beyond on 14-9-28.
//  Copyright (c) 2014年 com.beyond. All rights reserved.
//

#import "Enemy.h"
#import "cocos2d.h"
#import "OALSimpleAudio.h"
#import "CCAnimation.h"
#import "CCDirector.h"

@interface Enemy()
{
    // 最大的生命值
    int _maxHp;
    // 生命值
    int _hp;
}
@end

@implementation Enemy


#pragma mark - 父類方法

-(id)init
{
    if (self=[super init]) {
        // 敵機創建時,默認隱藏,只有當調用出場,參加戰斗 時,才顯示
        self.visible = NO;
    }
    return self;
}


#pragma mark - 攔截setter方法
- (void)setType:(EnemyType)type
{
    _type = type;
    
    // 根據 敵人類型,設置 敵人顯示的圖片
    [self setEnemyImage];
    
    // 根據 敵人類型,設置 敵人最大生命值
    switch (type) {
        case kEnemyType_1:
            _maxHp = 1;
            break;
        case kEnemyType_2:
            _maxHp = 2;
            break;
        case kEnemyType_3:
            _maxHp = 3;
            break;
        case kEnemyType_4:
            _maxHp = 4;
            break;
        case kEnemyType_5:
            _maxHp = 5;
            break;
        
        default:
            break;
    }
}

#pragma mark - 時鐘方法
- (void)update:(CCTime)delta
{
    // 同其他的子彈、英雄一樣,只有在顯示時,才需要更新位置
    // 當敵人處於不可見時,說明被打死了,或逃出屏幕了,因此無需更新其位置
    if (!self.visible) {
        return;
    }
    // 不斷調整敵人的位置 (速度 可以和最大生命值一樣,設置不同的...)
    self.position = ccpAdd(self.position, ccp( 0, -100 * delta));
}
#pragma mark - 供外部調用
// 出現在游戲中,出場,加入戰斗
- (void)attendTheBattle
{
    // 出場時,滿血
    _hp = _maxHp;
    // 出場時,顯示
    self.visible = YES;
    // 出場時,位置,從屏幕頂部俯沖下來
    self.anchorPoint = ccp(0.5, 0);
    
    CGSize winSize = [CCDirector sharedDirector].viewSize;
    // 重要~~~之所以要減一,是因為...出場時,要讓它一只腳 踏進屏幕,與屏幕窗口的rect有交集
    self.position = ccp(winSize.width * CCRANDOM_0_1(), winSize.height - 1);
    // 邊界檢測
    
}
// 被擊中
- (void)gotHit
{
    _hp--;
    
    if (_hp == 0) {
        // 1.播放對應的被打中時 的音效
        [self playHitSound];
        // 2.播放對應的被爆炸動畫
        [self playExplodeAnimation];
        
    }
}
// 消失
- (void)hide
{
    self.visible = NO;
    
    [self unscheduleAllSelectors];
}

#pragma mark - 抽取方法
// 根據 敵人類型,設置 敵人顯示的圖片
- (void)setEnemyImage
{
    // 根據 敵人類型,設置 其圖片
    NSString *name = [NSString stringWithFormat:@"enemy%d_fly_1.png", _type];
    // 從精靈幀緩存中,取出精靈幀,從而設置到精靈身上,顯示
    CCSpriteFrame *frame = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:name];
    [self setSpriteFrame:frame];
}

// 播放對應的被打中時 的音效
- (void)playHitSound
{
   [[OALSimpleAudio sharedInstance] playEffect:[NSString stringWithFormat:@"enemy%d_down.mp3", _type]];
}
// 播放爆炸動畫,爆炸完,隱藏,最後重新設置顯示圖片,為參加下一次戰斗作准備
- (void)playExplodeAnimation
{
    NSMutableArray *frames = [NSMutableArray array];
    // 這個爆炸效果的 4 應該動態變化 ....
    for (int i = 1; i<=4; i++) {
        NSString *name = [NSString stringWithFormat:@"enemy1_blowup_%d.png", i];
        CCSpriteFrame *f = [[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:name];
        [frames addObject:f];
    }
    // 名詞,動畫
    CCAnimation *animation = [CCAnimation animationWithSpriteFrames:frames delay:0.1];
    // 動作_1 爆炸
    CCActionAnimate *explosion = [CCActionAnimate actionWithAnimation:animation];
    // 動作_2 不可見
    CCActionHide *hide = [CCActionHide action];
    // 動作_3 因為爆炸後,精靈的顯示圖片變了,所以要重新設置回來,以便下一次 參加戰斗
    CCActionCallFunc *func = [CCActionCallFunc actionWithTarget:self selector:@selector(setEnemyImage)];
    // 動作_4 用序列包裝
    CCActionSequence *sequence = [CCActionSequence actions:explosion,hide,func, nil];
    // 執行動作
    [self runAction:sequence];
}
@end



















  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved