🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付

在 Unity 裡製作演出時,幾乎必然會需要跳過(Skip)功能。

結果畫面、轉蛋演出、故事段落。想做的只是「按下按鈕就把正在執行的演出跳到下一步或最終狀態」,但每次實作都很痛苦。

我本人對這個問題困擾很久。最後得到的做法是名為 ChainRacePattern (暫名) 的設計。

※ 本文介紹的 ChainRacePattern,現階段為提案階段的設計模式。

※ 更詳細的設計與實作說明已整理在後續文章。
Unityの演出スキップ問題をどう解決するか ー ChainRacePattern

為什麼演出跳過那麼麻煩

沒有跳過的演出是很單純的。

移動A → 移動B → 移動C → 完成

但一旦加入「按下跳過按鈕就立刻到最終狀態」的需求,情況就大不同了。

常見的做法是,在跳過時個別停止正在執行的動畫(tween)。

void OnSkipButtonPressed()
{
    if (tweenA != null && tweenA.IsPlaying()) tweenA.Kill();
    if (tweenB != null && tweenB.IsPlaying()) tweenB.Kill();
    if (tweenC != null && tweenC.IsPlaying()) tweenC.Kill();

    rect.anchoredPosition = finalPosition;
    isSkipped = true;
}

隨著演出越多,就會越難管理「現在哪個在動」以及「跳過時要把狀態推到哪裡」。
每次新增演出都要修改跳過處理,造成 演出邏輯與跳過邏輯高度耦合,這就是痛點的本質。

以 Chain 做抽象化

因此,我把演出的各個要素統一成名為 Chain 的物件。
Chain 的概念很單純:「可以開始(start)、會在某時完成(complete)、必要時可以被跳過(skip)」。

ChainSequence:順序執行

await new ChainSequence(
    new ChainDelay(0.5f),
    new ChainAction(() => Debug.Log("Hello")),
    new ChainDelay(1.0f)
).Start();

ChainParallel:並列執行

await new ChainParallel(
    ChainMoveTween(rectA, targetA, 1.0f),
    ChainMoveTween(rectB, targetB, 1.0f)
).Start();

到這裡為止看起來都蠻自然的。問題在於,如何表現「跳過」這個行為。

發現:使用者輸入也可以是 Chain

如果把按鈕輸入也視為「開始後按下就完成」的行為,那它也可以是一個 Chain

new ChainButton(skipButton)

有了這個想法,接下來就是組合的問題。

ChainRace:誰先完成誰勝利

ChainRace 會同時執行多個 Chain,並在「任一個完成的時候」立刻把其餘的跳過並結束。

await new ChainRace(
    new ChainButton(skipButton),
    new ChainSequence(
        ChainMoveTween(rect, pos1, 1.0f),
        ChainMoveTween(rect, pos2, 1.0f)
    )
).Start();

這個設計的意義很單純:

  • 如果動畫先完成 → 就跳過等待輸入,按正常流程繼續
  • 如果按鈕先被按下 → 就跳過動畫,直接進入下一步

也就是說,不把跳過當作例外處理,而是把它當成「輸入與演出之間的競賽(race)」來表現。

把「輸入也當成 Chain,然後用 Race 把它們競賽」的想法,我稱為 ChainRacePattern。

Chain 的基本規則

自訂 Chain 時有三個基本要點:

  • StartInternal()
    撰寫啟動處理。在完成時呼叫 Complete()
  • SkipInternal()
    在開始後被跳過時,立即把狀態推到結束(最終狀態)
  • isFastForward
    如果一開始啟動就確定會被 Skip(),則為 true。用來避開不必要的處理

每個 Chain 都擁有自己的跳過處理,這樣可以避免在外層增加大量跳過分支判斷。

實例1:Scene1 中三種跳過模式

Scene1 是一個矩形依序從位置1→2→3→4 移動的動畫,用以示範 ChainRace 的不同用法。

