如何在虛擬寵物遊戲迴圈中分離閒置狀態與互動狀態
在虛擬寵物遊戲中,請將自主行為與玩家動作保持在獨立的更新路徑中,然後讓兩者透過明確的狀態轉換來修改同一個共享的寵物狀態。閒置行為應根據經過的時間推進;互動行為則應回應輸入事件或當前的輸入狀態。這使得暫停、測試變得更加容易,並能防止寵物動畫或需求計時器與玩家指令互相衝突。
定義何謂「閒置」與「互動」
請將這些視為行為模式,而不一定是不同的場景或獨立的迴圈。在閒置(idle)狀態下,寵物執行其常規行為:選擇一個微小的環境動作、推進計時器或播放非必要的動畫。在互動(interactive)狀態下,遊戲正在處理刻意的動作,例如點擊、拖曳或選取的指令。寵物在互動過程中可能仍會播放動畫;兩者的區別在於由哪個系統負責做決策以及更改遊戲狀態。
首先列出玩家可以執行的動作以及寵物可以執行的自主行為的簡要清單。標記每個動作可能更改哪些狀態變數。例如,環境眨眼可能只影響外觀呈現,而選取的玩耍動作可能會更改寵物目前的活動並啟動計時器。這種簡單的所有權對應有助於在程式碼擴充之前發現衝突。
保持外部迴圈獨立於寵物行為
引擎的影格回呼(frame callback)應該負責協調整體工作,而非包含所有的寵物規則。一個實用的順序是:收集輸入、套用有效指令、推進模擬,最後呈現最新狀態。將輸入收集與模擬分開,這樣點擊就不會被意外當作計時器的 tick,並確保畫面呈現不會引起遊戲邏輯狀態的改變。《Game Programming Patterns》將這種分離描述為在重複迴圈中處理輸入、更新遊戲和進行繪製;當模擬需要穩定的時間間隔時,固定步長更新(fixed-step updates)會非常實用。Game Loop, Game Programming Patterns
對於網頁遊戲,requestAnimationFrame 會在重新繪製前排程工作,並提供可用於測量經過時間的時間戳記。瀏覽器通常會在背景分頁中暫停這些回呼,因此不要假設它們在遊戲處於背景執行時仍能作為可靠的真實時鐘運作。Window.requestAnimationFrame(), MDN
透過指令路由玩家輸入
將原始輸入轉換為小型指令,例如 start_play、stop_play 或 pet_tap。指令處理常式會檢查該動作在當前模式下是否有效,對共享模型進行一次更新,並發出任何相應的外觀呈現提示。這樣可以避免將動作邏輯同時分散在按鈕回呼、動畫回呼和閒置常式中。
例如,如果玩家在寵物已經在玩耍時點擊,請明確定義結果:忽略該點擊、選擇其他活動或停止該活動。避免讓閒置選擇器和點擊處理常式在同一次更新中同時指定新活動。在具有事件傳遞機制的引擎中,請在適當的階段處理遊戲玩法輸入並遵循 UI 的事件消耗;Godot 的 Node 文件指出,當 GUI 控制項需要優先權時,未處理的輸入(unhandled input)通常更適合用於遊戲玩法。Node class, Godot documentation
使用明確的時鐘推進閒置時間
對於應該在可見階段持續推進的行為,請累計經過的模擬時間,並在達到其間隔時觸發閒置決策。不要計算影格數:影格頻率是會變動的。在 Godot 中,_process(delta) 接收自上一個閒置影格以來經過的時間,而 _physics_process(delta) 則遵循物理 tick;文件也指出,在某些條件下,累計的 delta 可能會與真實世界的秒數產生偏差。Node class, Godot documentation
請根據行為選擇適當的時鐘。純外觀的動作通常可以使用影格經過時間。與碰撞相關的移動則屬於引擎的物理更新。寵物的「每隔幾秒選擇一個環境動作」計時器可以使用模擬計時器,但必須確定在長影格或暫停後該如何處理:限制最大經過時間、僅執行一次決策,或在有限步長內進行追趕。無限制的追趕可能會導致寵物在遊戲恢復時連續跳過多個狀態。
使模式轉換保持明確
在加入更多狀態之前,先寫下一個小型的轉換表。例如,idle → playing 開始玩家選取的活動;playing → idle 在活動結束或玩家取消時發生;idle → resting 則可能由自主常式選擇。在一處定義進入與退出效果,例如啟動或清除計時器以及選擇相關動畫。不要僅憑動畫播放完畢作為遊戲模式已變更的依據:視覺播放可能會被中斷或略過。
轉換函式應驗證當前模式、更新模型,並返回渲染器可以顯示的結果。這將「寵物正在做什麼」與「該動作如何繪製」分開。它也為測試提供了明確的目標:提交指令、檢查產生的模式,然後驗證閒置常式不再覆寫該模式。
決定背景時間的運作方式
有兩種常見的策略,具體取決於遊戲設計。僅限工作階段的寵物可以在暫停時停止模擬,並從先前的狀態恢復。如果遊戲希望計時器在關閉時仍繼續推進,則必須記錄參考時間,並在返回時核對經過的時間。請將其視為獨立的恢復計算,而不是嘗試在背景中執行影格迴圈;瀏覽器的動畫回呼在隱藏分頁中可能會被暫停。Window.requestAnimationFrame(), MDN
對於簡單的寵物,只需核對確實應該推進的數值——例如某個活動計時器——並為追趕設定一個合理的上限。接著測試在短時間和長時間間隔後關閉並重新開啟的情況。時鐘的選擇、暫停行為以及追趕上限都是設計決策;引擎的影格回呼不會替你做出這些決定。
檢查競爭更新與遺漏的輸入
使用幾個可重複的情境來測試迴圈:讓遊戲閒置數個週期;在閒置決策前夕發出指令;按住或重複輸入;暫停並恢復;以及在動畫仍在播放時觸發新動作。驗證每個指令是否僅更改模型一次、閒置邏輯是否不會取代玩家選取的狀態,以及時間流逝行為是否符合選定的暫停策略。
如果使用固定更新進行模擬,請記住它在算繪的影格之間可能會執行零次、一次或多次。Unity 在 FixedUpdate 的文件中記錄了這種行為,並建議將其用於物理計算;輸入和視覺更新具有不同的時間考量。FixedUpdate(), Unity documentation Unity 的 Input System 也會將裝置事件排隊,並根據其設定的更新模式進行處理,因此請使輸入處理與消耗這些指令的迴圈保持一致。Input event queue, Unity Input System
值得維持的實用分離架構
保持架構精簡:一個共享的寵物模型、一條輸入轉指令的路徑、一個閒置行為更新、一個明確的轉換函式,以及一個讀取模型的渲染器。僅在對時間敏感的行為需要時才加入固定模擬步長;不要讓每個動畫或環境選擇都依賴物理 tick。當出現錯誤時,請檢查是誰最後變更了模式以及是哪個時鐘推進了它。這讓每次更新都有明確的職責,並隨著寵物獲得更多動作,使閒置和互動行為維持可預測性。
