【吼吼睡cocos2d学习笔记】第四章 - 第一个游戏

来让我们开始第一个游戏的制作。

这个过程可能有点艰辛,但是只要坚持下来,第一个游戏往往能给我们带来巨大的收益(当然这个收益不是经济上的:-P)

先上截图:


iPad中:


游戏构思

角色

在屏幕的上方,有一定数量的敌人(蜘蛛),屏幕下方有一只玩家控制的熊猫。

游戏流程

每间隔一段时间,会有一只蜘蛛爬下来袭击熊猫,熊猫通过移动来躲避攻击。随着游戏的进行,蜘蛛下降的速度会越来越快,出动的频率会越来越高。

胜负判定

熊猫躲避过一定数目的蜘蛛以后获胜,在此之前玩家用完所有生命则失败。

游戏展示动画,其实是有音效的,可能屏幕录像的软件不能捕捉来自模拟器的声音:展示动画

分析

我们按照事务流的方式来对整个游戏进行简单分析:

1.启动游戏,加载主页面。本示例不做菜单,不做配置,直接进入游戏场景。

2.将游戏置为READY状态;初始化各种数据;根据屏幕的宽度计算蜘蛛的个数,初始化蜘蛛精灵;初始化熊猫精灵

3.当玩家触摸屏幕以后,游戏开始,游戏状态设置为PLAYING,启动以下计时器:

3a.播放蜘蛛帧动画的计时器

3b.搜索下一个出动的蜘蛛计时器

3c.碰撞检测的计时器

4.玩家用手指控制熊猫在屏幕下方移动,这里要注意的是,接收触摸事件的是熊猫,如果触摸点不在熊猫上,它是不能移动的。因此需要给熊猫精灵添加一个targetedTouchDelegate。同时要防止熊猫划出屏幕边界。

5.定时检测下一个出动的蜘蛛,找到以后,让蜘蛛下移的屏幕低部,然后复位,如果熊猫躲避过来此次攻击,加分。当出动的蜘蛛次数超过一定量的时候(本游戏中是8次),加快游戏速度,加快蜘蛛出动频率。同时判断是否已经满足胜利条件。

6.当碰撞检测计时器检测到碰撞后,停止出动蜘蛛计时器、碰撞检测计时器、动画播放计时器,生命减一,判断是否还有剩余生命。如果没有,Game Over,游戏状态设置为END;如果还有生命,游戏状态设置为DEAD。

7.当玩家触摸屏幕的时候:

7.a.如果游戏状态是READY,开始游戏。

7.b 如果游戏状态是DEAD,复位蜘蛛和熊猫,启动各个计时器。

7.c 如果游戏状态为其他状态,无视。

8.对熊猫精灵的事件分析:

当熊猫精灵接收到触摸事件以后,判断是否命中到了精灵范围内,如果是,吃掉该事件,否则让该事件继续下发给其他对象。

9.注意,为了无缝的向iPad设备上移植,需要注意:计量避免出现假设性代码,所有的尺寸都根据屏幕尺寸计算。

开工

XCode->New Project->IOS->cocos2d-name it->finish!

删掉默认的helloWorld层,按照下图,创建Group:


Sprites:盛放精灵类

Layers:盛放所有层

Scenes:盛放所有的场景

RootViewController.m

本游戏适合在竖屏模式下进行,因此需要做以下修改:

#elif GAME_AUTOROTATION == kGameAutorotationUIViewController
return ( UIInterfaceOrientationIsLandscape( interfaceOrientation ) );
修改为

#elif GAME_AUTOROTATION == kGameAutorotationUIViewController		
return ( UIInterfaceOrientationIsLandscape( interfaceOrientation ) );


AppDelegate.m

因为删除了HelloWorld层,现在需要启动我们自己添加的GameScene场景,因此需要修改AppDelegate.m的相关代码:

找到applicationDidFinishLaunching方法中[CCDirector sharedDirector] runWithScene的代码,此代码的作用是让【导演】运行第一个游戏场景,将之修改成:

[[CCDirector sharedDirector] runWithScene: [GameScene scene]];

