如何使用cocos2d制作一个太空射击游戏(转载)

来源:互联网 发布:火凤凰云计算基地 编辑:程序博客网 时间:2024/05/01 12:59



原文地址: http://www.raywenderlich.com/3611/how-to-make-a-space-shooter-iphone-game
程序截图:
(译)如何使用cocos2d制作一个太空射击游戏cocos2d
在这个教程里面,你将会学习到如何为iPhone开发一个太空射击游戏!
你可以使用加速计(重力感应)来控制飞船的移动,并且可以点击屏幕来发射激光武器。
如果你对于如何制作iphone游戏完全陌生的话,这个教程可以帮助你!你将会学习到,如何从头至尾构建一个完整的游戏,不需要任何的经验!
假如你对cocos2d编程完全陌生的话,那么你可能需要先学习一下相关的教程了。
这个教程对于中级开发者来说也非常好,因为它覆盖了一些比较高级的主题,比如视差滚动(parallax scrolling),预分配CCNode,加速计移动以及粒子系统的使用。
话不多说,直入主题!

安装cocos2d

为了制作这个游戏,你需要成为 iOS developer program的一员(这样的话,你的程序就能够安装到你的iPhone上面去,不过听说网上有人越狱也可以安装,知道的朋友麻烦给个链接,谢谢!)同时,需要安装Xcode和cocos2d框架。
如果你之前已经安装过cocos2d了,那接下来这部分就不要看了。(如果想使用新的cocos2d版本,只需要把之前安装的目录下面的模板文件全部删 除,再按照下面的指令重新安装即可)。如果你重来没有安装过cocos2d的话,那么只需要按照下面的指令序列,一步步地安装到你的mac上面就行了。
  • 首先下载Cocos2D .确定获得最新版本--作者写这篇文章的时候是1.0.0-rc2版本,目前是1.0.0-rc3版本。虽然不是稳定版本,但是,没关系,其实很稳定啦!:)
  • 双击下载下来的文件,并且解压缩到一个安全的位置。
  • 打开Terminal (Applications\Utilities\Terminal), 然后使用cd命令定位到刚刚解压缩的cocos2d文件夹下面去。然后运行./install-templates.sh来安装xcode模板,如下面所示:
$ cd Downloads $ cd cocos2d-iphone-1.0.0-rc2 $ ./install-templates.sh -f -u
如果一切顺利的话,你应该会看到终端里面一系列的输出语句:“ Installing xxx template”。
然后重新启动Xcode,祝贺你,您已成功安装cocos2d了!

Hello, Cocos2D!

让我们首先创建一个“Hello World”cocos2d工程。
打开Xcode,选择 File\New\New Project,然后选 iOS\cocos2d template,接下来点Next,并且把工程命名为SpaceGame,再点Next并选择一个文件夹作为你的工程的保存路径,最后点Create。
编译并运行工程,你将会看到一个“Hello World”出现在屏幕的正中间。
(译)如何使用cocos2d制作一个太空射击游戏cocos2d

添加相关资源文件

