Swift 3 我的游戏结束代码无法正常工作

Swift 3 my game over code doesn't work correctly

如果我触摸除了按钮之外的游戏就会崩溃。我能做什么?如何?我想忽略按钮以外的所有触摸。我怎样才能做到这一点? 这是我的 touchesBegan:

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    if let location = touch?.location(in: self),
        let node = self.nodes(at: location).first {

        var player = SKSpriteNode()

        if node.name == "BlueButton" {
            player = playerB
            playerB.isHidden = false

        } else if node.name == "RedButton" {
            player = playerR
            playerR.isHidden = false

        } else if node.name == "YellowButton" {
            player = playerY
            playerY.isHidden = false

        } else if node.name == "GreenButton" {
            player = playerG
            playerG.isHidden = false

        }
        for sprite in [playerB, playerW, playerR, playerY, playerG] {
            sprite?.removeFromParent()
        }
        player.position = CGPoint(x: 0, y: -60)
        addChild(player)
    }

}

这是我的 touchesEnded 函数

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
    addChild(playerW)
    playerB.removeFromParent()
    playerR.removeFromParent()
    playerY.removeFromParent()
    playerG.removeFromParent()

}

我觉得这个条件

if firstBody.node?.name == "BLUE" && secondBody.node?.name == "BLUEBLOCK" ||
   firstBody.node?.name == "RED" && secondBody.node?.name == "REDBLOCK" ||
   firstBody.node?.name == "YELLOW" && secondBody.node?.name == "YELLOWBLOCK" &&
   firstBody.node?.name == "GREEN" && secondBody.node?.name == "GREENBLOCK"

应该看起来像

if (firstBody.node?.name == "BLUE" && secondBody.node?.name == "BLUEBLOCK") ||
   (firstBody.node?.name == "RED" && secondBody.node?.name == "REDBLOCK") ||
   (firstBody.node?.name == "YELLOW" && secondBody.node?.name == "YELLOWBLOCK") ||
   (firstBody.node?.name == "GREEN" && secondBody.node?.name == "GREENBLOCK")

它看起来还是很丑,但必须工作

好吧,坦白说有点乱,尤其是 didBeginContact 函数。如果我没看错你的意图,它应该是这样的:

  • 与 "white" 方块的任何接触都应该结束游戏。
  • 对于除 一个 之外的所有其他颜色的接触,特定颜色应该结束游戏。
  • 联系特定颜色应该增加分数。

如果这确实是我们的目标,那么像下面这样的东西应该可以工作,尽管我仍然建议进一步重构以避免将 game-logic 的如此重要的部分基于 flakey string-matching:

func didBegin(_ contact: SKPhysicsContact) {
    guard let nodeA = contact.bodyA.node else { 
        // this and the one blow are good places to add a breakpoint to inspect what's going on if still having problems
        return 
    }  
    guard let nodeB = contact.bodyB.node else { 
         return 
    }

    // Some Bools to make the below logic more readable
    let blueContacted = nodeA.name == "BLUEBLOCK" || nodeB.name == "BLUEBLOCK"
    let redContacted = nodeA.name == "REDBLOCK" || nodeB.name == "REDBLOCK"
    let yellowContacted = nodeA.name == "YELLOWBLOCK" || nodeB.name == "YELLOWBLOCK"
    let greenContacted = nodeA.name == "GREENBLOCK" || nodeB.name == "GREENBLOCK"

    var removableNodeName: String?

    if blueContacted && yellowContacted {
        removableNodeName = "YELLOWBLOCK"
    } else if redContacted && greenContacted {
        removableNodeName = "GREENBLOCK"
    } else if yellowContacted && blueContacted {
        removableNodeName = "BLUEBLOCK"
    } else if greenContacted && redContacted {
        removableNodeName = "REDBLOCK"
    }

    if let nodeName = removableNodeName {
        score += 1
        scoreLabel?.text = "\(score)"
        if nodeA.name == nodeName {
            nodeA.run(SKAction.move(to: CGPoint(x: 0 , y: 360), duration: 0.3))
            nodeA.run(SKAction.fadeOut(withDuration: 0.3))
        } else {
            nodeB.run(SKAction.move(to: CGPoint(x: 0 , y: 360), duration: 0.3))
            nodeB.run(SKAction.fadeOut(withDuration: 0.3))
        }
    } else { // Any other contact means game over
        nodeA.removeFromParent()
        nodeB.removeFromParent()
        score = 0
        scoreLabel?.text = "\(score)"
        gameOver()
    }
}

编辑:添加了一些守卫以根据下面的讨论检查 physicsBodies 上是否存在节点。

根据我在其他回答中的讨论,我 猜测 您的 touchesBegan 的复杂性导致您偶尔会添加多个版本的 player-sprite .下面应该只添加每个 playerSprite 一次 并且一次只添加 一个 这应该可以更容易地避免由于精灵覆盖精灵等而导致的意外接触。 ..

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let touch = touches.first
    if let location = touch?.location(in: self),
        let node = self.nodes(at: location).first {

        var player = SKSpriteNode()

        if node.name == "BlueButton" {
            player = playerB
        } else if node.name == "RedButton" {
            player = playerR
        } else if node.name == "YellowButton" {
            player = playerY
        } else if node.name == "GreenButton" {
            player = playerG
        }
        for sprite in [playerB, playerW, playerR, playerY, playerG] {
            sprite.removeFromParent()
        }
        player.position = CGPoint(x: 0, y: -50)
        addChild(player)
    }
}