GameScene使我们自己设计的场景类,在Scenes文件组中,scene是该类的初始化方法,负责返回一个GameScene对象。


做完这些以后我们来实现主场景类: GameScene

首先在.h文件中添加静态scene方法的声明:

+(CCScene *)scene;

.m文件中实现该方法,同时加上对资源的释放:

-(void)dealloc
{
    [super dealloc];
}
+(CCScene *)scene
{
    CCScene *sc = [CCScene node];
    [sc addChild:[GameLayer node]];
    return  sc;
}

scene方法中构造了一个CCScene对象,并将GameLayer层作为子节点加入其中。

其实在IOS开发中,scene对象中的代码量往往非常少,代码大部分出现在层和精灵中。


在看关键的GameLayer以前,我们先来看一下熊猫精灵(PandaSprite)类

这个类继承自CCSprite,同时实现了CCTargetedTouchDelegate协议。这是.m中的代码

//
//  GameLayer.h
//  CH04
//
//  Created by 李庆辉 on 11-12-8.
//  QQ:66927785
//  Blog:http://blog.csdn.net/redparty
//  Copyright 2011年 __MS__. All rights reserved.
//

#import "PandaSprite.h"


@implementation PandaSprite
@synthesize curLayer;



//释放delegate
-(void)onExit
{
    [[CCTouchDispatcher sharedDispatcher] removeDelegate:self];
    [super onExit];
}


//当被node的时候,触发该事件,注册targetedDelegate
-(void)onEnter
{
    [[CCTouchDispatcher sharedDispatcher] addTargetedDelegate:self priority:0 swallowsTouches:YES];
    [super onEnter];
}

//获得自身的rect,用来进行命中判定
-(CGRect)rect
{
    return CGRectMake(-rect_.size.width * 0.5, -rect_.size.height * 0.5, rect_.size.width, rect_.size.height);
}

//当touch开始的时候,判定是否命中了自身,如果是,吃掉该事件,反之忽略该事件
-(BOOL)ccTouchBegan:(UITouch *)touch withEvent:(UIEvent *)event
{
    
    if (CGRectContainsPoint([self rect], [self convertTouchToNodeSpaceAR:touch])) {
        return YES;
    }
    return NO;
}


//根据玩家的触摸,变换主角的位置。
-(void)ccTouchMoved:(UITouch *)touch withEvent:(UIEvent *)event
{
    
    //获得GameLayer中的gameStatus的值,如果不是PLAYING,则忽略当前触摸。
    if ([curLayer getGameStatus] != @"PLAYING") {
        return;
    }
    CGSize sizeOfWin = [[CCDirector sharedDirector] winSize];
    
    //获得自己的尺寸的一半,用来对左右两边缘的位置进行校正
    CGSize halfOfMyself;
    halfOfMyself = CGSizeMake([self contentSize].width * 0.5, [self contentSize].height  * 0.5);
    //根据自身的大小确定自己在x轴方向上的最小值和最大值
    CGFloat minX = halfOfMyself.width;
    CGFloat maxX = sizeOfWin.width -  halfOfMyself.width;
    
    CGPoint posOfTouch = [touch locationInView:touch.view];
    
    CGPoint posForGL = [[CCDirector sharedDirector] convertToGL:posOfTouch];
    
    //对越界情况进行校正
    if (posForGL.x < minX) {
        posForGL.x = minX;
    }
    if (posForGL.x > maxX) {
        posForGL.x = maxX;
    }
    
    //坐标系转换
    posForGL.y = [self contentSize].height * 0.5;
    self.position = posForGL;
}
@end

代码中已经注视的非常清楚了,这里不再赘述。需要说明的是,在CCTouchMoved方法中,有如下代码:

//获得GameLayer中的gameStatus的值,如果不是PLAYING,则忽略当前触摸。
    if ([curLayer getGameStatus] != @"PLAYING") {
        return;
    }

curLayer是在.h中声明的id类型的对象:

//
//  GameLayer.h
//  CH04
//
//  Created by 李庆辉 on 11-12-8.
//  QQ:66927785
//  Blog:http://blog.csdn.net/redparty
//  Copyright 2011年 __MS__. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "cocos2d.h"

