【Cocos2D游戏引擎教程】如何使用Cocos2D制作一款简单的iPhone游戏(第二部分)

第一部分里,我们从touches对象集合中选择一个,得到他在当前屏幕上的坐标,通过调用convertToGL来把此坐标转换为当前屏幕模式适应的,这一点很重要,因为我们使用的是landscape模式。
接下来加载飞镖sprite并像往常一样设置其初始坐标。根据之前讨论过的相似三角形算法,我们计算得到飞镖的终点。
注意这个算法并不完美。即使飞镖的Y坐标已经出了屏幕,它还是会被强制移动到X坐标移出屏幕为止。想解决这个有很多手段,包括检测射击点到屏幕边缘的最短距离,在游戏逻辑的回调里检测飞镖坐标是否在屏幕之外(比如visit),虽然这些方法都可以解决它,但简单起见,这篇初学者教程还是会使用之前的方式。
最后一件事儿是决定运动所需的时间。飞镖最好是能以固定的速率射出,所以我们还需要一丁点儿数学计算。使用 勾股定理可以轻松地得到斜边的长度。
一旦有了距离,只需要将其除以一个固定的速率,便可得到时间。
剩余部分就像我们之前做的,给靶子设置上actions。编译并运行,哈哈,你的忍者能给予冲过来的鬼头靶子致命打击了!
【Cocos2D游戏引擎教程】如何使用Cocos2D制作一款简单的iPhone游戏(第二部分)

碰撞检测Collision Detection

飞镖四处飞,但我们的小忍者并没有看到飞镖击倒鬼头靶子。是时候加入一些检测飞镖与靶子碰撞检测的代码了。
使用Cocos2D有很多途径解决这个,包括使用其中一个引擎包含的物理引擎:Box2D或者Chipmunk。为了有效说明问题的本质并使事情简单,我们将自己实现一个简单的碰撞检测。
首先,我们需要记录所有在当前场景里的靶子和飞镖对象。在HelloWorldLayer类的声明中加入:
NSMutableArray *_targets;
NSMutableArray *_projectiles;

并在init方法里加入初始化数组的代码:
_targets = [[NSMutableArray alloc] init];
_projectiles = [[NSMutableArray alloc] init];

在dealloc方法里边清理之:
[_targets release];
_targets = nil;
[_projectiles release];
_projectiles = nil;

现在,修改addTarget方法,在靶子数组中加入一个新靶子并设置其标识(tag)留待后用:
target.tag = 1;
[_targets addObject:target];

同样的,把在ccTouchesEnded里新建的飞镖加入到飞镖数组中并设置tag留待后用:
projectile.tag = 2;
[_projectiles addObject:projectile];

最后,修改spriteMoveFinished方法,根据tag分类把即将删除的对象从数组中也移除掉:
if (sprite.tag == 1) { // target
[_targets removeObject:sprite];
} else if (sprite.tag == 2) { // projectile
[_projectiles removeObject:sprite];
}

编译并运行,确保到目前为止一切都OK。虽然目前还看不到什么显著的变化,但我们已经有了做碰撞检测的基础了。
添加以下方法到HelloWorldLayer:
- (void)update:(ccTime)dt {
NSMutableArray *projectilesToDelete = [[NSMutableArray alloc] init];
for (CCSprite *projectile in _projectiles) {
CGRect projectileRect = CGRectMake(
projectile.position.x - (projectile.contentSize.width/2),
projectile.position.y - (projectile.contentSize.height/2),
projectile.contentSize.width,
projectile.contentSize.height);
NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init];
for (CCSprite *target in _targets) {
CGRect targetRect = CGRectMake(
target.position.x - (target.contentSize.width/2),
target.position.y - (target.contentSize.height/2),
target.contentSize.width,
target.contentSize.height);
if (CGRectIntersectsRect(projectileRect, targetRect)) {
[targetsToDelete addObject:target];
}
}
for (CCSprite *target in targetsToDelete) {
[_targets removeObject:target];
[self removeChild:target cleanup:YES];
}
if (targetsToDelete.count > 0) {
[projectilesToDelete addObject:projectile];
}
[targetsToDelete release];
}
for (CCSprite *projectile in projectilesToDelete) {
[_projectiles removeObject:projectile];
[self removeChild:projectile cleanup:YES];
}
[projectilesToDelete release];
}

以上内容很清晰。我们遍历了一下飞镖和靶子数组,在遍历中得到每一个对象的bounding box(碰撞框),使用CGRectIntersectsRect来检测两个矩形是否相交。如果有相交,则将飞镖和靶子分别从场景和数组中移除。注意我们必须将这些对象加入到“toDelete”结尾的数组中,因为我们没法在当前循环中从数组中删掉它。还是一样,有很多更优的方法来解决这类问题,简单起见,我使用最简单的方法。
你仅仅需要一步就可以欢呼了,使用schedule调度这个方法,使其在每一帧都执行:
[self schedule:@selector(update:)];
编译并运行,所有和飞镖碰撞的靶子都会灰飞烟灭了!

