当射弹击中两个 "monsters" 时,didBeginContact 方法崩溃。我知道为什么,但我不知道如何避免

When projectile hits two "monsters" the didBeginContact method crashes. I know why but i don't know how to avoid it

所以我从教程中得到了这段代码:

func didBeginContact(contact: SKPhysicsContact) {

    // 1
    var firstBody: SKPhysicsBody?
    var secondBody: SKPhysicsBody?
    var body: SKPhysicsBody

    //contact.bodyB.node!.physicsBody!.allContactedBodies().count


        if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask {
            firstBody = contact.bodyA
            secondBody = contact.bodyB
            println("1 = A, 2 = B")
        } else {
            firstBody = contact.bodyB
            secondBody = contact.bodyA
            println("2 = A, 1 = B")
        }



        // 2
        if ((firstBody!.categoryBitMask & PhysicsCategory.Monster != 0) &&
            (secondBody!.categoryBitMask & PhysicsCategory.Projectile != 0)) {

                for var c = 1; c <= contact.bodyB.node!.physicsBody!.allContactedBodies().count; c++ {
                    projectileDidCollideWithMonster(firstBody!.node as! SKSpriteNode, monster: secondBody!.node as! SKSpriteNode)

                }
                secondBody!.node?.removeFromParent()
        }
}

func projectileDidCollideWithMonster(projectile:SKSpriteNode, monster:SKSpriteNode) {
    println("Hit")
    changeScore(1)
    changeAmo(true)
    projectile.removeFromParent()
    monster.removeFromParent()
}

然后发生的事情是,一个弹丸有时会同时击中两个怪物。

发生这种情况时 - didBeginContact 方法崩溃并提示 secondBody 为零。

经过深入研究,我找到了原因:

当射弹同时与其他两个节点碰撞时 - 此方法 运行s 两次。在第一个 运行 之后 - 如果将 bodyA 作为射弹,将 bodyB 作为怪物 - 将它们传递给 projectileDidCollideWithMonster 并将它们都移除。然后它又立即 运行s 但在那一刻抛射物不再存在并且它崩溃无法分配它的节点。

我不知道如何克服这个问题:(请问有什么建议吗?

解决方案:感谢以下想法,我做了一些更改。

在 class:

的顶部添加了数组和触发器
    var bodiesToBeRemoved = [SKSpriteNode]()
    var shouldRemoveBodies = false

并做了这些修改:

 func projectileDidCollideWithMonster(projectile:SKSpriteNode, monster:SKSpriteNode) {
 /* Called when collisions is detected and collided nodes are passed to it */
    //score and stuff
    println("Hit")
    changeScore(1)
    changeAmo(true)

    //collect the nodes to be removed
    bodiesToBeRemoved.append(projectile)
    bodiesToBeRemoved.append(monster)

    //change the trigger to remove collected nodes later on
    shouldRemoveBodies=true

}

override func update(currentTime: CFTimeInterval) {
    /* Called before each frame is rendered */

    //check the trigger
    if shouldRemoveBodies == true {
        println("\(bodiesToBeRemoved.count)")
        //remove collected nodes
        for var i = 0; i<bodiesToBeRemoved.count; i++ {
            bodiesToBeRemoved[i].removeFromParent()
        }

        //reset array
        bodiesToBeRemoved.removeAll(keepCapacity: false)

        //reset the trigger
        shouldRemoveBodies = false
    } else {
        //do nothing:)
    }

}

不要立即移除你的抛射物,只需将其标记为移除(例如,通过设置布尔标志,或者将其添加到某个集合(如果它不在集合中)。然后稍后,在下一次物理检查之前(例如在此帧的末尾),检查并移除所有标记为移除的射弹。

只检查它是否为零比检查每个节点的标记更好。

func removeNodeFromPhysicsBody(ps: SKPhysicsBody){
    if (ps.node != nil){
        ps.node?.removeFromParent()
    }
}

func wallDidCollideWithMeteor(wall:SKPhysicsBody, meteor:SKPhysicsBody) {
    removeNodeFromPhysicsBody(wall)
    removeNodeFromPhysicsBody(meteor)
}