@interface PandaSprite : CCSprite<CCTargetedTouchDelegate> 
{
    id curLayer;
}
@property (nonatomic,retain)id curLayer;
@end

id是Objective-C中所有节点的父类,相当于c#中的Object类。该对象将来会传入一个GameLayer的对象。之所以这样做是因为在熊猫精灵并非在任何时候都被允许移动的,只有在游戏状态为PLAYING的时候才响应该事件。具体可以参看GameLayer.m中的getGameStatus方法。这是一种在精灵和层之间传递数据的方式。


好,现在看是来看重量级的GameLayer类

先看.h文件

//
//  GameLayer.h
//  CH04
//
//  Created by 李庆辉 on 11-12-8.
//  QQ:66927785
//  Blog:http://blog.csdn.net/redparty
//  Copyright 2011年 __MS__. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "PandaSprite.h"
#import "SimpleAudioEngine.h"

@interface GameLayer : CCLayer {
    //窗口尺寸
    CGSize sizeOfWin ;
    //蜘蛛的尺寸
    CGSize sizeOfSpider;
    //熊猫的尺寸
    CGSize sizeOfPanda;
    //盛放蜘蛛精灵的数组
    CCArray *spiders;    
    //盛放熊猫生命的数组
    CCArray *LivesPandas;
    //主角精灵
    PandaSprite *panda;
    //蜘蛛的个数
    int spiderNumber;
    //控制游戏速度的一个因子,会被用在计算蜘蛛的下降速度和下降频率上
    CGFloat speed;
    //当前的游戏状态,分为:READY,PLAYING,DEAD,END,OVER
    NSString *gameStatus;
    //显示分数的label
    CCLabelTTF *lblScoreShow;
    //显示游戏信息的label
    CCLabelTTF *lblInfo;
    //动画播放分数的label
    CCLabelBMFont *lblScoreAnimate;
    //没有什么具体含义,仅仅被用来控制分数计算的频率
    int numSpidersMoved;
    
    int livesCount;
    
    //游戏得分
    int score;
    
}
//播放蜘蛛动画
-(void)playSpiderAnimate;
//重置蜘蛛们的位置
-(void)resetSpider;
//寻找下一个行动的蜘蛛
-(void)checkSpider:(ccTime)dt;
//将checkSpider寻找到的蜘蛛下坠并复位
-(void)downSpider:(CCSprite *)spider;
//作为downSpider中action的回调函数,负责让到达屏幕底部的蜘蛛复位
-(void)makeSpiderBack:(CCSprite *)spider;
//碰撞检测
-(void)checkCollision;
//停止所有发生在蜘蛛和主角上的动作。
-(void)stopAllAction;
//返回gameStatus的值,这个值会在PandaSprite中用到
-(NSString *)getGameStatus;
//该方法根据speed来改变蜘蛛出动的频率。
-(void)changeCheckTimeout;
//创建死亡label
-(void)createLables;
//创建蜘蛛数组
-(void)createSpiderArray;
//创建显示生命的熊猫
-(void)createLivesPandas;
//创建主角
-(void)createPanda;
//初始化游戏
-(void)initGame;
//用Action来显示实时分数
-(void)showAnimateScore;
//当胜利的时候
-(void)whenWin;
//当碰撞的时候
-(void)whenCollision;
//根据当前剩余的生命显示对应个数的熊猫
-(void)showLives;
//开始游戏相关的计时器
-(void)startSchedule;
//停止游戏相关的计时器
-(void)stopSchedule;
@end

有点多,但是每一行我的加上了注释,每个方法的实现都在.m中:

//
//  GameLayer.h
//  CH04
//
//  Created by 李庆辉 on 11-12-8.
//  QQ:66927785
//  Blog:http://blog.csdn.net/redparty
//  Copyright 2011年 __MS__. All rights reserved.
//

#import "GameLayer.h"


@implementation GameLayer

