《Cocos2D权威指南》——2.3 玩家交互

2.3 玩家交互

2.3.1 添加加速计移动
在Cocos2D世界里添加加速计支持非常简单,只需在当前运行的CCLayer的init方法返回之前,添加代码清单2-14所示代码。
代码清单2-14 添加加速计支持

//7.enable accelerometer
self.isAccelerometerEnabled = YES;

为了让玩家能够使用加速计非常平滑地控制飞机的飞行,这里提供一种通用的方法。因为游戏是垂直射击游戏,所以我们只关心设备垂直放置时Home按键左右摆动方向的加速计值即可。
步骤1 打开HelloWorldLayer.h文件,添加一个CGPoint _playerVelocity实例变量。
步骤2 打开HelloWorldLayer.m文件,在私有分类里添加-(void) updatePlayerPosition: (ccTime)dt方法,如图2-8所示。
步骤3 在init方法返回之后,紧跟代码清单2-14所示代码后添加方法调用,如代码清单2-15所示。
代码清单2-15 紧跟代码清单2-14所示代码后添加方法调用

//8.game main loop
  [self scheduleUpdate];

此方法是本游戏的主循环。任何游戏都包含一个游戏主循环,此主循环类用来更新游戏世界的状态、碰撞处理逻辑和玩家状态等,这里主要更新玩家的位置信息。
步骤4 定义一个update方法,调用更新玩家位置信息的方法,如代码清单2-16所示。
代码清单2-16 定义update方法

-(void) update:(ccTime)dt{
    [selfupdatePlayerPosition:dt];
}

在讨论updatePlayerPositoin方法之前,我们先看看如何操作加速计,同时保存加速计的数据。在update方法之后,添加代码清单2-17所示代码。
代码清单2-17 操作加速计

#pragma mark - accelerometer callback
-(void) accelerometer:(UIAccelerometer *)accelerometer didAccelerate: (UIAcceleration *)acceleration{
float deceleration = 0.4f;
float sensitivity = 6.0f;
floatmaxVelocity = 100;
playerVelocity.x = playerVelocity.x * deceleration + acceleration.x * sensitivity;
if (playerVelocity.x>maxVelocity) {
   playerVelocity.x = maxVelocity;
}else if(playerVelocity.x< -maxVelocity){
   playerVelocity.x = -maxVelocity;
    }

}

这里主要做两件事:
通过“滤波”方式,从加速计x轴方向取得数据,计算得到一个“合理”的速度值;
限制飞机飞行的最大速度。
注意 如果想获取其他方向的值,相应地计算acceleration的其他两个分量的值就可以了。
最后,看看实际更新玩家飞机位置信息的方法实现,如代码清单2-18所示。
代码清单2-18 更新玩家飞机位置信息的方法实现

-(void) updatePlayerPosition:(ccTime)dt{
    CCSprite *playerSprite = (CCSprite*)[self getChildByTag:kTagPalyer];
    CGPoint pos = playerSprite.position;
   pos.x += playerVelocity.x;

   CGSizescreenSize = [CCDirector sharedDirector].winSize;
   floatimageWidthHavled = playerSprite.texture.contentSize.width * 0.5f;
   floatleftBoderLimit = imageWidthHavled;
   floatrightBoderLimit = screenSize.width - imageWidthHavled;

   if (pos.x<leftBoderLimit) {
      pos.x = leftBoderLimit;
      playerVelocity = CGPointZero;
   }else if(pos.x>rightBoderLimit){
      pos.x = rightBoderLimit;
      playerVelocity = CGPointZero;
   }

   playerSprite.position = pos;
}