为了做这样一个iphone游戏,你将需要一些跟太空主题相关的图片资源和声音资源。
你可以直接下载我老婆制作的太空游戏资源。
因此,请直接下载吧,并且把它解压到你的硬盘的某个目录下面去。
一旦你解压完这些资源以后,把Backgrounds,Fonts,Particles,Sounds和Spritesheets文件夹拖到Resouces分组下面去。(基本上,除了Classes文件夹以外,其它所有的文件压都拖到Resource目录下面去)
确保 “Copy items into destination group’s folder (if needed)”被复选中,然后点击Finish。
当你做完这些事之后,你的工程的分组看起来会是下图所示的样子:
(译)如何使用cocos2d制作一个太空射击游戏cocos2d
如果你很好奇,你可以随便看看你刚刚向工程里面添加进去了一些什么东西。下面是完整的内容列表:
  • Backgrounds: 一些背景图片,你等下会使用它们来制作一个滚动背景。里面包含星系,太阳,和空间异常(它移动速度比较慢),还有一组空间尘埃图片(它们会出现在背景前面,而且会移动地稍微快一点)
  • Fonts: 使用 Glyph Designer制作的位图字体,我们将使用这些字体来在游戏中显示文字。
  • Particles: 使用 Particle Designer制作的一些特殊的粒子效果。 在这里,我们用来创建星星飞动的效果。
  • Sounds: 一些与太空相关的背景音乐和音效。使用 Garage Band 和 cxfr制作的。
  • Spritesheets: 一张格式为pvr.ccz的大图片,里面包含了游戏中将要用到的许多小图片,比如陨石,太空船等。这个文件使用 Texture Packer制作的---如果你想使用pvr.ccz文件格式的话,你可能就需要使用这个工具。当然pvr.ccz格式的优点就是文件小,加载速度快。
如果你还没安装上面任何一款工具的话,也不用担心!对于这个教程来说,你完全不需要他们,你可以使用我已经制作好的这些资源就够了。以后,如果有条件,你可以再去试试上面提到的工具。
下面就是Sprites.pvr.ccz文件,它看起来如下图所示:
(译)如何使用cocos2d制作一个太空射击游戏cocos2d
你可能会奇怪,为什么要把所有的这些图片都弄成这样一张大图呢?因为,首先,它可以帮助节省内存,同时还可以提高性能。
接下来,让我们开始coding吧!:)

添加一个太空船

