用 SpriteKit 做一个逃逸游戏 (3)

翻译 2014年02月07日 13:12:16

移动球拍

我们需要移动它!移动球拍需要接收触摸事件。你可以在 MyScene 中实现以下方法以接收触摸事件:

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event;

-(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event;

-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event;

在此之前,还需要新加一个属性。在 MyScene.m 中@implementation  语句前加入:

@interface MyScene()  

@property (nonatomic) BOOL isFingerOnPaddle;  

@end

这个属性用于保存玩家是否触摸到了球拍。这对于实现球拍的移动是有用的。

然后,在 MyScene.m 中实现 touchesBegan:withEvent: 方法:

-(void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {

     /* 触摸开始时调用 */

     UITouch* touch = [touches anyObject];

     CGPoint touchLocation = [touch locationInNode:self];

       SKPhysicsBody* body = [self.physicsWorld bodyAtPoint:touchLocation];

     if (body && [body.node.name isEqualToString: paddleCategoryName]) {

         NSLog(@"Began touch on paddle");

         self.isFingerOnPaddle = YES;

     }

}

上述代码获取触摸并得到触摸在屏幕中的位置。然后用physicasWorld的 bodyAtPoint:方法找出触摸位置所处的物体(如果有的话)。然后判断是否有这样一个物体存在,以及这个物体是不是球拍。早先我们为球拍指定了一个名字——你可以通过物体的名字来判断它是否是指定的对象。如果触摸位置就是球拍所处的位置,将isFingerOnPaddle 设为 YES 并在控制台中输出一个消息。

你已经摸到我了;)

接下来实现  touchesMoved:withEvent:方法:

-(void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {

     // 1 如果用户触摸到球拍

     if (self.isFingerOnPaddle) {

         // 2 获取触摸位置

         UITouch* touch = [touches anyObject];

         CGPoint touchLocation = [touch locationInNode:self];

         CGPoint previousLocation = [touch previousLocationInNode:self];

         // 3 获得球拍节点

         SKSpriteNode* paddle = (SKSpriteNode*)[self childNodeWithName: paddleCategoryName];

         // 4 计算球拍将移动的x位置

         int paddleX = paddle.position.x + (touchLocation.x - previousLocation.x);

         // 5 限制球拍的移动在屏幕范围之内

         paddleX = MAX(paddleX, paddle.size.width/2);

         paddleX = MIN(paddleX, self.size.width - paddle.size.width/2);

         // 6 更新球拍的坐标

         paddle.position = CGPointMake(paddleX, paddle.position.y);

     }

}

这就是球拍的移动方式。

  1. 检查玩家是否触摸到球拍。
  2. 如果是,需要根据玩家滑动手指的距离来更改球拍的坐标。这就需要算出本次触摸的位置和上次触摸的位置。
  3. 获得球拍对应的 SKSpriteNode 对象。
  4. 将手指移动的x距离加到球拍当前位置上。
  5. 重置球拍位置之前,限定球拍移动分为在屏幕许可的范围之内。
  6. 将球拍位置设置为计算结果。

注意:如你所见,代码直接操作了球拍的坐标。这是由于球拍是静态的。对于动态物体,不应该直接改变其坐标。因为这样会破坏物理引擎模拟的状态,导致不可预料的行为。

你别不信,如果你将球拍改为动态物体,将重力加速度设置为低重力状态,例如:

self.physicsWorld.gravity = CGPointMake(-0.1, -0.1);

试试看,一切都乱了,不是吗?

还有最后一个触摸方法 touchesEnded:withEvent: 需要实现,我们在这里进行变量的重置:

-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {

     self.isFingerOnPaddle = NO;

}

将 isFingerOnPaddle  设置为 NO;确保用户手指离开并再次触摸屏幕之后,变量被重置。

SpriteKit 的第一次亲密接触!

啊,不是你想象的那种接触!(本图片来自 DeviantArt.com 的 hugoo13,受知识共享协议保护)

 

迄今为止,我们的游戏中只有一个会在屏幕中四处乱蹦的小球,和一个通过触摸来进行移动的球拍。

对于真正的游戏,还需要设定某种规则以判定玩家输赢。我们设定,如果球落到了屏幕底部而不是球拍上为输。但如何使用SpriteKit 来判断这种情况?

SpriteKit 可以判断两个物体间发生的接触。但是为实现这个目的,需要遵循几个固定的步骤。我先简单描述一下每个步骤,稍后再细讲:

 

  • 设置物体的 bit 掩码:在游戏中,物体存在几种类型——例如玩家、怪物、子弹、道具等等。为了标志每种不同的物体,我们可以将对象通过以下几个 bit 掩码来加以配置:
  • Set up physics body bit masks: In your game you might have several different types of physics bodies – for example, you can have the player, enemies, bullets, bonus items etc. To uniquely identify these different types of physics bodies, each physics body can be configured using several bit masks. These include:
    • categoryBitMask: 用于表示对象类型。用一个 32 位整数表示,其中,每一位表示一种类型,因此整个游戏可以包含 32 种对象。这对大部分游戏来说就已足够了。对于复杂游戏,还可以用多个类型来组合。因此,通过这种灵活的方式你可以突破 32 这个限制。
    • contactTestBitMask: 当对象和其他对象发生触碰时,我们可以在这个掩码上设置一个类型码,这样 SpriteKit 会向 contact delegate 发送消息。默认每位都是0——表示不通知任何对象。从性能的角度考虑,你应该只设置那些真正需要设置的位。
    • Setting a bit in this bitmask causes SpriteKit to notify the contact delegate when the body touches another body assigned to that particular category. By default, all bits are cleared – you are not notified about any contacts between objects. For best performance you should only set bits in the contacts mask for interactions you are really interested in.
    • collisionBitMask: 用于定义能够和本类物体发生碰撞的物体。一般情况下,一个质量很大的物体与一个质量很小的物体发生碰撞,后者对前者加速度的改变微乎其微,因此通常情况下无需对此类碰撞进行检测。也就是说,允许两个对象能够彼此穿过。
  • 设置并实现 contact delegate:conatact delegate 是 SKPhysicasWorld 的一个属性。当两个物体开始和发生碰撞时(根据指定的 contactTestBitMasks 值),contact delegate 对象将被通知。

注意:位掩码?如果你从未使用过它,不要担心。尽管一开始他们看起来很复杂,但却非常有用!

什么是位掩码?位掩码是一连串的二进制数。比如:1011 1000。其实并不复杂。

为什么说它很有用?首先,你可以从这个二进制数读取对象状态,也可以将对象状态单独设置到这个数的某一个二进制位。只需要进行一个 AND 或 OR 操作:

强大的位掩码 :)

它以一种非常紧凑的方式(比如一个变量)存储大量信息,同时存取、操作存储在其中的信息也很方便。




用 SpriteKit 做一个逃逸游戏 (2)

在initWithSize:方法末尾加入下列代码: // 1 创建物理形状(以屏幕为边界)     SKPhysicsBody* borderBody = [SKPhysicsBody bo...
  • kmyhy
  • kmyhy
  • 2014年01月20日 16:21
  • 4791

用 SpriteKit 做一个逃逸游戏 (4)

在代码中怎样使用? 首先,为不同的物体类别创建常量。在 MyScene.m 中的常量声明语句后加入下列语句: static const uint32_t ballCategor...

用 SpriteKit 做一个逃逸游戏 (4)

在代码中怎样使用?首先,为不同的物体类别创建常量。在 MyScene.m 中的常量声明语句后加入下列语句: static const uint32_t ballCategory  = 0x1 ...
  • kmyhy
  • kmyhy
  • 2014年02月07日 13:18
  • 4017

用 SpriteKit 做一个逃逸游戏 (5)

但是……这真是出人意料…嗯……怎么样?出乎你的意料了吧!当球碰上砖块之后,砖块是被弹开,而不是被击碎?为了监听球和砖之间的碰撞,你需要修改球的contactTestBitMask(注意,在 initW...
  • kmyhy
  • kmyhy
  • 2014年02月07日 13:20
  • 4172

用 SpriteKit 做一个逃逸游戏 (1)

原文:http://www.raywenderlich.com/49721/how-to-create-a-breakout-game-using-spritekitSpriteKit 是苹果的新的游...
  • kmyhy
  • kmyhy
  • 2014年01月15日 15:46
  • 8485

做一个像植物大战僵尸的Flash游戏3

http://bbs.9ria.com/thread-81770-1-5.html 查看该系列的其它文章: 做一个像植物大战僵尸的Flash游戏1 做一个像植物大战僵尸的Flash游戏2 做一...

使用Multiplayer Networking做一个简单的多人游戏例子-1/3(Unity3D开发之二十五)

本文主要讲述了如何使用Multiplayer Networking开发多人游戏,文中实例、代码来源于Unity官方教程。 原文:INTRODUCTION TO A SIMPLE MULTIPLAY...

使用Multiplayer Networking做一个简单的多人游戏例子-2/3(Unity3D开发之二十六)

使用Multiplayer Networking做一个简单的多人游戏例子-1/3 7. 在网络中控制Player移动上一篇中,玩家操作移动会同时控制同屏内的所有Player,且只有自己的屏幕生效。因为...

使用Multiplayer Networking做一个简单的多人游戏例子-3/3(Unity3D开发之二十七)

上一篇中血条还没有同步到所有客户端,下面添加血条同步。主要用到[SyncVar]同步变量。13. 网络同步血条 打开Health脚本 添加命名空间UnityEngine.Networking usin...

quick cocos2d-x 实战:做一个手机横版格斗游戏3:游戏开始界面切图

首先切图,把所有的资源文件放在fight子目录下的res目录下。现在的图为了演示,所有的图都是单张的,但是在实际项目,这些单张的都会合并成一个大图,然后载入后,分别调用。打包工具,可以用texture...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:用 SpriteKit 做一个逃逸游戏 (3)
举报原因:
原因补充:

(最多只允许输入30个字)