【问题标题】:I'm having an issue detecting multiple different collisions in SpriteKit (Obj-C)我在检测 SpriteKit (Obj-C) 中的多个不同碰撞时遇到问题
【发布时间】:2015-08-26 19:49:04
【问题描述】:

我正在使用 Objective-C 和 SpriteKit 构建游戏。在这个游戏中,有小行星落在玩家身上,玩家必须避开它们。小行星每 0.5 秒生成一次。还有另一种类型的小行星,“黄金小行星”,它在游戏中使用不同的变量,可以射击以获得金币。

游戏的另一部分是购买新的“船”来穿越小行星。一艘船具有能够射击普通小行星以摧毁它们以及金色小行星的特殊能力。这就是问题的开始。

这是检测常规小行星和子弹之间碰撞的代码。很多代码来自 Sangony 在this StackOverflow 帖子上的回答。

NSString *playerImage = [[NSUserDefaults standardUserDefaults]
                         stringForKey:@"playerImage"];

if ([playerImage  isEqual: @"crazyben.png"]) //make sure the ship is the one with the special ability to destroy regular asteroids, not where the issue is
{
    NSLog(@"Crazy Ben Enabled");
    uint32_t collision3 = (contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask);

    if (collision3 == (bulletCategory | asteroidCategory))
    {
        NSLog(@"collision3");
        for (SKSpriteNode * object in self.asteroidArray);
        {
            NSLog(@"for statement");
            if ([contact.bodyA.node.name
                  isEqualToString:[NSString stringWithFormat:@"asteroid-%i", self.asteroidCounter]] ||[contact.bodyB.node.name isEqualToString:[NSString stringWithFormat:@"asteroid-%i", self.asteroidCounter]]) //broken here, it only allows you to detect a collision between the bullet and the asteroid that currently matches up to the "self.asteroidCounter" int
            {
                NSLog(@"crazyhit");
                [self runAction:[SKAction playSoundFileNamed:@"gunshot.mp3" waitForCompletion:NO]];
                [self.bullet removeFromParent];
                [self.asteroid removeFromParent];
            }
        }

    }
}

损坏的部分是需要检测碰撞的部分。使用此代码,您只能摧毁与 self.asteroidCounter 整数对应的小行星,它是最近生成的小行星。如果我删除该行

NSLog(@"for statement");
            if ([contact.bodyA.node.name
                  isEqualToString:[NSString stringWithFormat:@"asteroid-%i", self.asteroidCounter]] ||[contact.bodyB.node.name isEqualToString:[NSString stringWithFormat:@"asteroid-%i", self.asteroidCounter]])

允许它摧毁小行星,无论它是否与 self.asteroidCounter 具有相同的编号,而不是摧毁被击中的特定小行星,它似乎只是简单地摧毁屏幕上的随机小行星。

我想要的是将实际被击中的小行星从父级中移除。

提前致谢,如果有任何信息缺失或您需要澄清,我很乐意补充或澄清。

编辑:我编辑了代码,并通过 J. asteroidCounterB = asteroidCounterA - 1、asteroidCounterC = asteroidCounterB - 1 等添加了 asteroidCounter B 的变量。有了这个,我得到的行为与我以相同的名称对待它们时相同,而不是使用 asteroidCounter 变量来识别它们。现在我认为问题出在代码中

[self.asteroid removeFromParent];

当它这样做时,它不会从父级移除特定的小行星,它只是从父级移除其中一个。如果我删除所有 asteroidCounter 变量(除了原始变量),有没有办法可以这样说?

[self.asteroid-%i removeFromParent];

显然,这不起作用,但如果有办法获得类似的东西,那就太好了。

【问题讨论】:

  • 你试过创建 2 个数组吗?一颗用于普通小行星,一颗用于黄金小行星。这可能会使您的代码更易于处理。
  • @sangony 好吧,黄金小行星实际上并不需要一个阵列,它实际上是一个与普通小行星完全不同的东西。由于屏幕上一次只有一个金色的,我没有与普通的相同的问题。对于常规的,屏幕上会同时显示许多,而不是删除被击中的那个,它只是以一种看起来相当随机的方式删除一个。
  • 我认为您对我为什么建议为每个节点使用唯一名称感到困惑。您应该循环遍历小行星阵列并查看哪个小行星与所接触小行星的名称匹配。
  • @sangony 你觉得你能告诉我具体怎么做吗?我希望每个小行星都有一个唯一的名称,这样我就能够确定哪颗小行星被击中,并摧毁那个特定的小行星。

标签: ios objective-c sprite-kit


【解决方案1】:

如果您要为每个节点使用唯一的名称,一种简单的方法是在名称的末尾添加一个数字。

self.objectID++;
myNode.name = [NSString stringWithFormat:@"myNode-%lu",self.objectID];

self.object 是一个属性@property (nonatomic) long objectID;

要检查您的哪些“myNode”对象涉及碰撞,您可以这样做:

if (collision == (bulletCategory | asteroidCategory)) {

    for(SKSpriteNode *object in self.asteroidArray) {
        if(([object.name isEqualToString:contact.bodyB.node.name]) || ([object.name isEqualToString:contact.bodyA.node.name])) {
                // your code
        }
    }
}

【讨论】:

  • 这似乎与我当前使用的代码相同,但具有不同的变量和 long 而不是整数。在这里使用 long 而不是 int 会有所不同吗?
  • @JustMe - 代码类似,在这种情况下使用 long 而不是 int 并没有什么不同。代码中的行: ** if ([contact.bodyA.node.name isEqualToString:[NSString stringWithFormat:@"asteroid-%i", self.asteroidCounter]] ||[contact.bodyB.node.name isEqualToString:[ NSString stringWithFormat:@"asteroid-%i", self.asteroidCounter]]) ** 只检查是否与最近创建的小行星发生碰撞。
【解决方案2】:

单独测试每个不同的案例更容易。首先像您已经完成的那样设置不同的静态类别位掩码

static const uint32_t normalAstroidCategory = 0x1 << 0;
static const uint32_t goldAstroidCategory = 0x1 << 1;
static const uint32_t normalBullets = 0x1 << 2;
static const uint32_t specialBullets = 0x1 << 3;

然后确保您设置正确的项目符号具有正确的contactTestBitMasks以及CategoryBitMasks。

//Code used for special bullets
specialBullet.categoryBitMask = specialBullet;
specialBullet.contactTestBitMask = normalAstroidCategory | goldAstroidCategory
//Code used for normal bullets
normalBullet.categoryBitMask = normalBullet;
normalBullet.contactTestBitMask = normalAstroidCategory

确保您还为 astroids 设置了正确的位掩码

-(void)didBeginContact:(SKPhysicsContact*)contact{
    if (contact.bodyA == normalBullets || contact.bodyB == normalBullets 
        || contact.bodyA == specialBullets || contact.bodyB == specialBullets)
    {
        if (contact.bodyA.categoryBitMask == goldAstroidCategory || contact.bodyB.categoryBitMask == goldAstroidCategory){
            gold++;
        }
    }
}

如果您担心飞船也会与小行星相撞,您可能需要添加额外的逻辑。还可以尝试在 NSUserDefaults 中保存船舶类型而不是图像名称,因为它更可靠,或者使用枚举来查看船舶是否属于某种类型

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-30
    • 1970-01-01
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多