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

这个过程可能有点艰辛,但是只要坚持下来,第一个游戏往往能给我们带来巨大的收益(当然这个收益不是经济上的:-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学习笔记】第四章 - 第一个游戏相关推荐

  1. cocos2d学习笔记第四章 粒子效果及座标系

    请先保证fire.png文件在工程中存在, 因为cocos2D的粒子系统需要使用,否则颜色无变化,只会显示黑方框. 1. 使用自带的粒子效果来实现指弹打中敌人后的喷血效果 CCParticleSyst ...

  2. 《Go语言圣经》学习笔记 第四章 复合数据类型

    <Go语言圣经>学习笔记 第四章 复合数据类型 目录 数组 Slice Map 结构体 JSON 文本和HTML模板 注:学习<Go语言圣经>笔记,PDF点击下载,建议看书. ...

  3. 计算机网络(第7版)谢希仁著 学习笔记 第四章网络层

    计算机网络(第7版)谢希仁著 学习笔记 第四章网络层 第四章 网络层 4.3划分子网和构造超网 p134 4.3.1划分子网 4.3.2使用子网时分组的转发 4.3.3无分类编址CIDR(构建超网) ...

  4. Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25

    Effective Java(第三版) 学习笔记 - 第四章 类和接口 Rule20~Rule25 目录 Rule20 接口优于抽象类 Rule21 为后代设计接口 Rule22 接口只用于定义类型 ...

  5. 机器人导论(第四版)学习笔记——第四章

    机器人导论(第四版)学习笔记--第四章 4.1 引言 4.2 解的存在性 4.3 当n<6时操作臂子空间的描述 4.4 代数解法和几何解法 4.5 简化成多项式的代数解法 4.6 三轴相交的Pi ...

  6. 高等数值计算方法学习笔记第4章第一部分【数值积分(数值微分)】

    高等数值计算方法学习笔记第4章第一部分[数值积分(数值微分)] 一.数值积分概论 1.数值求积的基本思想(牛-莱公式找不到原函数,用矩形近似) 2.代数精度的概念 1.上述四个公式的代数精度(梯形,左 ...

  7. 线性代数学习笔记——第四章学习指南——n维向量空间

    一.学习内容及要求 1. 内容: §4.1. n维向量空间的概念 线性代数学习笔记--第四十讲--n维向量空间的概念 线性代数学习笔记--第四十一讲--n维向量空间的子空间 §4.2. 向量组的线性相 ...

  8. Lan Goodfellow 《DEEP LEARNING》学习笔记 --第四章

    https://app.yinxiang.com/shard/s64/nl/22173113/a89ab8f8-3937-419c-8b81-cc913abaa35a/ 为了方便起见,我用的可手写的a ...

  9. python实验题第四章_「Python」2020.03.16学习笔记 | 第四章列表、元组、字典-习题(11-13)...

    学习测试开发的Day74,真棒! 学习时间为1H 第四章列表.元组.字典-习题(11-13) 11.求两个集合的交集和并集 代码 list1=[1,2,3,4] list2=[2,3,5,5] def ...

最新文章

  1. 中间件事务码R3AC1里Block Size的含义
  2. 虚拟机玩转缓存服务器,Nginx服务器中浏览器本地缓存和虚拟机的相关设置
  3. php概率计算_php 抽奖概率算法
  4. 算法设计与分析(第三周)递归实现全排列问题
  5. DDS发生器的verilog实现(三)
  6. 我的世界java版和基岩版对比_基岩版Beta1.11.0.1发布
  7. RAID阵列基础知识
  8. 快速建站-html基础-0223
  9. 基于JAVA+SpringMVC+Mybatis+MYSQL的实验室设备管理系统
  10. 普通人,怎么改变命运?
  11. linux命令学习——tar
  12. [译] What is some general advice for a new PhD student?
  13. c语言贪吃蛇毕业论文,毕业论文c语言贪吃蛇
  14. android qq 登录 qq号,手机QQ异常登录怎么办 QQ帐号无法登录解决办法
  15. 服务器软件firmware的作用(BIOS、BMC、PSOC、CPLD)
  16. jdk 7 下载地址(全新)
  17. Java集成Outlook邮件操作
  18. 用python扑克随机发牌_Python小应用之发扑克牌
  19. EtherCAT总线介绍及从站硬件设计
  20. 插画版 Kubernetes 指南

热门文章

  1. 计算机网络的资源共享功能包,计算机网络的资源共享功能包括
  2. 网贷大数据什么时候会好_如果人类把地球钻穿了,会发生什么?大数据分析告诉你多可怕...
  3. mysql外部排序_深入浅出MySQL优先队列(你一定会踩到的order by limit 问题)
  4. 星光 SaaS 伙伴甄云科技:如何构建更适合快成长企业的数字化采购管理平台?
  5. sql中in与php数组,格式化SQL“IN”子句的PHP数组
  6. 新颖的c语言题目,新颖版c语言经典习题100例(全面面)
  7. mysql 云无忧ps教程_华为云数据库MySQL一键开通读写分离,无忧应对企业业务高峰情景...
  8. 主动断开socket链接_TCP连接与断开详解(socket通信)
  9. mysql多客户端数据不同步_一种多终端设备上的数据同步方法
  10. python keyerror_盘点Python 初学者最容易犯的10大错误!你中招了吗?