#define SPRITETAG 100
#define LABLE_TAG 150
#define SCORE_HEIGHT 30
#define  SCALE_SPIDER 0.5
#define SCALE_PANDA 0.8
#define FADE_SCORE 45
#define SPEED 2
#define DTSPEED 250
#define MAXLIVES 5
#define SCALE_LIVESPANDA 0.25

static int framIndex;

//释放层用到的非autoRelease资源
-(void)dealloc
{
    [super dealloc];
    [spiders release];
    spiders = nil;
}


-(id)init
{
    if (self = [super init]) {

        [self initGame];
   
    }
    return  self;
}
-(void)initGame
{
    //获得屏幕尺寸
    sizeOfWin = [[CCDirector sharedDirector] winSize];
    //创建label(分数、生命、死亡信息、win)
    [self  createLables];
    
    //创建蜘蛛数组
    [self createSpiderArray];
    
    //创建主角
    [self createPanda];
    
    //创建显示生命用的熊猫
    [self createLivesPandas];
    
    //重置蜘蛛位置
    [self resetSpider];
    //预加载音效文件,如果不予加载的话,第一次播放此音效的时候会卡至少一秒钟。
    [[SimpleAudioEngine sharedEngine] preloadEffect:@"bomb.caf"];
    numSpidersMoved = 1;
    score = 0;
    livesCount = MAXLIVES;
    framIndex = 1;
    speed = SPEED;
    gameStatus = @"READY";
    [self setIsTouchEnabled:YES];
}

-(void)createPanda
{
    //添加主角
    CCSpriteFrameCache *frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
    [frameCache addSpriteFramesWithFile:@"sprite.plist"];
    panda = [PandaSprite node];
    [panda setDisplayFrame:[frameCache spriteFrameByName:@"panda.png"]];
    
    sizeOfPanda = [panda contentSize];
    sizeOfPanda.width *= SCALE_PANDA;
    sizeOfPanda.height *= SCALE_PANDA;
    [self addChild:panda z:3];
    
    //将本层传入panda对象中,实现层和精灵的信息传递
    panda.curLayer = self;
}
-(void)createLivesPandas
{
    CCSpriteFrameCache *frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
    [frameCache addSpriteFramesWithFile:@"sprite.plist"];
    
    CCSprite *tmpPanda = [CCSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"zz1.png"]];
    
    //获得生命区熊猫的尺寸
    CGSize sizeOfLivesPanda = [tmpPanda contentSize];
    sizeOfLivesPanda.width *= SCALE_LIVESPANDA;
    sizeOfLivesPanda.height *= SCALE_LIVESPANDA;
    
    LivesPandas = [[CCArray alloc] initWithCapacity:MAXLIVES];
    for (int i = 0; i < MAXLIVES; i++) {
        CCSprite * tmpPanda = [CCSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"panda.png"]];
        [LivesPandas addObject:tmpPanda];
        tmpPanda.scale = SCALE_LIVESPANDA;
        tmpPanda.position = CGPointMake((i+1)*sizeOfLivesPanda.width, sizeOfWin.height - sizeOfLivesPanda.height - 5 );
        [self addChild:tmpPanda];
    }
}
-(void)createSpiderArray
{
    //创建蜘蛛精灵表的帧缓存,并加载蜘蛛精灵动作的plist文件
    CCSpriteFrameCache *frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
    [frameCache addSpriteFramesWithFile:@"sprite.plist"];
    
    //生成临时蜘蛛,获取缩放以后蜘蛛的尺寸。
    CCSprite* spider = [CCSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"zz1.png"]];
    spider.scale = SCALE_SPIDER;
    sizeOfSpider = [spider contentSize];
    sizeOfSpider.width *= SCALE_SPIDER;
    sizeOfSpider.height *= SCALE_SPIDER;
    
    //根据蜘蛛的尺寸计算可以放置的蜘蛛的个数,根据个数初始化蜘蛛数组
    spiderNumber = sizeOfWin.width/sizeOfSpider.width;
    spiders = [[CCArray alloc] initWithCapacity:spiderNumber];
    for (int i = 0; i < spiderNumber; i++) {
        CCSprite *tmpSpider = [CCSprite spriteWithSpriteFrame:[frameCache spriteFrameByName:@"zz1.png"]];
        [spiders addObject:tmpSpider];
        tmpSpider.scale = SCALE_SPIDER;
        [self addChild:tmpSpider z:0 tag:SPRITETAG + i];
    }
}
-(void)createLables
{
    //信息
    lblInfo = [CCLabelTTF labelWithString:@""  fontName:@"Arial" fontSize:22];
    lblInfo.position = CGPointMake(sizeOfWin.width * 0.5, sizeOfWin.height * 0.5);
    [self addChild:lblInfo z:100 tag:LABLE_TAG];
    [lblInfo setVisible:NO];
    [lblInfo setOpacity:125];
    
    //分数
    CCLabelTTF *lblScore = [CCLabelTTF labelWithString:@"分数:" fontName:@"Arial" fontSize:14];
    lblScore.anchorPoint = CGPointMake(1, 1);
    lblScore.position =  CGPointMake(sizeOfWin.width - 60 - [lblScore contentSize].width/2, sizeOfWin.height - 10);
    [self addChild:lblScore];
    
    lblScoreShow = [CCLabelTTF labelWithString:@"0000000" fontName:@"Arial" fontSize:14];
    lblScoreShow.anchorPoint = CGPointMake(1, 1);
    lblScoreShow.position =  CGPointMake(sizeOfWin.width - [lblScore contentSize].width/2,sizeOfWin.height - 10);
    [self addChild:lblScoreShow];
    
    //实时显示当前得分的标签,用到了BMFont,使用Hiero制作
    lblScoreAnimate = [CCLabelBMFont labelWithString:@"" fntFile:@"myfont.fnt"];
    lblScoreAnimate.scale = 0;
    [lblScoreAnimate setOpacity:FADE_SCORE];
    lblScoreAnimate.position = CGPointMake(sizeOfWin.width * 0.5, sizeOfWin.height * 0.5);
    [self addChild:lblScoreAnimate];
    
    //生命
}


