SpriteKit Swift: 当 bodyA 同时与多个 body 碰撞时如何防止崩溃?

SpriteKit Swift: How to prevent a Crash when bodyA collisions with more than one bodyB at the same time?

情况:

已经广泛搜索,没有找到解决方案。

例如,这没有帮助:Swift/SpriteKit Multiple Collision Detection?

问题:

我的代码工作正常,除非玩家同时击中两个不同的 PhysicsCategory 对象(例如,掉落并同时准确击中地面和墙壁)。这会使我的应用程序崩溃。


代码:

struct PhysicsCategory {
    static let player: UInt32 = 0x1 << 1
    static let ground: UInt32 = 0x1 << 2
    static let wall: UInt32 = 0x1 << 3
    static let scoreWall: UInt32 = 0x1 << 4
}

func didBeginContact(contact: SKPhysicsContact) {
    let firstBody = contact.bodyA
    let secondBody = contact.bodyB

    if firstBody.categoryBitMask == PhysicsCategory.scoreWall && secondBody.categoryBitMask == PhysicsCategory.player || firstBody.categoryBitMask == PhysicsCategory.player && secondBody.categoryBitMask == PhysicsCategory.scoreWall {

        score += 1
        scoreLabel.text = "\(score)"

        updatePlayerColor()

    }

    else if firstBody.categoryBitMask == PhysicsCategory.wall && secondBody.categoryBitMask == PhysicsCategory.player || firstBody.categoryBitMask == PhysicsCategory.player && secondBody.categoryBitMask == PhysicsCategory.wall {

        lost = true

        self.scene?.speed = 0

        gameVC?.dismissViewControllerAnimated(false, completion: nil)

        //playDeathAnimation with completion block self.dismiss(VC)
    }

    else if firstBody.categoryBitMask == PhysicsCategory.ground && secondBody.categoryBitMask == PhysicsCategory.player || firstBody.categoryBitMask == PhysicsCategory.player && secondBody.categoryBitMask == PhysicsCategory.ground {

        lost = true

        self.scene?.speed = 0

        gameVC?.dismissViewControllerAnimated(false, completion: nil)

        //playDeathAnimation with completion block self.dismiss(VC)
    }
}

调试器错误:

致命错误:索引超出范围。

我要找的是:

我只想知道我的代码中是否已经考虑了双重碰撞。调试器错误是指我的代码中受冲突影响的其他部分。但是这里添加的代码太多了。所以请只回答以下问题:如何解释我的 SpriteKit 游戏中 ScoreWall 和 Wall 之间的双重碰撞?

试试这样的东西?它应该删除您的代码重复并防止您的游戏结束逻辑发生两次。

func didBeginContact(contact: SKPhysicsContact) {
    if (lost) {
        return
    }
    var a = contact.bodyA.categoryBitMask
    var b = contact.bodyB.categoryBitMask
    if a > b {
        swap(&a, &b)
    }

    if a == PhysicsCategory.player && b == PhysicsCategory.scoreWall {

        score += 1
        scoreLabel.text = "\(score)"

        updatePlayerColor()

    } else if a == PhysicsCategory.player && (b == PhysicsCategory.ground || b == PhysicsCategory.wall) {

        lost = true

        self.scene?.speed = 0

        gameVC?.dismissViewControllerAnimated(false, completion: nil)

        //playDeathAnimation with completion block self.dismiss(VC)
    }
}

你遇到了什么错误?

无论如何,你可能要等到物理模拟结束后才能删除重要部分(不知道你的应用程序的整个逻辑)。因此在碰撞检测中设置 lost 布尔条件是好的,但其余的可能必须在 didSimulatePhysicsdidFinishUpdate.

中完成

您没有发生双重碰撞。你将有 2 次单次碰撞,即 didBeginContact 将被调用一次用于玩家与地面之间的碰撞,再次用于玩家与墙壁之间的碰撞。一个 SKPhysicsContact 只能有 2 个主体。您的崩溃是由其他原因引起的,可能是由于删除了 gameVC?

有关 didBeginContact 的 'cleaner' 版本的示例,试试这个:

 func didBeginContact(contact: SKPhysicsContact) {

        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

        switch contactMask {
        // If the player and the scoreWall have collided:
        case .player | .scoreWall :
           score += 1
           scoreLabel.text = "\(score)"
           updatePlayerColor()

        // If the player and the wall have collided:
        case .player | .wall :
           lost = true
           self.scene?.speed = 0
           gameVC?.dismissViewControllerAnimated(false, completion: nil)

        // If the player and the ground have collided:
        case .player | .ground :
           lost = true
           self.scene?.speed = 0
           gameVC?.dismissViewControllerAnimated(false, completion: nil)

        default :
           print("Some other contact has occurred")
        }