從第3單元開始,就介紹過什麼是非同步事件(簡稱「事件」),舉凡網路連線(URLSession)、互動手勢(Gesture)、按鍵(Button)…等,都會觸發非同步事件,當事件發生時,會回頭呼叫我們寫的函式(或匿名函式)— 稱為事件處理函式(event handler)。
事件處理是每位程式設計師必須熟悉的重要觀念。
在 Swift 中,事件處理大多採用「發布者-訂閱者」(Publisher-Subscriber)溝通模式,要先有程式在事件發生時發布訊息,我們才能訂閱。在本課程中,發布者大多是作業系統或框架底層,我們寫的程式作為訂閱者。
在前一課6-10e其實就用過事件處理:
// 6-10e 動畫控制器
OrbitEntityAction.subscribe(to: .paused) { 事件 in
...
}
這行程式會訂閱公轉動作(OrbitEntityAction)的暫停事件,RealityKit 框架是發布者,當動作暫停時,會發布資料(稱為訊息或通知)給每個訂閱者。此例中,資料會以參數「事件」(名稱可自訂)帶進我們所寫的匿名函式 — 即事件處理函式。
上一節6-11c手勢互動也同樣用到事件處理:
// 6-11c
var 手勢: some Gesture {
TapGesture()
.targetedToAnyEntity()
.onEnded { 事件 in
...
}
}
事件處理的應用很廣,到處都看得到。
RealityKit 提供哪些事件可供訂閱呢?根據原廠文件,包括以下幾大類別:
# | 事件類別 | 說明 | 相關事件 |
---|---|---|---|
1 | AccessibilityEvents | 無障礙輔助事件 | 略 |
2 | AnimationEvents | 動畫事件 | .PlaybackCompleted 播放結束 |
.PlaybackLooped 循環播放 | |||
.PlaybackStarted 開始播放 | |||
.PlaybackTerminated 播放終止 | |||
.SkeletalPoseUpdateComplete | |||
3 | AudioEvents | 音效播放事件 | .PlaybackCompleted 播放結束 |
4 | CollisionEvents | 碰撞事件 | .Began 碰撞開始 |
.Ended 碰撞結束 | |||
.Updated 持續碰撞 | |||
5 | ComponentEvents | 元件事件 | .DidActivate 元件已啟用 |
.DidAdd 元件已加入 | |||
.DidChange 元件已變更 | |||
.WillDeactivate 元件將失效 | |||
.WillRemove 元件將移除 | |||
6 | PhysicsSimulationEvents | 物理模擬事件 | .DidSimulate 模擬已開始 |
.WillSimulate 模擬即將開始 | |||
7 | SceneEvents | 場景事件 | .AnchoredStateChanged 錨點變更 |
.DidActivateEntity 個體已啟用 | |||
.DidAddEntity 個體已加入 | |||
.DidReparentEntity 變更父個體 | |||
.Update 場景更新 | |||
.WillDeactivateEntity 個體將失效 | |||
.WillRemoveEntity 個體將移除 | |||
8 | SynchronizationEvents | 網路同步事件 | 略 |
9 | VideoPlayerEvents | 影片播放事件 | 略 |
這些類別表明在什麼時間點,可以插入我們寫的程式碼,例如「場景更新」(SceneEvents.Update)預設每1/60秒更新一次,每次就會呼叫一次事件處理函式,用得好的話,可以給畫面帶來驚奇的效果。
對物理模擬來說,最常用的是碰撞事件,共有三個,分別是碰撞開始、碰撞結束、持續碰撞中,本節將利用碰撞開始事件(CollisionEvents.Began),在炸彈與上升氣泡碰撞時發出響聲,並讓氣泡消失。