当玩家节点与另一个节点碰撞时游戏结束,当玩家与边界碰撞时游戏才应该结束

Posted

技术标签:

【中文标题】当玩家节点与另一个节点碰撞时游戏结束,当玩家与边界碰撞时游戏才应该结束【英文标题】:Game ends when player node collides with another node, when the game should only end when the player collides with the boundary 【发布时间】:2016-06-10 06:07:47 【问题描述】:

问题:一旦玩家节点接触到硬币节点,游戏就会在玩家与边界碰撞时结束。

输出应该是什么:玩家应该能够接触到硬币节点并穿过它,为 scoreLabel 添加一个值。 当前代码:

 struct ColliderType 

static let playerCategory: UInt32 = 0x1 << 0
static let boundary: UInt32 = 0x1 << 1
static let coinCategory: UInt32 = 0x1 << 2
static let firstBody: UInt32 = 0x1 << 3
static let secondBody: UInt32 = 0x1 << 4



   var gameOver = false
   var coinInt = 0

    coin.physicsBody?.categoryBitMask = ColliderType.coinCategory
    coin.physicsBody?.contactTestBitMask = ColliderType.playerCategory
    coin.physicsBody?.collisionBitMask = 0


    player.physicsBody?.categoryBitMask = ColliderType.playerCategory
    player.physicsBody?.contactTestBitMask = ColliderType.boundary | ColliderType.coinCategory
    player.physicsBody?.collisionBitMask = ColliderType.boundary

func didBeginContact(contact:SKPhysicsContact) 
    var firstBody: SKPhysicsBody
    var secondBody: SKPhysicsBody

    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask 
        firstBody = contact.bodyA
        secondBody = contact.bodyB


     else

        firstBody = contact.bodyB
        secondBody = contact.bodyA

    

    if firstBody.categoryBitMask == ColliderType.playerCategory && secondBody.categoryBitMask == ColliderType.coinCategory 
       self.coin.removeFromParent()
       coinInt += 1
       coinLabel.text = "\(coinInt)"
    

    gameOver = true
    self.speed = 0
    timer.invalidate()



override func touchesBegan(touches: Set<UITouch> , withEvent event: UIEvent?) 
    if gameOver == false 

    self.player.physicsBody?.velocity = CGVectorMake(1, 3)
    self.player.physicsBody?.applyImpulse(CGVectorMake(0, 12))

    


更新:

    boundary.contactTestBitMask = ColliderType.playerCategory
    boundary.categoryBitMask = ColliderType.boundary
    boundary.collisionBitMask = ColliderType.playerCategory

   coin.physicsBody?.categoryBitMask = ColliderType.coinCategory
   coin.physicsBody?.contactTestBitMask = ColliderType.playerCategory
   coin.physicsBody?.collisionBitMask = 0


    player.physicsBody?.categoryBitMask = ColliderType.playerCategory
    player.physicsBody?.contactTestBitMask = ColliderType.coinCategory
    player.physicsBody?.collisionBitMask = ColliderType.boundary




func didBeginContact(contact:SKPhysicsContact) 
    let firstBody: SKPhysicsBody
    let secondBody: SKPhysicsBody


    if contact.bodyA.categoryBitMask < contact.bodyB.categoryBitMask 
        firstBody = contact.bodyA
        secondBody = contact.bodyB


     else

        firstBody = contact.bodyB
        secondBody = contact.bodyA

    


    if firstBody.categoryBitMask == ColliderType.coinCategory || secondBody.categoryBitMask == ColliderType.coinCategory 

    self.coin.removeFromParent()
    self.coinInt += 1
    self.coinLabel.text = "\(self.coinInt)"

    else if firstBody.categoryBitMask == ColliderType.boundary || secondBody.categoryBitMask == ColliderType.boundary 

    gameOver = true
    self.speed = 0
    timer.invalidate()



【问题讨论】:

关于您的编辑:您的播放器不检查边界,而是相反的方式可能有意义。但是您可能根本不希望 播放器 检查任何联系人以简化事情。 【参考方案1】:

您的gameOver = true 语句位于 didBeginContact 中的所有 if 之外。换句话说:接触发生的那一刻,你设置 gameOver = true。

if firstBody.categoryBitMask == ColliderType.coinCategory || secondBody.categoryBitMask == ColliderType.coinCategory 
   self.coin.removeFromParent()
   coinInt += 1
   coinLabel.text = "\(coinInt)"
 else if firstBody.categoryBitMask == ColiderType.boundary || secondBody.categoryBitMask == ColiderType.boundary 
    gameOver = true
    self.speed = 0
    timer.invalidate()