首先,让我们在屏幕上添加一艘太空船吧!
打开HelloWorldLayer.h文件,然后在@interface里面添加两个实例变量:
CCSpriteBatchNode *_batchNode; CCSprite *_ship;
第一个变量 (_batchNode)是必须的,因为我们将把所有的图片存储在一张图片里面,然后使用这个BatchNode就可以仅使用一次opengl调用来做所有的绘图操作。
第二个变量(_ship)代表屏幕上的太空飞船。
接下来,打开HelloWorldLayer.m,并且把init方法改成下面的样子:
-(id) init { if( (self=[super init])) { _batchNode = [CCSpriteBatchNode batchNodeWithFile:@"Sprites.pvr.ccz"]; // 1 [self addChild:_batchNode]; // 2 [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"Sprites.plist"]; // 3 _ship = [CCSprite spriteWithSpriteFrameName:@"SpaceFlier_sm_1.png"]; // 4 CGSize winSize = [CCDirector sharedDirector].winSize; // 5 _ship.position = ccp(winSize.width * 0.1, winSize.height * 0.5); // 6 [_batchNode addChild:_ship z:1]; // 7 } return self; }
让我们一句一句地解释上面的代码:
  1. 使用一张大的图片创建一个CCSpriteBatchNode对象来批处理所有的对象的描绘操作。接收的参数是Sprites.pvr.ccz。
  2. 把CCSpriteBatchNode添加到当前层里面去,这样就可以绘制它的所有的孩子对象。
  3. 加载Sprites.plist文件,它里面包含了这张大图里面的所有的小图的位置坐标信息。这样,你以后可以非常方便地使用 spriteWithSpriteFrameName来提取一张张小图片来初使化一些精灵。
  4. 使用 SpaceFlier_sm_1.png图片来创建一个精灵,注意这张图片是大图里的一个子图。
  5. 使用CCDirector来获得屏幕的大小---我们接下来会用到这个大小。
  6. 设置飞船的位置在屏幕宽度的10%,高度的50处。注意,飞船的中心点位置默认是飞船的中心。
  7. 把ship当作batchNode的一个孩子添加进去,这样的话,这些精灵就会被批处理显示出来。
编译并运行工程,你将会看到你的飞船图片出现在屏幕上面啦!
(译)如何使用cocos2d制作一个太空射击游戏cocos2d

添加视差滚动

我们已经有一个很酷的飞船在屏幕上了,但是,它看起来就好像坐在那里一样,毫无生气!我们可以通过往里面添加视差滚动背景来解决这个问题。
但是,等一下,到底什么是视差滚动了?
视差滚动,简单来说,就是“移动背景中的一些图片比其它图片慢一点点”,打个比方,一个背景中的物体有远有近,近的背景移动地快(比如地面),远的背景移动地慢(比如天空),这样子就会形成景深不一样的视差效果出来。
想要在cocos2d里面使用视差滚动效果非常简单。你只需要做3步就ok了:
  1. 创建一个CCParallaxNode,然后把它加到层中去。
  2. 创建你想要滚动的元素,然后通过调用CCParallaxNode的 addChild:parallaxRatio:positionOffset方法把这些元素添加进去。
  3. 移动CCParallaxNode来滚动背景。这样的话,CCParallaxNode就会根据parallaxRatio的不同,或快或慢地移动它里面添加的元素了。
让我们看看这个过程具体是怎样的。打开HelloWorldLayer.h,然后在@interface里面加入下面代码:
CCParallaxNode *_backgroundNode; CCSprite *_spacedust1; CCSprite *_spacedust2; CCSprite *_planetsunrise; CCSprite *_galaxy; CCSprite *_spacialanomaly; CCSprite *_spacialanomaly2;
然后,转到HelloWorldLayer.m文件,在init方法的底部加入下面的代码:
// 1) Create the CCParallaxNode _backgroundNode = [CCParallaxNode node]; [self addChild:_backgroundNode z:-1]; // 2) Create the sprites we'll add to the CCParallaxNode _spacedust1 = [CCSprite spriteWithFile:@"bg_front_spacedust.png"]; _spacedust2 = [CCSprite spriteWithFile:@"bg_front_spacedust.png"]; _planetsunrise = [CCSprite spriteWithFile:@"bg_planetsunrise.png"]; _galaxy = [CCSprite spriteWithFile:@"bg_galaxy.png"]; _spacialanomaly = [CCSprite spriteWithFile:@"bg_spacialanomaly.png"]; _spacialanomaly2 = [CCSprite spriteWithFile:@"bg_spacialanomaly2.png"]; // 3) Determine relative movement speeds for space dust and background CGPoint dustSpeed = ccp(0.1, 0.1); CGPoint bgSpeed = ccp(0.05, 0.05); // 4) Add children to CCParallaxNode [_backgroundNode addChild:_spacedust1 z:0 parallaxRatio:dustSpeed positionOffset:ccp(0,winSize.height/2)]; [_backgroundNode addChild:_spacedust2 z:0 parallaxRatio:dustSpeed positionOffset:ccp(_spacedust1.contentSize.width,winSize.height/2)]; [_backgroundNode addChild:_galaxy z:-1 parallaxRatio:bgSpeed positionOffset:ccp(0,winSize.height * 0.7)]; [_backgroundNode addChild:_planetsunrise z:-1 parallaxRatio:bgSpeed positionOffset:ccp(600,winSize.height * 0)]; [_backgroundNode addChild:_spacialanomaly z:-1 parallaxRatio:bgSpeed positionOffset:ccp(900,winSize.height * 0.3)]; [_backgroundNode addChild:_spacialanomaly2 z:-1 parallaxRatio:bgSpeed positionOffset:ccp(1500,winSize.height * 0.9)];
编译并运行工程,你将会看到飞船背景了。
(译)如何使用cocos2d制作一个太空射击游戏cocos2d
然而,这还不是很有趣,因为还没有任何东西在动!
为了移动太空尘埃和相关背景层,你只需要移动一样东西就可以了,那就是parallaxNode。对于移动parallax node的每一个y值,灰尘就会移动0.1y值,同时背景会移动0.05y值。
为了移动parallax节点,你只需要飞一帧更新一下它的位置就可以了。打开HelloWorldLayer.m文件,加入下列的代码:(添加位置注意看注释)
// Add to end of init method [self scheduleUpdate]; // Add new update method - (void)update:(ccTime)dt { CGPoint backgroundScrollVel = ccp(-1000, 0); _backgroundNode.position = ccpAdd(_backgroundNode.position, ccpMult(backgroundScrollVel, dt)); }
编译并运行工程,你会看到,使用parallax来做视差滚动效果真是太简洁了!
(译)如何使用cocos2d制作一个太空射击游戏cocos2d
然后,运行几秒钟之后,你会发现一个问题:背景滚动完之后没有了!我们只得到了一个黑色的屏幕!那真是太糟糕了!好,接下来,看看我是怎么解决的吧!

连续地滚动

我们想要背景保持无限地连续滚动效果。我们的做法就是,当背景移出屏幕的左边的时候,就马上把它移动到屏幕右边的适当的位置上去。
这里有一个小小的问题,目前CCParallaxNode并不支持直接修改它的每个孩子的offset。你不能够简单地更新它的孩子的坐标点,因为CCParallaxNode每次更新的时候会覆盖那些改变。
不过没关系,我已经制作了一个CCParallaxNode的分类,它可以用来解决这个问题,这个Category可以在项目的资源文件下面的Classes文件夹中找到。把 CCParallaxNode-Extras.h 和 CCParallaxNode-Extras.m拖到工程中去,同时确保 “Copy items into destination group’s folder”被复选中,然后点击Finish。
然后,在HelloWorldLayer.m中做下列改变来实现连续滚动的效果:
// Add to top of file #import "CCParallaxNode-Extras.h" // Add at end of your update method NSArray *spaceDusts = [NSArray arrayWithObjects:_spacedust1, _spacedust2, nil]; for (CCSprite *spaceDust in spaceDusts) { if ([_backgroundNode convertToWorldSpace:spaceDust.position].x < -spaceDust.contentSize.width) { [_backgroundNode incrementOffset:ccp(2*spaceDust.contentSize.width,0) forChild:spaceDust]; } } NSArray *backgrounds = [NSArray arrayWithObjects:_planetsunrise, _galaxy, _spacialanomaly, _spacialanomaly2, nil]; for (CCSprite *background in backgrounds) { if ([_backgroundNode convertToWorldSpace:background.position].x < -background.contentSize.width) { [_backgroundNode incrementOffset:ccp(2000,0) forChild:background]; } }
编译并运行工程,这时你可以看到有一个无限连续滚动的背景了!
(译)如何使用cocos2d制作一个太空射击游戏cocos2d

添加星星

没有哪一个太空射击游戏是没有星星在旁边飞的!
同样的,我们也可以创建相应的星星图片,并且把它当作paralla节点的一个孩子添加进去。但是,这里我们不想这么做,因为星星是一个非常好的介绍粒子系统的例子。
粒子系统能够让你使用同样的精灵创建大量的小对象,并且非常高效。cocos2d给了你很多配置粒子系统的参数, Particle Designer这个工具可以使这些参数的配置可视化。
但是,这个教程里面,我们不会涉及如何调整粒子系统的各项参数,我们使用已经做好的星星的粒子效果。只需要在init方法中把它简单地添加进来即可:
NSArray *starsArray = [NSArray arrayWithObjects:@"Stars1.plist", @"Stars2.plist", @"Stars3.plist", nil]; for(NSString *stars in starsArray) { CCParticleSystemQuad *starsEffect = [CCParticleSystemQuad particleWithFile:stars]; [self addChild:starsEffect z:1]; }
通过把粒子系统加到层中去,接着它会自动运行起来。编译并运行代码,你现在可以看到好多星星在屏幕上飞过了!:)
(译)如何使用cocos2d制作一个太空射击游戏cocos2d

使用加速计来移动飞船

到目前为止,还是很好,但是,如果我们不能控制飞船的移动的话,那就不是一个完整的游戏!
这里,我们将采用加速计来移动太空飞船。当用户沿着x轴方向倾斜设备的时候,飞船就会上下移动。
这个功能实际上非常容易实现。首先,在HelloWorldLayer.h里面的@interface里面添加一个成员变量,用来记录飞船沿着y轴方向每秒移动的点的个数。(这个点不一定等于一个实际的像素点,如果是Retina的设备,一个点=2个像素)
float _shipPointsPerSecY;
然后,在HelloWorldLayer.m中做如下修改:
// 1) Add to bottom of init self.isAccelerometerEnabled = YES; // 2) Add new method - (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration { #define kFilteringFactor 0.1 #define kRestAccelX -0.6 #define kShipMaxPointsPerSec (winSize.height*0.5) #define kMaxDiffX 0.2 UIAccelerationValue rollingX, rollingY, rollingZ; rollingX = (acceleration.x * kFilteringFactor) + (rollingX * (1.0 - kFilteringFactor)); rollingY = (acceleration.y * kFilteringFactor) + (rollingY * (1.0 - kFilteringFactor)); rollingZ = (acceleration.z * kFilteringFactor) + (rollingZ * (1.0 - kFilteringFactor)); float accelX = acceleration.x - rollingX; float accelY = acceleration.y - rollingY; float accelZ = acceleration.z - rollingZ; CGSize winSize = [CCDirector sharedDirector].winSize; float accelDiff = accelX - kRestAccelX; float accelFraction = accelDiff / kMaxDiffX; float pointsPerSec = kShipMaxPointsPerSec * accelFraction; _shipPointsPerSecY = pointsPerSec; } // 4) Add to bottom of update CGSize winSize = [CCDirector sharedDirector].winSize; float maxY = winSize.height - _ship.contentSize.height/2; float minY = _ship.contentSize.height/2; float newY = _ship.position.y + (_shipPointsPerSecY * dt); newY = MIN(MAX(newY, minY), maxY); _ship.position = ccp(_ship.position.x, newY);
让我们一点点剖析一下这段代码:
  1. 添加这行代码的作用是让当前的层可以接收到加速计移动事件,当有事件发生的时候,会回调 accelerometer:didAcccelerate这个方法。
  2. 这 个方法的前面一部分是直接从Apple的样例代码中copy过来的,所做的事情其实是某种意义上的“滤波”。其实你也不用理解它的原理,基本上就是为了让 飞船的移动更加平滑。如果你实在是对此非常感兴趣,可以查看这里来获得一些信息。不管怎么说,在运行完这个滤波之后,我们可以测试下看看,到底有哪些改 进。通过实现证明,这种方法确实感觉不错!
  3. 基于每秒沿y轴方向移动的点数,来更新飞船的位置。同时要注意边界值的判断。
编译并运行工程(一定要编译到真机上面,否则模拟器是没有加速计效果的,你不可能抱着电脑摇吧:))。这时,上下晃动真机,你可以操作你的飞船移动了!
(译)如何使用cocos2d制作一个太空射击游戏cocos2d