1. 全體跳過

new ChainRace(
    new ChainButton(skipButton),
    new ChainSequence(移動1→2, 移動2→3, 移動3→4)
)

按下按鈕會將整個演出一次性跳過。

2. 區段單位跳過

new ChainRace(new ChainButton(skipButton), 移動1→2),
new ChainRace(new ChainButton(skipButton), 移動2→3),
new ChainRace(new ChainButton(skipButton), 移動3→4)

按下按鈕時,只跳過當下的區段,然後進入下一段。

3. 無法跳過區間

new ChainRace(new ChainButton(skipButton), 移動1→2),
new ChainSequence(移動2→3),
new ChainRace(new ChainButton(skipButton), 移動3→4)

只有區段2會被強制完整播放、不允許跳過。

換句話說,只要控制是否用 ChainRace 包起來,就能方便地切換該區段是否允許跳過。

實例2:Scene2 結果畫面演出

Scene2 是一個針對結果畫面設計的實作範例。

new ChainSequence(
    new ChainRace(
        new ChainButton(screenButton),
        new ChainParallel(
            fadePanel.ChainFade(false),
            resultDialog.ChainShowDialog()
        )
    ),
    new ChainRace(
        new ChainButton(screenButton),
        resultDialog.ChainShowBonus()
    ),
    ChainTouchScreen(),
    new ChainParallel(
        resultDialog.ChainHideDialog(),
        fadePanel.ChainFade(true)
    )
)

從上到下只需閱讀流程就能理解:

  1. 漸層淡入與對話框顯示(可跳過)
  2. 獎勵演出(可跳過)
  3. 觸碰等待
  4. 對話框隱藏與淡出

只用 SequenceParallelRace 就能很直觀地描述演出流程與跳過控制。

與 Promise.race 或 Rx 的關係

事後才知道,這個想法類似於 JavaScript 的 Promise.race() 或 Rx 的 Amb

但在遊戲演出場景中,單純「忽略輸的那一方」是不夠的。
被跳過的一方也必須「正確地落到最終狀態」,因此我們需要 SkipInternal()isFastForward 這類機制來確保被跳過時也能完成收尾。

總結

ChainRacePattern 的重點如下:

  • 將演出的各個要素統一成 Chain
  • 將使用者輸入也表現為 Chain
  • ChainRace 把輸入與演出進行競賽(race)
  • 只要是否用 ChainRace 包起來,就能切換該區段的可跳過性
  • 每個 Chain 自行負責自己的跳過處理

這樣新增演出時比較不會破壞跳過邏輯,跳過用的分支也不會散落在外層。
我用這個方式大幅降低了過去遇到的痛點。

注意: ChainRacePattern 目前仍屬於設計模式提案。
它不是一個已完備的函式庫,而是作為實作範例公開。為了保持最小構成,有需要的話請依用途或專案自行擴充與調整功能。

有興趣的話可以看看倉庫與示範,也歡迎任何回饋。
以 MIT License 發布,必要時可自由修改與使用。


原文出處:https://qiita.com/morishift/items/a2c5012d496312358323


精選技術文章翻譯,幫助開發者持續吸收新知。

共有 0 則留言


精選技術文章翻譯,幫助開發者持續吸收新知。
🏆 本月排行榜
🥇
站長阿川
📝18   💬9   ❤️1
497
🥈
我愛JS
📝1   💬6  
43
🥉
💬1  
4
評分標準:發文×10 + 留言×3 + 獲讚×5 + 點讚×1 + 瀏覽數÷10
本數據每小時更新一次
🔧 阿川の電商水電行
Shopify 顧問、維護與客製化
💡
小任務 / 單次支援方案
單次處理 Shopify 修正/微調
⭐️
維護方案
每月 Shopify 技術支援 + 小修改 + 諮詢
🚀
專案建置
Shopify 功能導入、培訓 + 分階段交付