上一節(6-4b)提到SceneKit物理模擬除了基本的力場與碰撞之外,還有兩個特殊應用,包括上一節的模擬關節,以及本節要介紹的模擬車輛。
相比於模擬關節,模擬車輛的程式複雜一些,也較容易出錯,網路上面可參考的資料或範例非常少(雖然此功能已發表10年),筆者經過不斷嘗試錯誤,終於寫出一個可正常運作的版本。
要做出模擬車輛,有幾個條件及步驟:
不過,按照原廠文件做出來的模擬車輛,通常像下面這樣,輪胎轉90°或甚至翻車(天啊,太危險了吧):
可見車身較單純,輪胎則有各式各樣問題。若要讓輪胎正常運作,解法之一是在車身與輪胎之間,多加一個節點「輪圈」(或輪軸、底盤等名稱),節點關係變成「車身 — 輪圈 — 輪胎」。程式碼如下:
let 輪胎 = SCNTorus(ringRadius: 0.5, pipeRadius: 0.2)
輪胎.materials = [金屬大理石]
let 輪胎節點 = SCNNode(geometry: 輪胎)
輪胎節點.rotation = SCNVector4(0, 0, 1, .pi / 2.0)
let 輪圈 = SCNBox(width: 0.3, height: 0.6, length: 0.6, chamferRadius: 0.1)
let 輪圈節點 = SCNNode(geometry: 輪圈)
輪圈節點.addChildNode(輪胎節點)
接下來再以此複製出四個車胎,注意其中用「輪圈節點.clone()」來複製節點(會包含子節點),透過SCNPhysicsVehicleWheel() 做出模擬輪胎,最後還要加上「物理輪胎.suspensionRestLength = 0.30」才不會翻車,suspensionRestLength 用來設定輪胎的懸吊系統。
var 四輪: [SCNPhysicsVehicleWheel] = []
for i in 0 ..< 4 {
let 新輪胎 = 輪圈節點.clone()
switch i {
case 0:
新輪胎.position = SCNVector3(1.2, 0, 2.0)
新輪胎.name = "左前輪"
case 1:
新輪胎.position = SCNVector3(-1.2, 0, 2.0)
新輪胎.name = "右前輪"
case 2:
新輪胎.position = SCNVector3(1.2, 0, -2.0)
新輪胎.name = "左後輪"
case 3:
新輪胎.position = SCNVector3(-1.2, 0, -2.0)
新輪胎.name = "右後輪"
default:
新輪胎.position = SCNVector3Zero
}
車身節點.addChildNode(新輪胎)
let 物理輪胎 = SCNPhysicsVehicleWheel(node: 新輪胎)
物理輪胎.suspensionRestLength = 0.30
四輪.append(物理輪胎)
}
車身與四個輪胎都準備好之後,就可以用SCNPhysicsVehicle()組成車輛:
let 四輪車 = SCNPhysicsVehicle(chassisBody: 車身節點.physicsBody!, wheels: 四輪)