【问题标题】:How to setup collisions correctly in SceneKit?如何在 SceneKit 中正确设置碰撞?
【发布时间】:2020-08-17 16:06:29
【问题描述】:

我遇到了碰撞检测问题。

当前设置

1) 我用SCNPhysicsContactDelegate 扩展了ViewController 类:

class ViewController: UIViewController, SCNPhysicsContactDelegate

2) 我设置了一个 OptionSet 来管理碰撞类别:

// Collisions
struct CollisionCategory: OptionSet {
    let rawValue: Int

    static let CoinsCategory = CollisionCategory(rawValue: 0)        // Coin SCNNode
    static let CarCategory = CollisionCategory(rawValue : 1)         // Car SCNNode
    static let FinishLineCategory = CollisionCategory(rawValue: 2)   // FinishLine SCNNode
}

3) 我设置了categoryBitMaskcontactTestBitMaskcollisionBitMask,所有这些:

// Setup car
carNode.physicsBody?.categoryBitMask = CollisionCategory.CarCategory.rawValue
carNode.physicsBody?.contactTestBitMask = CollisionCategory.CoinsCategory.rawValue | CollisionCategory.FinishLineCategory.rawValue
carNode.physicsBody?.collisionBitMask = CollisionCategory.CoinsCategory.rawValue | CollisionCategory.FinishLineCategory.rawValue

// Setup finishLine
planeNode.physicsBody?.categoryBitMask = CollisionCategory.FinishLineCategory.rawValue
planeNode.physicsBody?.contactTestBitMask = CollisionCategory.CarCategory.rawValue
planeNode.physicsBody?.collisionBitMask = CollisionCategory.CarCategory.rawValue

// Setup coin
coin.physicsBody?.categoryBitMask = CollisionCategory.CoinsCategory.rawValue
coin.physicsBody?.contactTestBitMask = CollisionCategory.CarCategory.rawValue
coin.physicsBody?.collisionBitMask = CollisionCategory.CarCategory.rawValue

4) 我设置physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) 来管理碰撞发生时:

func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
    if(contact.penetrationDistance >= 0.08 && contact.nodeB.name!.contains("Coin")) {
        // Remove coin from parent
        contact.nodeB.removeFromParentNode()
        // Increment counter
        self.coinsCounter += 1
        DispatchQueue.main.async {
            // Increase coin counter
            let view = self.arSceneView.viewWithTag(10) as! UILabel
            view.text = String(self.coinsCounter)
        }
    }

    // PROBLEMS HERE
    if(contact.penetrationDistance >= 0.076 && contact.nodeB.name!.contains("FinishLine") && !self.startFinishLineCollision && !self.outOfTrack) {
        self.startFinishLineCollision = true

        // Increment lap
        if(seconds > 10) {
            self.laps += 1
            DispatchQueue.main.async {
                (self.arSceneView.viewWithTag(14) as! UILabel).text = String(self.laps)
            }

            if(self.laps == 4){
                endGame()
            }
        }
    }
}

问题

我需要检查汽车何时触及终点线以标记一圈并将圈数计数器增加 1。问题是我在 nodeAnodeB 之间不断收到来自此函数的联系消息,即使有是汽车和终点线之间没有碰撞。

例如,下图中有一条碰撞消息,但汽车和终点线之间没有有效的碰撞。

当前设置有什么问题?

我需要什么

我需要精确检查汽车和终点线之间是否发生碰撞。

谢谢


更新

我也尝试了以下设置,但没有解决方案...

let CoinsCategory = 2
let CarCategory = 4
let FinishLineCategory = 6

carNode.physicsBody?.categoryBitMask = CarCategory
carNode.physicsBody?.collisionBitMask = CoinsCategory | FinishLineCategory

planeNode.physicsBody?.categoryBitMask = FinishLineCategory
planeNode.physicsBody?.collisionBitMask = CarCategory

coin.physicsBody?.categoryBitMask = CoinsCategory
coin.physicsBody?.collisionBitMask = CarCategory

func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
    switch contact.nodeB.physicsBody!.collisionBitMask {
        case FinishLineCategory:
            print("Finish Line Collision")
        case CoinsCategory:
            print("Coin Collision")
        default:
            print("Other collision")
    }
}

没有调用打印...就像对象之间没有碰撞一样。

注意: 终点线、汽车和硬币都是同一父级(它们下方的平面)上的子级。有关系吗?

【问题讨论】:

  • 你的FinishLineCategory不应该是8而不是6吗?

标签: ios swift collision-detection scenekit arkit


【解决方案1】:

好的,我找到了解决我的问题的解决方法:

1) 我使用硬币(黄色立方体)作为对撞机。

2) 我用Color.clear(透明颜色)设置它,使其不可见。

3) 我把它放在终点线的中心。

4)由于contactTest不工作,我使用penetrationDistance

func physicsWorld(_ world: SCNPhysicsWorld, didBegin contact: SCNPhysicsContact) {
    if(contact.penetrationDistance >= 0.08 && contact.nodeB.name! == "Coin") {
        // Remove coin from parent
        contact.nodeB.removeFromParentNode()
        // Increment counter
        self.coinsCounter += 1
        DispatchQueue.main.async {
            // Increase coin counter
            let view = self.arSceneView.viewWithTag(10) as! UILabel
            view.text = String(self.coinsCounter)
        }
    }



    // >>>>> NEW CODE HERE! <<<<<
    if(contact.penetrationDistance > 0.078 && contact.nodeB.name! == "CoinFinishLine" && !self.outOfTrack && !self.lapIncrement) {

        self.lapIncrement = true

        // Start lap increment timer (5 seconds)
        self.startNSecondsTimer(howMuchTime: 1.0, target: 1)

        // Increment lap
        if(seconds > 10) {
            self.laps += 1
            DispatchQueue.main.async {
                (self.arSceneView.viewWithTag(14) as! UILabel).text = String(self.laps)
            }

            if(self.laps == 3){
                endGame()
            }
        }
    }
}

无论如何,如果有人能解释我为什么我不能让contactTestBitMask 工作并且我只能使用collisionBitMask 这个解决方案是受欢迎的。谢谢

【讨论】:

    猜你喜欢
    • 2015-02-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-07
    • 1970-01-01
    • 1970-01-01
    • 2018-06-09
    • 2023-04-09
    相关资源
    最近更新 更多