紋理素材
場景
// // 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