簡體   English   中英

如何在 SceneKit 中正確設置碰撞?

[英]How to setup collisions correctly in SceneKit?

我正面臨碰撞檢測的問題。

當前設置

1)我用 SCNPhysicsContactDelegate 擴展了ViewController SCNPhysicsContactDelegate

class ViewController: UIViewController, SCNPhysicsContactDelegate

2)我設置了一個選項集來管理碰撞類別:

// 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之間不斷收到來自此 function 的聯系消息,即使汽車和終點之間沒有碰撞線。

例如,在下圖中有一條碰撞消息,但汽車和終點線之間沒有有效的碰撞。

碰撞

當前設置有什么問題?

我需要的

我需要精確檢查汽車和終點線之間是否存在碰撞。

謝謝


更新

我也嘗試了以下設置,但沒有解決方案...

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")
    }
}

沒有調用打印...就像對象之間沒有碰撞一樣。

注意:終點線、汽車和硬幣都是同一父級(它們下方的平面)上的子級。 是否相關?

好的,我找到了解決我的問題的解決方法:

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是受歡迎的。 謝謝

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM