【问题标题】:SKPhysicsContact is there any way to determine which body is A and B?SKPhysicsContact 有什么方法可以确定 A 和 B 是哪个身体?
【发布时间】:2016-11-05 08:38:20
【问题描述】:

在 SpriteKit 中,我们在 didBeginContact 方法中检测到 。 但这看起来有点愚蠢做这样的事情: func didBeginContact(contact: SKPhysicsContact) {

    if let contactA = contact.bodyA.node?.name {

        if let contactB = contact.bodyB.node?.name {

            //now that we have safely unwrapped these nodes, we can operate on them

            if contactA == "ball" {

                collisionBetweenBall(contact.bodyA.node!, object: contact.bodyB.node!)

            } else if contactB == "ball" {

                collisionBetweenBall(contact.bodyB.node!, object: contact.bodyA.node!)

            }

        }

    }

}

有什么方法可以确保 bodyA 始终是一个球?有没有与categorybitmask相关的规则?

【问题讨论】:

    标签: objective-c swift sprite-kit game-physics


    【解决方案1】:

    如果您使用简单的类别,每个物理体只属于一个类别,那么 didBeginContact 的这种替代形式可能更具可读性:

    func didBeginContact(contact: SKPhysicsContact) {
        let contactMask = contact.bodyA.categoryBitMask | contact.bodyB.categoryBitMask
    
    switch contactMask {
    
       case categoryBitMask.ball | categoryBitMask.something:
           print("Collision between ball and something")
           let ballNode = contact.bodyA.categoryBitMask == categoryBitMask.ball ? contact.bodyA.node! : contact.bodyB.node!
           ballNode.pop()
           score += 10
    
       default :
           //Some other contact has occurred
           print("Some other contact")
       }
    }
    

    请注意,如果您的类别更复杂,这将不起作用,因为简单的 AND 测试 (categoryBitMask.ball | categoryBitMask.something) 将不匹配。

    【讨论】:

    • 在多个联系人同时发生的情况下,此代码在某些情况下可能会崩溃。假设您有三个相交的对象。 SpriteKit 一次只能处理一个联系人。并假设您在与 B 或 C 类型的对象接触时从父对象(类型)A 中删除它。所以 didBeginContact 将被调用两次。如果您从其父对象 A 中删除对象 A,则在下一次 didBeginContact 调用中,强制展开将失败。你应该指出他不要像这样使用强制展开,因为节点属性可能是 nil ...否则,它应该工作并且它是可读的:)
    • @Whirlwind 这是否意味着if letguard 在这里有用?
    • @Confused 最有可能是让或守卫是的。甚至是可选的链接。只是为了防止潜在的崩溃。这可能会发生...
    • 我(最近)开始了解如何以及为什么使用if let,但还没有弄清楚guard。但我喜欢玩物理引擎,所以这看起来是一个很好的借口,可以有目的地找出如何在合理的位置进行操作。谢谢!!!
    • 深入研究了SKTemplate对if letcopy()SKShapeNodes的使用。当我意识到它确实在做两件事时,这是一个有见地的时刻。 1. 将可选项转换为同名的实际变量,以及 2. 提供在一个范围内做很多事情的机会。我还在为关闭该范围内的东西的好处吃午饭,就像史蒂夫的这个回答中发生的那样,我为 ballNode 分配放置了一个if let,然后它将包装 pop() 调用和除了分数变量。这是在这种情况下使用if let 的正确位置/想法吗?
    【解决方案2】:

    通常你会这样做

    首先,如果您还没有这样做,您将存储您的位掩码类别。

    enum PhysicsCategory {
         static let ball: UInt32 =  0x1 << 0
         static let wall: UInt32 =  0x1 << 1
         static let enemy: UInt32 = 0x1 << 2
    }
    

    然后像这样将它们分配给你的精灵

     ball.physicsBody?.categoryBitMask = PhysicsCategory.ball
     ball.physicsBody?.contactTestBitMask = PhysicsCategory.wall | PhysicsCategory.enemy
    
     wall.physicsBody?.categoryBitMask = PhysicsCategory.wall
     wall.physicsBody?.contactTestBitMask = 0 
    
     enemy.physicsBody?.categoryBitMask = PhysicsCategory.enemy
     enemy.physicsBody?.contactTestBitMask = 0 
    

    注意:因为在此示例中球会检查与墙壁和敌人的接触,所以您不需要告诉墙壁或敌人检查与球的接触。 可以在 1 个物理体上执行此操作,因此您可以在其他物理体上将其设置为 0,除非他们有其他特定联系人要查找。

    你可以在没有双重 if 语句的情况下在联系方法中检查它们。

    func didBegin(_ 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
        }
    
    
        // Ball hit wall or wall hit ball
        if (firstBody.categoryBitMask == PhysicsCategory.ball) && (secondBody.categoryBitMask == PhysicsCategory.wall) {
    
              // Some code
        }
    
        // Ball hit enemy or enemy hit ball
        if (firstBody.categoryBitMask == PhysicsCategory.ball) && (secondBody.categoryBitMask == PhysicsCategory.enemy) {
    
              // Some code
        }
    }
    

    此外,不要忘记在场景的 didMoveToView 中设置委托以使其正常工作。

    physicsWorld.contactDelegate = self
    

    希望对你有帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-10-09
      • 2019-08-07
      • 2012-11-03
      • 2021-03-16
      • 2018-06-27
      • 2012-07-03
      • 1970-01-01
      相关资源
      最近更新 更多