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

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

碰撞检测Collision Detection

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

1
2
NSMutableArray  *_targets;
NSMutableArray  *_projectiles;

并在init方法里加入初始化数组的代码:

1
2
_targets  =  [ [ NSMutableArray alloc ] init ];
_projectiles  =  [ [ NSMutableArray alloc ] init ];

在dealloc方法里边清理之:

1
2
3
4
[_targets release ];
_targets  =  nil;
[_projectiles release ];
_projectiles  =  nil;

现在,修改addTarget方法,在靶子数组中加入一个新靶子并设置其标识(tag)留待后用:

1
2
target.tag  =  1;
[_targets addObject :target ];

同样的,把在ccTouchesEnded里新建的飞镖加入到飞镖数组中并设置tag留待后用:

1
2
projectile.tag  =  2;
[_projectiles addObject :projectile ];

最后,修改spriteMoveFinished方法,根据tag分类把即将删除的对象从数组中也移除掉:

1
2
3
4
5
if  (sprite.tag  ==  1 )  {  // target
   [_targets removeObject :sprite ];
}  else  if  (sprite.tag  ==  2 )  {  // projectile
   [_projectiles removeObject :sprite ];
}

编译并运行,确保到目前为止一切都OK。虽然目前还看不到什么显著的变化,但我们已经有了做碰撞检测的基础了。
添加以下方法到HelloWorldLayer:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
-  ( 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调度这个方法,使其在每一帧都执行:

1
[self schedule : @selector (update : ) ];

编译并运行,所有和飞镖碰撞的靶子都会灰飞烟灭了!

完成触摸Finishing Touches

我们已经非常接近制作出一个成品(但很简单)的游戏了。只需要再加入一些音效和音乐(没有游戏不带声音的!)以及一些简单的游戏逻辑。
首先,把背景音乐和一个射击音效拖拽进你的工程的resources文件夹。你可以随意使用以下资源cool background music I made or my awesome pew-pew sound effect, 或者制作你自己的。
接下来在HelloWorldLayer.m的一开头导入头文件:

1
#import "SimpleAudioEngine.h"

在init方法中,如下所示播放背景音乐:

1
[ [SimpleAudioEngine sharedEngine ] playBackgroundMusic : @ "background-music-aac.caf" ];

在ccTouchesEnded方法中播放音效:

1
[ [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:

1
2
3
4
5
6
7
8
9
10
11
12
13
#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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#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块儿加入如下:

1
int _projectilesDestroyed;

在HelloWorldLayer.m里,导入GameOverScene类:

1
#import "GameOverScene.h"

在update方法中,增加飞镖摧毁靶子的数量并检测获得胜利的条件,在removeChild:target:之后加入:

1
2
3
4
5
6
7
_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:方法之后加入:

1
2
3
GameOverScene  *gameOverScene  =  [GameOverScene node ];
[gameOverScene.layer.label setString : @ "You Lose :[" ];
[ [CCDirector sharedDirector ] replaceScene :gameOverScene ];

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

源码全部给你!Gimme The Code!

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值