可能更接近你想要的。

【讨论】:

您好,抱歉回复延迟。该代码看起来正是我需要的,但是当我测试它时,第一个 if 语句不起作用,但 else if 函数正常工作。我一直在修改我的代码,测试不同的方法,一切看起来都应该完美无缺,但第一个 if 语句目前不起作用。 其实你应该使用 if firstBody.categoryBitMask == ColliderType.coinCategory || secondBody.categoryBitMask == ColliderType.coinCategory 因为硬币只检查它是否与玩家接触。 我将第一个 if 语句替换为您提供的那个,我似乎注意到第一个 if 语句没有按应有的方式运行的任何更改。一秒钟,我将用我当前的代码更新我的问题。我仍在学习 swift,所以我非常感谢您迄今为止的帮助。【参考方案2】:

(添加一个新答案,因为它基于新代码,并且 O.P. 问题中的讨论/更改会使逻辑流程有点难以理解)

首先,我将对 physicBodies 进行以下更改:

player.physicsBody?.contactTestBitMask = 0 // or ColliderType.None which would be my stylistic choice

然后剩下的会是这样的。

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

    if firstBody.categoryBitMask == ColliderType.coinCategory || secondBody.categoryBitMask == ColliderType.coinCategory 
        self.coin.removeFromParent()
        self.coinInt += 1
        self.coinLabel.text = "\(self.coinInt)"
     else if firstBody.categoryBitMask == ColliderType.boundary || secondBody.categoryBitMask == ColliderType.boundary 
        gameOver = true
        self.speed = 0
        timer.invalidate()
    

注意事项: 从提供的代码中不清楚如何引用 self.coin。我self.coin.removeFromParent() 可能没有太大意义,因为您在最初的帖子中写了几个 硬币。它可能应该是这样的:

if contact.bodyA.categoryBitMask == ColliderType.coinCategory 
    contact.bodyA.node!.removeFromParent()
 else if contact.bodyB.categoryBitMask == ColliderType.coinCategory 
    contact.bodyB.node!.removeFromParent()

但我真的考虑如果您打算在此基础上进行扩展,则完全将整个联系人处理重新设计为不同的野兽。

【讨论】:

您提供的代码已经解决了这个问题,现在硬币碰撞功能完美无缺!感谢您的帮助!当我获得 15 名声望时,我将做一个笔记回到这篇文章,以便我可以投票给这个答案。【参考方案3】:

编写didBeginContact 的更简洁的方法是:

    func didBeginContact(contact: SKPhysicsContact) 
        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask

        switch contactMask 

        case ColliderType.playerCategory | ColliderType.coinCategory:
            // player and coin have contacted. We need to get the coin, which is either firstBody or secondBody,  to remove it, so assign the corect one to coinNode
            let coinNode = contact.bodyA.categoryBitMask == ColliderType.coinCategory ? contact.bodyA.node! : contact.bodyB.node!
             coinNode.removefromParent
             coinInt += 1
             coinLabel.text = "\(coinInt)"

        case ColliderType.playerCategory | ColliderType.boundaryCategory:
            // player and boundary have contacted
                gameOver = true
            self.speed = 0
            timer.invalidate()

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

您可以添加任意数量的case ColliderType.object1 | ColliderType.object2:

【讨论】:

唯一的问题是排除 2 个类别的对象 不确定这是不是真的,因为我们正在测试是否设置了类别中的某些位但掩码,而不是整个类别(至少,这是意图)。 player = 0001 , coin = 0010 superpower = 0100 如果节点因为拥有超能力而变成0101,那么player的情况|硬币失败是因为您将 0111 与 0011 进行比较,但您希望它通过,并且必须扩展到每个案例以实现此目标是荒谬的 是的 - 你是对的,但我想这是一个相当不寻常的情况。为此,我认为如果您在 contactMask 和要检查联系人的 2 个类别之间执行按位与运算,则非 0 结果意味着命中。 很确定我的代码中某处有一条关于我应该如何真正测试每一点的评论......我将此视为个人挑战。

以上是关于当玩家节点与另一个节点碰撞时游戏结束,当玩家与边界碰撞时游戏才应该结束的主要内容,如果未能解决你的问题,请参考以下文章

Swift SpriteKit 基本接触/碰撞

仅当玩家在 Y 轴上向上移动时才移动地面视差

SpriteKit中精灵之间的碰撞

添加炸弹数量,当玩家碰撞时不起作用

(转)CocosCreator零基础制作游戏《极限跳跃》九为游戏添加声音音效功能

玩家在与标记对象碰撞时消失