导航

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

Posted on 2011-12-12 15:06  吼吼睡  阅读(2467)  评论(1编辑  收藏  举报

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

这个过程可能有点艰辛,但是只要坚持下来,第一个游戏往往能给我们带来巨大的收益(当然这个收益不是经济上的:-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-蜘蛛人源码

回见。