添加陨石

这个游戏目前看起来还不错,但是,危险和激情在哪里呢?让我们往场景中添加一些陨石吧!
我们接下来将要采纳的方法其实是非常普遍的做法,我们在右边屏幕之后创建一些陨石,然后利用cocos2d的action把它移动到屏幕的左边去。
我们可以在每次需要一个陨石的时候,马上创建一个对象,但是,分配内存的操作是非常慢的!所以你最好不要这样做!因此,我们可以预先分配好一堆陨石对象,这样当需要一个陨石对象的时候,就从中抓取一个就ok了。
好,我们看看具体该怎么做吧。打开HelloWorldLayer.h,然后往类中添加下列成员变量:
CCArray *_asteroids; int _nextAsteroid; double _nextAsteroidSpawn;
接下来在HelloWorldLayer.m里面做如下修改:
// Add to top of file #define kNumAsteroids 15 // Add to bottom of init _asteroids = [[CCArray alloc] initWithCapacity:kNumAsteroids]; for(int i = 0; i < kNumAsteroids; ++i) { CCSprite *asteroid = [CCSprite spriteWithSpriteFrameName:@"asteroid.png"]; asteroid.visible = NO; [_batchNode addChild:asteroid]; [_asteroids addObject:asteroid]; } // Add new method, above update loop - (float)randomValueBetween:(float)low andValue:(float)high { return (((float) arc4random() / 0xFFFFFFFFu) * (high - low)) + low; } // Add to bottom of update loop double curTime = CACurrentMediaTime(); if (curTime > _nextAsteroidSpawn) { float randSecs = [self randomValueBetween:0.20 andValue:1.0]; _nextAsteroidSpawn = randSecs + curTime; float randY = [self randomValueBetween:0.0 andValue:winSize.height]; float randDuration = [self randomValueBetween:2.0 andValue:10.0]; CCSprite *asteroid = [_asteroids objectAtIndex:_nextAsteroid]; _nextAsteroid++; if (_nextAsteroid >= _asteroids.count) _nextAsteroid = 0; [asteroid stopAllActions]; asteroid.position = ccp(winSize.width+asteroid.contentSize.width/2, randY); asteroid.visible = YES; [asteroid runAction:[CCSequence actions: [CCMoveBy actionWithDuration:randDuration position:ccp(-winSize.width-asteroid.contentSize.width, 0)], [CCCallFuncN actionWithTarget:self selector:@selector(setInvisible:)], nil]]; } // Add new method - (void)setInvisible:(CCNode *)node { node.visible = NO; }
关于上面的代码,有几点需要说明一下:
  • CCArray 和NSArray差不多,但是做了速度方面的优化。所以如果可以的话,尽可能多地使用CCArray。
  • 注意,我们添加了15个陨石到batchNode中去了。但是,把它们都设置成了不可见。如果是不可见的,就把它当前是未激活的。
  • 我们使用一个实例变量 (_nextAsteroidSpawn) 来指示下一个陨石出现的时间点。我们会在update循环中一直检测这个变量的值。
  • 如 果你对cocos2d的action还很陌生的话,其实action就是一种很简单的,可以让精灵在一段时间做一些事情的对象。比如,你可以让精灵在指定 的一段时间内,让它旋转、缩放、移动等等。这里,我们执行了2个action的序列:一个从右边移动到左边的action,还有一个是当前一个 action结束时,调用另一个函数把陨石设置为不可见的action。这两个action的顺序是固定的。
