SpriteKit中有多个不同的碰撞问题(使用Xcode编写Objective-C的iOS应用程序)

我目前在Objective-C中构build一个iOS应用程序。 应用程序的想法是,你有某种types的火箭飞船通过一个小行星带。 它以纵向模式播放。 现在有两种不同的小行星。 正常的那些,当你撞到他们时会让你失去知觉,而那些金色的东西会被射到硬币上。

对于碰撞,我使用Ray Wenderlich SpriteKit教程中的代码。 类别是这样设置的:

static const uint32_t playerCategory = 0x1 << 0; static const uint32_t asteroidCategory = 0x1 << 1; 

运行的代码是这样的:

 - (void)player:(SKSpriteNode *)player didCollideWithAsteroid:(SKSpriteNode *)asteroid { [self runAction:[SKAction playSoundFileNamed:@"Explosion.mp3" waitForCompletion:NO]]; NSLog(@"Hit"); [self.player removeFromParent]; [asteroid removeFromParent]; SKAction *actionMoveDone = [SKAction removeFromParent]; SKAction * loseAction = [SKAction runBlock:^{ SKTransition *reveal = [SKTransition crossFadeWithDuration:0.5]; SKScene * gameOverScene = [[GameOverScene alloc] initWithSize:self.size won:NO]; [self.view presentScene:gameOverScene transition: reveal]; }]; [self.asteroid runAction:[SKAction sequence:@[loseAction, actionMoveDone]]]; } 

碰撞检测代码是这样的:

 - (void)didBeginContact:(SKPhysicsContact *)contact { // 1 SKPhysicsBody *firstBody, *secondBody; if (contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask) { firstBody = contact.bodyA; secondBody = contact.bodyB; } else { firstBody = contact.bodyB; secondBody = contact.bodyA; } // 2 if ((firstBody.categoryBitMask & playerCategory) != 0 && (secondBody.categoryBitMask & asteroidCategory) != 0) { [self player:(SKSpriteNode *)firstBody.node didCollideWithAsteroid:(SKSpriteNode *)secondBody.node]; } } 

像这样,一切都很好,玩家撞上小行星,探测到碰撞,声音效果起作用,“游戏结束”场景取代了当前的场景。

当我尝试添加另一种小行星时,问题就开始了。 对于类别,我尝试了很多东西,比如

 static const uint32_t playerCategory = 0x1 << 0; static const uint32_t asteroidCategory = 0x1 << 1; static const uint32_t bulletCategory = 0x1 << 2; static const uint32_t goldAsteroidCategory = 0x1 << 3; 

 static const uint32_t playerCategory = 0x1 << 0; static const uint32_t asteroidCategory = 0x1 << 1; static const uint32_t bulletCategory = 0x1 << 0; static const uint32_t goldAsteroidCategory = 0x1 << 1; 

乃至

 static const uint32_t playerCategory = 0x1 << 0; static const uint32_t asteroidCategory = 0x1 << 1; static const uint32_t bulletCategory = 1x1 << 0; static const uint32_t goldAsteroidCategory = 1x1 << 1; 

几乎所有我能想到的东西的组合。

子弹击中小行星时运行的代码如下:

 - (void)bullet:(SKSpriteNode *)bullet didCollideWithGoldAsteroid:(SKSpriteNode *)goldAsteroid { [self runAction:[SKAction playSoundFileNamed:@"ding.m4a" waitForCompletion:NO]]; NSLog(@"Hit"); [bullet removeFromParent]; [goldAsteroid removeFromParent]; [self plusOneCoin]; } 

碰撞检测代码是相同的,但是用一些小的编辑replace了与相关信息相冲突的信息。

出于某种原因,没有任何工作。 根据我使用的类别设置代码,也可以

  1. 当我遇到一个普通的小行星时,如果碰上了一颗黄金小行星,就没有任何事情发生(如预期的那样),但是当我射击一颗黄金小行星时,根本没有任何事情发生,而不是运行代码。
  2. 当我开枪的时候,我自动输了
  3. 当我开枪的时候,没关系,但是如果我击中任何小行星,我就输了。

我不确定发生了什么,所以任何帮助,将不胜感激。 如果我需要发布更多的代码或细节为你们提供帮助,我会很乐意这样做。

您的问题来自您在didBeginContact方法中处理联系人的方式。 处理联系人有几种方法。 一些简单和一些更复杂。 考虑这个更简单的方法:

 - (void)didBeginContact:(SKPhysicsContact *)contact { uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask); if (collision == (playerCategory | asteroidCategory)) { // do something } } 

你可以稍微复杂一些。 例如,你有两种types的小行星,但不希望每个类别都使用一个独特的类别,因为你受限于类别数量。 你可以通过给你的小行星添加一个名称属性来实现这个functionmyNode.name = @"GoodRock";myNode.name = @"BadRock"; 。 现在在你的联系方式中:

 - (void)didBeginContact:(SKPhysicsContact *)contact { uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask); if(collision == (playerCategory | asteroidCategory)) { if(([contact.bodyA.node.name isEqualToString:@"GoodRock"]) || ([contact.bodyB.node.name isEqualToString:@"GoodRock"])) { // do something } if(([contact.bodyA.node.name isEqualToString:@"BadRock"]) || ([contact.bodyB.node.name isEqualToString:@"BadRock"])) { // do something else } } } 

这使您只能为大量不同的小行星types使用一个联系人类别。

另外一种select是给每个小行星分配一个唯一的名字。 如果您需要确切知道哪颗小行星被击中,您可能需要这样做。 也许每隔一段时间你就为三重点创造一个“惊奇”的小行星,或者为每个小行星命中一个分手animation。

在这种情况下,你需要为每个小行星分配一个独特的名字,像这样:

 // create an int variable and +1 every time you create a new asteroid asteroidCounter++; [myNode setName:[NSString stringWithFormat:@"asteroid-%i", asteroidCounter]]; 

然后,您需要将您创build的每个新小行星存储在一个可变数组中:

 [asteroidArray addObject:myNode]; 

在联系方式你枚举数组是这样的:

 - (void)didBeginContact:(SKPhysicsContact *)contact { uint32_t collision = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask); if(collision == (playerCategory | asteroidCategory)) { for(SKSpriteNode *object in myArray) { if(([contact.bodyA.node.name isEqualToString:@"asteroid-3"]) || ([contact.bodyB.node.name isEqualToString:@"asteroid-3"])) { // do something to asteroid #3 } } } } 

如果使用最后一个选项,则需要记住从arrays中删除不再使用的任何节点(销毁,离屏等)。 如果你不这样做,它不会崩溃你的代码,但这是一个很好的习惯。 特别是如果你不断向arrays添加新的小行星。