Как правильно настроить коллизии в SceneKit? - PullRequest
0 голосов
/ 03 мая 2020

У меня проблема с обнаружением столкновений.

Текущая настройка

1) Я расширил ViewController класс с SCNPhysicsContactDelegate:

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) Я настраиваю categoryBitMask, contactTestBitMask и collisionBitMask для всех из них:

// 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()
            }
        }
    }
}

Проблема

Мне нужно проверить, когда машина касается линии Fini sh, чтобы отметить круг и увеличить счетчик кругов на 1. Проблема в том, что я получаю непрерывные сообщения о контактах от этой функции между nodeA и nodeB, даже если нет столкновения между автомобилем и линией Fini sh.

Например, в На следующем изображении есть сообщение о столкновении, но не существует эффективного столкновения между автомобилем и линией Fini sh.

collision

Что не так с текущей настройкой?

Что мне нужно

Мне нужно проверить, нет ли столкновения между автомобилем и финишной чертой с Точность.

Спасибо


Обновление

Я тоже попробовал следующую настройку без решения ...

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 Ответ

0 голосов
/ 04 мая 2020

Хорошо, я нашел способ обойти мою проблему:

1) Я использовал монету (желтый куб) в качестве коллайдера.

2) Я установил ее с Color.clear (прозрачный цвет) таким образом, чтобы сделать его невидимым.

3) Я поместил его в центр линии Fini sh.

4) Поскольку contactTest не работает, я used 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 с этим решением, приветствуется. Спасибо

...