-(void)resetSpider
{
    //将蜘蛛们复位
    CGSize halfSize = CGSizeMake(sizeOfSpider.width * 0.5, sizeOfSpider.height * 0.5);
    CGFloat leftMargin = (sizeOfWin.width - sizeOfSpider.width * spiderNumber) * 0.5;
    for (int i = 0; i < spiderNumber; i++) {
       CCSprite *spider = (CCSprite *)[self getChildByTag:SPRITETAG + i];
        spider.position = CGPointMake((i+1)*sizeOfSpider.width - halfSize.width+leftMargin , sizeOfWin.height -  halfSize.height - SCORE_HEIGHT);
        [spider stopAllActions];
    }
    
    //将熊猫复位
    panda.position = CGPointMake(sizeOfWin.width * 0.5, sizeOfPanda.height * 0.5);
}

-(void)playSpiderAnimate
{
    CCSpriteFrameCache *frameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
    [frameCache addSpriteFramesWithFile:@"sprite.plist"];
    if (++framIndex >2) {
        framIndex = 1;
    }
    for (int i = 0; i<spiderNumber; i++) {
        CCSprite *tmpspider = [spiders objectAtIndex:i];
        if ([tmpspider numberOfRunningActions] == 0) {
            //为了让蜘蛛的动画产生不一致,避免所有的蜘蛛播放相同的纹理,将i也加入了计算中,最终得到的是一个介于1-2的整数
            [tmpspider setDisplayFrame:[frameCache spriteFrameByName:[NSString stringWithFormat:@"zz%d.png",(framIndex + i)%2 +1]]];
        }
    }
    
}
-(void)changeCheckTimeout
{
    [self unschedule:@selector(checkSpider:)];
    [self schedule:@selector(checkSpider:) interval:0.25 * speed];
}