编译并运行代码,这时候你可以看见一些陨石在屏幕上飞过啦!
(译)如何使用cocos2d制作一个太空射击游戏cocos2d

发射激光

我不清楚你是怎么想的,当我看到屏幕上有陨石在飞的时候,我的第一感觉就是,把它们干掉!
因此,让我们给飞船添加发射激光武器的功能吧!这段代码和我们之前添加陨石的代码有点类似,因为我们会创建一组可以重用的激光束,同时使用action来移动这些激光束。
主要的区别就是,我们将使用touch事件来发射激光。
首先打开HelloWorldLayer.h,然后在类中添加下面成员变量:
CCArray *_shipLasers; int _nextShipLaser;
然后在HelloWorldLayer.m做如下修改:
// Add to top of file #define kNumLasers 5 // Add to bottom of init _shipLasers = [[CCArray alloc] initWithCapacity:kNumLasers]; for(int i = 0; i < kNumLasers; ++i) { CCSprite *shipLaser = [CCSprite spriteWithSpriteFrameName:@"laserbeam_blue.png"]; shipLaser.visible = NO; [_batchNode addChild:shipLaser]; [_shipLasers addObject:shipLaser]; } self.isTouchEnabled = YES; // Add new method - (void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { CGSize winSize = [CCDirector sharedDirector].winSize; CCSprite *shipLaser = [_shipLasers objectAtIndex:_nextShipLaser]; _nextShipLaser++; if (_nextShipLaser >= _shipLasers.count) _nextShipLaser = 0; shipLaser.position = ccpAdd(_ship.position, ccp(shipLaser.contentSize.width/2, 0)); shipLaser.visible = YES; [shipLaser stopAllActions]; [shipLaser runAction:[CCSequence actions: [CCMoveBy actionWithDuration:0.5 position:ccp(winSize.width, 0)], [CCCallFuncN actionWithTarget:self selector:@selector(setInvisible:)], nil]]; }
这个例子也向你展示了,在cocos2d里面接收touch事件是多么容易啊---仅需要把isTouchEnabled设置为yes就ok了。然后你需要实现ccTouchesBeban(或者ccTouchesMoved,ccTouchesEnded等等)。
编译并运行代码,现在你可以发射激光武器了。
(译)如何使用cocos2d制作一个太空射击游戏cocos2d

