去(2024)年更新的 RealityView 讓 iOS/iPadOS/macOS 也能像 visionOS 一樣,輕鬆寫出空間運算或AR程式,其中關鍵之一,就是能與 SwiftUI 緊密結合,尤其在手勢控制,比原先的 ARView + UIKit 好用多了。

所有App遊戲都會有些物體或角色讓使用者控制,這也是遊戲之所以好玩的關鍵:讓使用者能參與互動。而SwiftUI 的優勢之一,就是易用的控制視圖與手勢 。

設想一幕遊戲場景:當看到怪物從海底漂浮上來時,用手勢釋放深水炸彈將它炸死。

此處先借用上一節模型,將正十二面體當作炸彈,一開始放在上方靜止氣泡裡面,當滑鼠或手勢點選氣泡時,釋放正十二面體,讓它往下掉,與下方漂浮上來的氣泡碰撞(碰撞後的處理,待下一節介紹)。

效果如下,為了方便觀察,將上升氣泡的速度從原來0.6m/sec降為0.3m/sec:

https://youtu.be/szWKd4hIp1s

影片後半段,當滑鼠游標移到靜止氣泡時,會稍微變亮,這是另一個元件,「懸浮效果元件」(HoverEffectComponent)的功能,只對 macOS 有效,從影片中可看出,這個元件也會影響子個體,當游標移到正十二面體時,同樣會變亮。

氣泡模型.components.set(HoverEffectComponent())  // 游標偵測
...
氣泡模型.addChild(模型)  // 將正十二面體綁到氣泡中

至於影片一開始,當游標或手勢點選靜止氣泡時,就會釋放正十二面體往下掉落,這個功能怎麼做到的呢?這是本節的重點。

第一步,在設定手勢之前,要被點選的個體須載入「輸入標定元件」(InputTargetComponent),否則手勢無效;而輸入標定元件需要碰撞偵測元件,才知道點選位置是否在個體範圍內,因此至少須載入兩個元件:

氣泡模型.components.set(InputTargetComponent())     // 手勢偵測
氣泡模型.generateCollisionShapes(recursive: false)  // 碰撞偵測

第二步是設定手勢:

var 手勢: some Gesture {
    TapGesture()
        .targetedToAnyEntity()
        .onEnded { 事件 in
            print(事件.entity)
            if let 炸彈 = 事件.entity.findEntity(named: "炸彈") as? ModelEntity {
                炸彈.physicsBody = .init(mode: .dynamic)
                炸彈.generateCollisionShapes(recursive: false)
            }
        }
}