【吼吼睡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 == 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对象。
做完这些以后我们来实现主场景类: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-蜘蛛人源码
回见。
转载于:https://www.cnblogs.com/pengyingh/articles/2393191.html
【吼吼睡cocos2d学习笔记】第四章 - 第一个游戏相关推荐
- cocos2d学习笔记第四章 粒子效果及座标系
请先保证fire.png文件在工程中存在, 因为cocos2D的粒子系统需要使用,否则颜色无变化,只会显示黑方框. 1. 使用自带的粒子效果来实现指弹打中敌人后的喷血效果 CCParticleSyst ...
- 《Go语言圣经》学习笔记 第四章 复合数据类型
<Go语言圣经>学习笔记 第四章 复合数据类型 目录 数组 Slice Map 结构体 JSON 文本和HTML模板 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. ...
- 计算机网络(第7版)谢希仁著 学习笔记 第四章网络层
计算机网络(第7版)谢希仁著 学习笔记 第四章网络层 第四章 网络层 4.3划分子网和构造超网 p134 4.3.1划分子网 4.3.2使用子网时分组的转发 4.3.3无分类编址CIDR(构建超网) ...
- Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25
Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25 目录 Rule20 接口优于抽象类 Rule21 为后代设计接口 Rule22 接口只用于定义类型 ...
- 机器人导论(第四版)学习笔记——第四章
机器人导论(第四版)学习笔记--第四章 4.1 引言 4.2 解的存在性 4.3 当n<6时操作臂子空间的描述 4.4 代数解法和几何解法 4.5 简化成多项式的代数解法 4.6 三轴相交的Pi ...
- 高等数值计算方法学习笔记第4章第一部分【数值积分(数值微分)】
高等数值计算方法学习笔记第4章第一部分[数值积分(数值微分)] 一.数值积分概论 1.数值求积的基本思想(牛-莱公式找不到原函数,用矩形近似) 2.代数精度的概念 1.上述四个公式的代数精度(梯形,左 ...
- 线性代数学习笔记——第四章学习指南——n维向量空间
一.学习内容及要求 1. 内容: §4.1. n维向量空间的概念 线性代数学习笔记--第四十讲--n维向量空间的概念 线性代数学习笔记--第四十一讲--n维向量空间的子空间 §4.2. 向量组的线性相 ...
- Lan Goodfellow 《DEEP LEARNING》学习笔记 --第四章
https://app.yinxiang.com/shard/s64/nl/22173113/a89ab8f8-3937-419c-8b81-cc913abaa35a/ 为了方便起见,我用的可手写的a ...
- python实验题第四章_「Python」2020.03.16学习笔记 | 第四章列表、元组、字典-习题(11-13)...
学习测试开发的Day74,真棒! 学习时间为1H 第四章列表.元组.字典-习题(11-13) 11.求两个集合的交集和并集 代码 list1=[1,2,3,4] list2=[2,3,5,5] def ...
最新文章
- 中间件事务码R3AC1里Block Size的含义
- 虚拟机玩转缓存服务器,Nginx服务器中浏览器本地缓存和虚拟机的相关设置
- php概率计算_php 抽奖概率算法
- 算法设计与分析(第三周)递归实现全排列问题
- DDS发生器的verilog实现(三)
- 我的世界java版和基岩版对比_基岩版Beta1.11.0.1发布
- RAID阵列基础知识
- 快速建站-html基础-0223
- 基于JAVA+SpringMVC+Mybatis+MYSQL的实验室设备管理系统
- 普通人,怎么改变命运?
- linux命令学习——tar
- [译] What is some general advice for a new PhD student?
- c语言贪吃蛇毕业论文,毕业论文c语言贪吃蛇
- android qq 登录 qq号,手机QQ异常登录怎么办 QQ帐号无法登录解决办法
- 服务器软件firmware的作用(BIOS、BMC、PSOC、CPLD)
- jdk 7 下载地址(全新)
- Java集成Outlook邮件操作
- 用python扑克随机发牌_Python小应用之发扑克牌
- EtherCAT总线介绍及从站硬件设计
- 插画版 Kubernetes 指南
热门文章
- 计算机网络的资源共享功能包,计算机网络的资源共享功能包括
- 网贷大数据什么时候会好_如果人类把地球钻穿了,会发生什么?大数据分析告诉你多可怕...
- mysql外部排序_深入浅出MySQL优先队列(你一定会踩到的order by limit 问题)
- 星光 SaaS 伙伴甄云科技:如何构建更适合快成长企业的数字化采购管理平台?
- sql中in与php数组,格式化SQL“IN”子句的PHP数组
- 新颖的c语言题目,新颖版c语言经典习题100例(全面面)
- mysql 云无忧ps教程_华为云数据库MySQL一键开通读写分离,无忧应对企业业务高峰情景...
- 主动断开socket链接_TCP连接与断开详解(socket通信)
- mysql多客户端数据不同步_一种多终端设备上的数据同步方法
- python keyerror_盘点Python 初学者最容易犯的10大错误!你中招了吗?