基本的碰撞检测

恩,到目前为止,这看起来有点像一个游戏了,但是,还不够完整,因为没有爆炸!
而且我天性不听话,喜欢搞破坏,所以是时候往游戏里面添加一些破坏啦!:)
打开HelloWorldLayer.h,然后添加下面的实例变量:
int _lives;
然后update方法的最后面添加下面代码:
for (CCSprite *asteroid in _asteroids) { if (!asteroid.visible) continue; for (CCSprite *shipLaser in _shipLasers) { if (!shipLaser.visible) continue; if (CGRectIntersectsRect(shipLaser.boundingBox, asteroid.boundingBox)) { shipLaser.visible = NO; asteroid.visible = NO; continue; } } if (CGRectIntersectsRect(_ship.boundingBox, asteroid.boundingBox)) { asteroid.visible = NO; [_ship runAction:[CCBlink actionWithDuration:1.0 blinks:9]]; _lives--; } }
这里使用了最最简单的方式,只是判断两个精灵的边界矩形是否有交集。注意,边界部分可能有透明,而且边界矩形不能反应精灵实例的轮廓,所以最好的做法是使用前面介绍的box2d的方法。不过没关系,这个游戏,我们这样做就可以了。
对于更好的使用box2d的方法,请查看《如何只使用box2d来做碰撞检测》。
编译并运行代码,现在你会看到有东西爆炸啦!