这段代码根据之前计算出来的加速计的速度值,加上玩家飞机的x轴方向的速度,同时限制玩家飞机只能在屏幕范围之内飞行。
好了,现在编译并运行,我们就可以通过加速计来控制飞机的移动了!
2.3.2 添加子弹并射击
目前来说,一切看起来还不错。但是,假如不能开枪打死这些敌机,那么游戏会非常乏味。话不多说,给玩家飞机添加子弹射击功能吧!为了玩家操作的方便性,我们希望实现在游戏开始时只要轻轻单击屏幕就可以自动发射子弹了,这样玩家只需要专心控制飞机的飞行就可以了,当然,子弹是无限的。
步骤1 在HelloWorldLayer.h中添加两个成员变量,如代码清单2-19所示。
代码清单2-19 在HelloWorldLayer.h中添加两个成员变量

BOOL _isTouchToShoot;
CCSprite *_bulletSprite;

步骤2 在HelloWorldLayer()的@end之前添加一个新方法,如代码清单2-20所示。
代码清单2-20 在HelloWorldLayer()的@end之前添加新方法
-(void) bulletFinishedMoving:(id)sender;
步骤3 为了能接收玩家的触摸消息,我们在init方法返回之前添加代码清单2-21所示代码。
代码清单2-21 在init方法返回之前添加代码

//9.enable touch
self.isTouchEnabled = YES;
_isTouchToShoot = NO;

//10.init bullets
_bulletSprite = [CCSprite spriteWithFile:@"bullet1.png"];
_bulletSprite.visible = NO;
[self addChild:_bulletSprite z:4];

其他self.isTouchEnabled设置为YES之后,就可以在CCLayer里处理触摸消息了。
步骤4 框架自动调用ccTouchesEnded方法,实现代码如代码清单2-22所示。
代码清单2-22 ccTouchesEnded方法的实现

-(void) ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    CCLOG(@"touch!");
    _isTouchToShoot = YES;
}

在init方法最后初始化子弹精灵。
注意 这里我们没有采用敌机那种方式用数组保存一系列精灵图片,因为这里要设计子弹消失了才可以发射下一颗子弹,这样可以给游戏添加一些难度和趣味性。
步骤5 在update方法底部添加发射子弹的方法。
[self updatePlayerShooting:dt]方法的作用就是让玩家飞机不断地发射子弹,具体实现如代码清单2-23所示。
代码清单2-23 在update方法底部添加[self updatePlayerShooting:dt]方法

-(void) updatePlayerShooting:(ccTime)dt{
if (_bulletSprite.visible || !_isTouchToShoot) {
return;
    }

    CCSprite *playerSprite = (CCSprite*)[self getChildByTag:kTagPalyer];
    CGPoint pos = playerSprite.position;

    CGPoint bulletPos = CGPointMake(pos.x, 
pos.y + playerSprite.contentSize.height/ 2 + _bulletSprite.contentSize.height);
    _bulletSprite.position = bulletPos;
    _bulletSprite.visible = YES;

CGSizewinSize = [CCDirector sharedDirector].winSize;
idmoveBy = [CCMoveBy actionWithDuration:1.0 position:ccp(0,winSize.height - bulletPos.y)];
id callback = [CCCallFuncN actionWithTarget:self selector:@selector(bulletFinishedMoving:)];
id ac = [CCSequence actions:moveBy,callback, nil];
    [_bulletSpriterunAction:ac];
}
-(void) bulletFinishedMoving:(id)sender{
    _bulletSprite.visible = NO;
}

这段代码很简单,主要判断子弹当前是否可见。如果可见或者玩家还没有触摸屏幕,则直接返回。接下来就是计算子弹的起始坐标,然后让子弹运行一个action往上飞行就OK了。等子弹到达屏幕顶端时,我们再把子弹的可见性重新设置为NO,这样下一颗子弹又可以从玩家飞机上空发射出来了。
编译并运行,然后轻轻触摸屏幕,是不是有真实的射击游戏的感觉了呢?

上一篇:冬季实战营第一期:从零到一上手玩转云服务器 学习报告


下一篇:用 Flask 来写个轻博客 (18) — 使用工厂模式来生成应用对象