iOS_31_cocos2d_微信飞机

来源:互联网 发布:淘宝店铺怎样布局 编辑:程序博客网 时间:2024/04/27 15:26
最终效果图:


纹理素材



场景

////  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<kPelletMaxCount; i++) {        // 默认 就是先隐藏的        Pellet *b = [Pellet node];        // 类型为:大子弹        b.type = kPelletTypeBig;        // 添加到数组中        [_pelletArr addObject:b];        // 添加到spriteBatchNode        [_batch addChild:b];    }     }#pragma mark 5.初始化敌机缓存// 初始化指定数量的敌机 ,并添加到batchNode中,统一管理,在时钟方法里,安排敌机出场- (void)setupEnemyArr{    // 1.初始化 敌机缓存    _enemyArr = [[NSMutableArray alloc] init];        for (int i = 0; i<kEnemyMaxCount; i++) {        // 默认 就是先隐藏的        Enemy *e = [Enemy node];        // 类型为:敌机_1        e.type = kEnemyType_1;        // 添加到 敌机数组中        [_enemyArr addObject:e];        // 添加到spriteBatchNode        [_batch addChild:e];    }     }#pragma mark - 游戏控制按钮点击- (void)gameControlBtnClicked{    // 如果 正在游戏,就暂停;反之继续游戏    if (_isGameRuning) {        // _isGameRuning = NO;        [self pauseGame];    } else {        // _isGameRuning = YES;        [self startGame];    }}#pragma mark 开始- (void)startGame{    // 1.首先置标记为 1    _isGameRuning = YES;    // 允许交互    self.userInteractionEnabled = YES;        // 2.播放背景音乐              [[OALSimpleAudio sharedInstance] preloadBg:@"game_music.mp3"];    [[OALSimpleAudio sharedInstance] playBgWithLoop:YES];//    [[OALSimpleAudio sharedInstance]playBg:@"game_music.mp3" loop:YES];    // 3.初始化 子弹两次出现 之间需要的总的累计间隔时间,如 0.3秒    // 这样一设置之后,game一开始就有子弹射出去了    _pelletTotalIntervalTime = kPelletTotalIntervalTime;    }#pragma mark 暂停- (void)pauseGame{    // 1.首先置标记为 0    _isGameRuning = NO;    // 停止交互(触摸移动)    self.userInteractionEnabled = NO;        // 2.停止所有消息调度    // 同时,也要让spriteBatchNode中管理的所有成员,执行 unscheduleAllSelectors 方法     [_batch.children makeObjectsPerformSelector:@selector(unscheduleAllSelectors)];        // 3.暂停背景音乐         [[OALSimpleAudio sharedInstance]stopBg];    [[OALSimpleAudio sharedInstance]stopAllEffects];}#pragma mark 结束- (void)endGame{    // 1.首先置标记为 0    _isGameRuning = NO;    self.userInteractionEnabled = NO;        // 2.停止所有消息调度         // 同时,也要让spriteBatchNode中管理的所有成员,执行 unscheduleAllSelectors 方法    [_batch.children makeObjectsPerformSelector:@selector(unscheduleAllSelectors)];        // 3.停止背景音乐               }#pragma mark - 时钟方法- (void)update:(CCTime)delta{    // 如果 游戏暂停中,则不更新任何状态    if (!_isGameRuning) {        return;    }        // 1.背景动画(始终向下滚动)    [self bgAnimation];        // 2.子弹动画(射出,运行轨迹)    [self pelletAnimation:delta];        // 3.敌机出场作战    [self enemyAnimation:delta];        // 4.碰撞\边界检测    [self collsionAndBoundaryCheck];}#pragma mark 1.滚动背景// 1.背景动画(始终向下滚动)- (void)bgAnimation{    // 2张背景图片,始终相差一张图片的高度(无论屏幕多高)    CGFloat height = _bg1.contentSize.height;    CGFloat bg1_Y = _bg1.position.y;    // 向下走    bg1_Y--;    // 临界点    // 向下走过程中,如果 1 超出屏幕了,将1 拉回去(2的y取决于1的y,因此,只要设置1的y)    if (bg1_Y <= -height) {        bg1_Y = 0;    }    _bg1.position = ccp(0, bg1_Y);    // 2始终在1的头顶上    _bg2.position = ccp(0, bg1_Y + height);}#pragma mark 2.子弹动画- (void)pelletAnimation:(CCTime)delta{    // 先累加 delta时间,到一定量时,再发射子弹    _pelletTotalIntervalTime += delta;    // 如果累计间隔时间达到了 预订的值:如0.3秒,可以发射子弹,位置是:英雄头顶    if (_pelletTotalIntervalTime >= 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<span style="font-family:Courier New;color:#393939;"><span style="font-size: 24px; line-height: 32px; background-color: rgb(245, 245, 245);"><strong></strong></span></span>


子弹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



















2 1
原创粉丝点击