[英]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)我設置了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()
}
}
}
}
我需要檢查汽車何時觸及終點線以標記一圈並將圈數計數器增加 1。問題是我在nodeA
和nodeB
之間不斷收到來自此 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.