胜利/失败条件检测

我们差不多快做完了---现在只需要往游戏中添加判断游戏胜利或者失败的条件就可以了。
我是这样考虑的,只要玩家存活了30秒,就是胜利;如果被陨石打中了3次,那么就是失败。
因此,在HelloWorldLayer.h中做如下修改:
// Add before @interface typedef enum { kEndReasonWin, kEndReasonLose } EndReason; // Add inside @interface double _gameOverTime; bool _gameOver;
同时,相应地修改HelloWorldLayer.m:
// Add at end of init _lives = 3; double curTime = CACurrentMediaTime(); _gameOverTime = curTime + 30.0; // Add at end of update loop if (_lives <= 0) { [_ship stopAllActions]; _ship.visible = FALSE; [self endScene:kEndReasonLose]; } else if (curTime >= _gameOverTime) { [self endScene:kEndReasonWin]; } // Add new methods above update - (void)restartTapped:(id)sender { [[CCDirector sharedDirector] replaceScene:[CCTransitionZoomFlipX transitionWithDuration:0.5 scene:[HelloWorldLayer scene]]]; } - (void)endScene:(EndReason)endReason { if (_gameOver) return; _gameOver = true; CGSize winSize = [CCDirector sharedDirector].winSize; NSString *message; if (endReason == kEndReasonWin) { message = @"You win!"; } else if (endReason == kEndReasonLose) { message = @"You lose!"; } CCLabelBMFont *label; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { label = [CCLabelBMFont labelWithString:message fntFile:@"Arial-hd.fnt"]; } else { label = [CCLabelBMFont labelWithString:message fntFile:@"Arial.fnt"]; } label.scale = 0.1; label.position = ccp(winSize.width/2, winSize.height * 0.6); [self addChild:label]; CCLabelBMFont *restartLabel; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { restartLabel = [CCLabelBMFont labelWithString:@"Restart" fntFile:@"Arial-hd.fnt"]; } else { restartLabel = [CCLabelBMFont labelWithString:@"Restart" fntFile:@"Arial.fnt"]; } CCMenuItemLabel *restartItem = [CCMenuItemLabel itemWithLabel:restartLabel target:self selector:@selector(restartTapped:)]; restartItem.scale = 0.1; restartItem.position = ccp(winSize.width/2, winSize.height * 0.4); CCMenu *menu = [CCMenu menuWithItems:restartItem, nil]; menu.position = CGPointZero; [self addChild:menu]; [restartItem runAction:[CCScaleTo actionWithDuration:0.5 scale:1.0]]; [label runAction:[CCScaleTo actionWithDuration:0.5 scale:1.0]]; }
如果你不理解endScene方法的话,也没关系---那些代码是我过去用来快速地判断游戏胜利或失败的方式。
真正重要的是,你要理解其它部分的代码---在每一个update循环中,你只检测玩家是否胜利或失败,然后相应地调那个方法就可以了。
编译并运行代码,看看你会不会输?
(译)如何使用cocos2d制作一个太空射击游戏cocos2d