//寻找下一个出动的蜘蛛
-(void)checkSpider:(ccTime)dt
{
    for (int i = 0; i<20; i++) {
        int checkIndex = CCRANDOM_0_1() * spiderNumber;
        CCSprite *spider = [spiders objectAtIndex:checkIndex];
        //如果找到了一个本身没有动作的蜘蛛,说明该蜘蛛还没有出动,出动之。
        if ([spider numberOfRunningActions] == 0)  {
            
            //出动蜘蛛
            [self downSpider:spider];
            
            
            
            
            
            
            break;
        }
    }
}
-(void)whenWin
{
    [lblInfo setString:@"You Win!"];
    [lblInfo setVisible:YES];
    [self stopAllAction];
    [self unschedule:@selector(checkSpider:)];
    [self unschedule:@selector(checkCollision)];
    gameStatus = @"END";
}

//计算分数,用动画的方式现在在屏幕中间,同时累加到分数变量,显示在右上角。
-(void)showAnimateScore
{
    //根据当前speed计算当前得分,原则上是:速度越快,单位得分越高
    int scoreBySpeed = ((SPEED+0.1)-speed) * DTSPEED;
    score += scoreBySpeed;
    [lblScoreAnimate setString:[NSString stringWithFormat:@"%d",scoreBySpeed]];
    [lblScoreShow setString:[NSString stringWithFormat:@"%07d",score]];
    //播放动画前,将label透明度调大,尺寸缩小到0
    lblScoreAnimate.scale = 0;
    [lblScoreAnimate setOpacity:FADE_SCORE];
    //创建一个放大动作和一个隐出动作
    CCAction *acS = [CCScaleTo actionWithDuration:0.2 scale:3];
    CCAction *acE= [CCFadeTo actionWithDuration:0.2 opacity:0];
    
    //用CCSpawn的方式同步执行两个动作
    [lblScoreAnimate runAction:[CCSpawn actions:acS,acE, nil]];
}

//出动蜘蛛
-(void)downSpider:(CCSprite *)spider
{
    //蜘蛛移动的目标位置
    CGPoint targetPos = CGPointMake(spider.position.x, [spider contentSize].height * 0.5);
    
    CCAction *ac = [CCMoveTo actionWithDuration:speed position:targetPos];
    //当蜘蛛执行玩ac动作以后,回来执行callBack指向的回调函数:makeSpiderBack
    CCCallFuncN *callBack = [CCCallFuncN actionWithTarget:self selector:@selector(makeSpiderBack:) ];
    
    //用CCSequence的方式执行ac和callBack
    [spider runAction:[CCSequence actions:ac,callBack, nil]];
}

//回调函数,让蜘蛛复位
-(void)makeSpiderBack:(CCSprite *)spider
{
    CGPoint backPos = CGPointMake(spider.position.x, sizeOfWin.height - sizeOfSpider.height * 0.5 - SCORE_HEIGHT);
    CCAction *back = [CCMoveTo actionWithDuration:1 position:backPos];
    [spider runAction:back];
    
    //播放加分动画,加分
    [self showAnimateScore];
    
    //每有一只蜘蛛被躲避开,就加快游戏速度,同时进行获胜判定
    numSpidersMoved++;
    if (numSpidersMoved %5 == 0) {
        //在本游戏中,如果速度快到0.7,认为玩家获胜。
        if (speed < 0.7) {
            [self whenWin];
            return;
        }
        speed -= 0.02;
        [self changeCheckTimeout];
        numSpidersMoved = 1;
    }
    
}

//当用户点击屏幕的时候,根据不同的情景改变游戏状态。
-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    //如果当前是死亡状态,继续游戏
    if (gameStatus == @"DEAD") {
        [panda stopAllActions];
        [panda setVisible:YES];
        [lblInfo setVisible:NO];
        [self resetSpider];
        gameStatus = @"PLAYING";
        [self changeCheckTimeout];
        [self startSchedule];
    }
    
    //如果当前是READY状态,开始游戏
    if (gameStatus == @"READY") {
        gameStatus = @"PLAYING";
        [self changeCheckTimeout];
        [self startSchedule];
    }
}
//开始游戏相关的计时器
-(void)startSchedule
{
    //让蜘蛛动起来
    [self unschedule:@selector(playSpiderAnimate)];
    [self schedule:@selector(playSpiderAnimate) interval:0.4];
    
    //启动碰撞检测
    [self unschedule:@selector(checkCollision)];
    [self schedule:@selector(checkCollision) interval:0.02];
}

