上一節(6-4b)提到SceneKit物理模擬除了基本的力場與碰撞之外,還有兩個特殊應用,包括上一節的模擬關節,以及本節要介紹的模擬車輛。

相比於模擬關節,模擬車輛的程式複雜一些,也較容易出錯,網路上面可參考的資料或範例非常少(雖然此功能已發表10年),筆者經過不斷嘗試錯誤,終於寫出一個可正常運作的版本。

要做出模擬車輛,有幾個條件及步驟:

  1. 先設計車身節點,啟動物理模擬,設為動態(dynamic)本體
  2. 加入一個或多個輪胎節點,並設為車身的子節點
  3. 輪胎節點無需設定物理模擬,只要透過SCNPhysicsVehicleWheel()設定即可
  4. 車身與輪胎一起加入SCNPhysicsVehicle(),以產出模擬車輛
  5. 最後將模擬車輛透過addBehavior()加入場景的物理世界(physicsWorld)

不過,按照原廠文件做出來的模擬車輛,通常像下面這樣,輪胎轉90°或甚至翻車(天啊,太危險了吧):

Apr-29-2024 22-52-48.gif

Apr-30-2024 10-06-49.gif

可見車身較單純,輪胎則有各式各樣問題。若要讓輪胎正常運作,解法之一是在車身與輪胎之間,多加一個節點「輪圈」(或輪軸、底盤等名稱),節點關係變成「車身 — 輪圈 — 輪胎」。程式碼如下:

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: 四輪)