来让我们开始第一个游戏的制作。
这个过程可能有点艰辛,但是只要坚持下来,第一个游戏往往能给我们带来巨大的收益(当然这个收益不是经济上的:-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 == kGameautorotationUIVIEwControllerreturn ( 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对象。
首先在.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 swallows@R_419_5033@: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.25static 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)cc@R_419_5033@Ended:(NSSet *)@R_419_5033@ 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-蜘蛛人源码
回见。
总结以上是内存溢出为你收集整理的【吼吼睡cocos2d学习笔记】第四章 - 第一个游戏全部内容,希望文章能够帮你解决【吼吼睡cocos2d学习笔记】第四章 - 第一个游戏所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)