//停止游戏相关的计时器
-(void)stopSchedule
{
     [self unschedule:@selector(playSpiderAnimate)];
    [self unschedule:@selector(checkCollision)];
}
//碰撞检测
-(void)checkCollision
{
    //计算熊猫和蜘蛛的最大相距半径,大于此值认为发生了碰撞。
    float maxDistance = sizeOfSpider.width * 0.45 +sizeOfPanda.width * 0.45;
    
    //依次判定每一个蜘蛛是否与熊猫发生了碰撞
    for (int i = 0; i < spiderNumber; i++) {
        CCSprite *spider;
        spider = [spiders objectAtIndex:i];
        //忽略没有出动的蜘蛛
        if ([spider numberOfRunningActions] == 0) {
            continue;
        }
        //得到当前蜘蛛和熊猫的距离
        float actualDistance = ccpDistance(spider.position, panda.position);
        
        if (actualDistance < maxDistance) {
           
            [self whenCollision];
            break;
            
            
        }
    }
}

//当碰撞发生的时候,进行处理
-(void)whenCollision
{
    //播放音频
    [[SimpleAudioEngine sharedEngine] playEffect:@"bomb.caf"];
    
    [self unschedule:@selector(checkSpider:)];
    [self stopSchedule];
    [self stopAllAction];
    gameStatus = @"DEAD";
    
    
    
    //blink the spider
    CCAction *blink = [CCBlink actionWithDuration:0.5 blinks:3];
    [panda runAction:blink];
    livesCount--;
    [lblInfo setVisible:YES];
    if (livesCount == 0) {
        [lblInfo setString:@"GAME OVER!"];
        gameStatus = @"OVER";
        return;
    }
    [self showLives];
    [lblInfo setString:@"你挂了!点击屏幕重新来过!"];
    
}
-(void)showLives
{
    for (int i = livesCount; i<MAXLIVES; i++) {
        CCSprite *tmpSprite = [LivesPandas objectAtIndex:i];
        [tmpSprite setVisible:NO];
    }
}
//停止所有蜘蛛和主角的动作
-(void)stopAllAction
{
    for (int i = 0; i < spiderNumber; i++) {
        CCSprite *spider = [spiders objectAtIndex:i];
        [spider stopAllActions];
    }
    [panda stopAllActions];
}
//该方法用在向panda精灵中传递游戏状态,实现:只有在PLAYING的时候才可以移动主角。
-(NSString *)getGameStatus
{
    return gameStatus;
}
@end

我想注释已经足够清楚了,有序考虑到了向iPad平台的兼容,所以有大量的代码用来计算尺寸和位置。千万不要认为这是在浪费时间,记住一句话:

程序员应该尽量少写基于假设的代码

比如spider.positon = CGPointMake(160,32)。

你写这行代码的本意可能是想将熊猫精灵放在屏幕的底部的中间,听起来似乎不错,因为当前你做的是iphone的开发,熊猫的高度是64px。但是这都基于两个假设:

假设一:屏幕宽度是320px,显然并非所有的IOS设备都是这样。

假设二:熊猫高度是64px。

事实上,我们很容易在游戏进行到一定的程度以后,要添加新的需求,比如移植到iPad上,比如说你想增加一个关卡,这次主角是一个蚂蚁或者一只大象。那么这些基于假设的代码就会成为让你加班的原因。也很有可能会耽误你和女儿的周末晚餐⋯⋯

资源

本例中,用到了以下资源:

bomb.caf:主角死亡时候播放的音效。

sprite.plist & sprite.png:精灵贴图列表,使用Zwoptex文件制作,这个工具使用起来非常简单,大家可以google之。

myfont.fnt & myfont.png:自定义字体类表和图像,使用hiero制作。游戏开发必备。


说得再多,不如自己动手写一遍。

奉上源码:cocos2d-蜘蛛人源码

回见。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值