免费的音乐和音效

你懂的,我怎么可能不给你们提供一些很棒的音效和音效呢?
之前,你已经把相关的音乐和音效加到工程里面来了,因此,我们只需要在HelloWorldLayer.m中做如下修改即可:
// Add to top of file #import "SimpleAudioEngine.h" // Add to bottom of init [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"SpaceGame.caf" loop:YES]; [[SimpleAudioEngine sharedEngine] preloadEffect:@"explosion_large.caf"]; [[SimpleAudioEngine sharedEngine] preloadEffect:@"laser_ship.caf"]; // Add inside BOTH CGRectIntersectsRect tests [[SimpleAudioEngine sharedEngine] playEffect:@"explosion_large.caf"]; // Add inside ccTouchBegan [[SimpleAudioEngine sharedEngine] playEffect:@"laser_ship.caf"];
好了!编译并运行,这就是一个我们从头至尾一步步开发出来的完整的游戏啦!:)
(译)如何使用cocos2d制作一个太空射击游戏cocos2d


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 驾校准考证丢了怎么办 科目二下大雨怎么办 考科目二下雨天怎么办 普通话总是二乙怎么办 科目二很紧张怎么办 18年科目四缺考怎么办 个人医保卡欠费怎么办 医保欠费不想交怎么办 怀化市驾考绿色通道怎么办? 签注易不能办理怎么办 网上怎么办护照和签证 意大利被偷护照怎么办 户口在学校 怎么办签证 户口换了身份证怎么办 广州在校大学生怎么办护照 民间借贷无法还怎么办 退伍档案没接收怎么办 档案被单位扣住怎么办 公积金提不出来怎么办 公积金还贷款怎么办手续 科一预约失败怎么办 科四忘记预约怎么办 我科目一缺考了怎么办? 无可选考试场地怎么办 早产儿脑部发育不好怎么办 宝宝脑部发育不好怎么办 小孩脑部发育不好怎么办 8岁儿童智力低下怎么办 儿童食物不耐受怎么办 忘记就诊卡号怎么办 nt检查预约不到怎么办 听力不好科目三怎么办 青岛公安不立案怎么办 长春驾照丢了怎么办 驾照超期一个月怎么办 太原暂住证丢了怎么办 太原居住证丢了怎么办 太原自行车丢了怎么办 太原身份证丢了怎么办 在太原健康证怎么办 学车体检色盲怎么办