完成触摸Finishing Touches

我们已经非常接近制作出一个成品(但很简单)的游戏了。只需要再加入一些音效和音乐(没有游戏不带声音的!)以及一些简单的游戏逻辑。
首先,把背景音乐和一个射击音效拖拽进你的工程的resources文件夹。你可以随意使用以下资源cool background music I made or my awesome pew-pew sound effect, 或者制作你自己的。
接下来在HelloWorldLayer.m的一开头导入头文件:
#import "SimpleAudioEngine.h"
在init方法中,如下所示播放背景音乐:
[[SimpleAudioEngine sharedEngine] playBackgroundMusic:@"background-music-aac.caf"];
在ccTouchesEnded方法中播放音效:
[[SimpleAudioEngine sharedEngine] playEffect:@"pew-pew-lei.caf"];
现在,我们加入一个提示“You Win”或者“You Lose”的游戏结束场景。右键点击Classes文件夹,选择FileNew File,并选择Objective-C class,确保继承的类是NSObject。点击Next,在filename位置输入GameOverScene作为文件名,确保“Also create GameOverScene.h”是选中的。
用以下内容替换掉GameOverScene.h:
#import "cocos2d.h"
@interface GameOverLayer : CCLayerColor {
CCLabelTTF *_label;
}
@property (nonatomic, retain) CCLabelTTF *label;
@end
@interface GameOverScene : CCScene {
GameOverLayer *_layer;
}
@property (nonatomic, retain) GameOverLayer *layer;
@end

用以下内容替换掉GameOverScene.m:
#import "GameOverScene.h"
#import "HelloWorldLayer.h"
@implementation GameOverScene
@synthesize layer = _layer;
- (id)init {
if ((self = [super init])) {
self.layer = [GameOverLayer node];
[self addChild:_layer];
}
return self;
}
- (void)dealloc {
[_layer release];
_layer = nil;
[super dealloc];
}
@end
@implementation GameOverLayer
@synthesize label = _label;
-(id) init
{
if( (self=[super initWithColor:ccc4(255,255,255,255)] )) {
CGSize winSize = [[CCDirector sharedDirector] winSize];
self.label = [CCLabelTTF labelWithString:@"" fontName:@"Arial" fontSize:32];
_label.color = ccc3(0,0,0);
_label.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:_label];
[self runAction:[CCSequence actions:
[CCDelayTime actionWithDuration:3],
[CCCallFunc actionWithTarget:self selector:@selector(gameOverDone)],
nil]];
}
return self;
}
- (void)gameOverDone {
[[CCDirector sharedDirector] replaceScene:[HelloWorldLayer scene]];
}
- (void)dealloc {
[_label release];
_label = nil;
[super dealloc];
}
@end

注意这里有两个不同的对象:一个scene和一个layer。一个scene可以包含很多layer。不过目前这个只有一个,这个layer只是放置了一个label在屏幕中心,并schedule了一个3秒会自动返回Hello World场景的事件。
最后,加入一些极为简单的游戏逻辑进去。首先,记录一下被主人公的飞镖干掉的靶子。在HelloWorldLayer类中加入一个成员变量,在HelloWorldLayer.h中的@interface块儿加入如下:
int _projectilesDestroyed;
在HelloWorldLayer.m里,导入GameOverScene类:
#import "GameOverScene.h"
在update方法中,增加飞镖摧毁靶子的数量并检测获得胜利的条件,在removeChild:target:之后加入:
_projectilesDestroyed++;
if (_projectilesDestroyed > 30) {
GameOverScene *gameOverScene = [GameOverScene node];
_projectilesDestroyed = 0;
[gameOverScene.layer.label setString:@"You Win!"];
[[CCDirector sharedDirector] replaceScene:gameOverScene];
}

当有鬼头靶子越过了屏幕左侧,你就输了,修改spriteMoveFinished方法,在tag == 1 case中removeChild:sprite:方法之后加入:
GameOverScene *gameOverScene = [GameOverScene node];
[gameOverScene.layer.label setString:@"You Lose :["];
[[CCDirector sharedDirector] replaceScene:gameOverScene];

编译并执行,现在你胜利或失败后会进入game over场景中,根据条件的不同会显示相应信息。

源码全部给你!Gimme The Code!

就到这里!这是到目前为止所有的源码下载地址simple Cocos2D iPhone Game

本部分教程中提及源码或资源备用下载

[dl href=’http://pan.baidu.com/share/link?shareid=61923&uk=2502824232′]simple Cocos2D iPhone Game[/dl]
[dl href=’http://pan.baidu.com/share/link?shareid=61924&uk=2502824232′]cool background music I made [/dl]
[dl href=’http://pan.baidu.com/share/link?shareid=61925&uk=2502824232′]my awesome pew-pew sound effect[/dl]