38
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Unity】演出スキップがつらすぎたので、ChainRacePattern という仕組みを作った

38
Last updated at Posted at 2026-03-15

はじめに

Unity で演出を作っていると、ほぼ確実にスキップ機能が必要になります。

リザルト画面、ガチャ演出、ストーリーパート。やりたいことは「ボタンが押されたら、実行中の演出を飛ばして次へ進む」だけなのに、実装は毎回つらい。

私自身、この問題にかなり悩みました。その末にたどり着いたのが ChainRacePattern (仮) です。

※ 本記事で紹介する ChainRacePattern は、現時点では提案段階の設計パターンです。

※ 詳しい設計・実装の話は続編にまとめました。
Unityの演出スキップ問題をどう解決するか ー ChainRacePattern

演出スキップの何がつらいのか

スキップがない演出は単純です。

移動A → 移動B → 移動C → 完了

しかし「スキップボタンを押したら即座に最終状態にする」が入った途端、話が変わります。

よくあるのは、スキップ時に実行中のアニメーションを個別に止める実装です。

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 は「開始できて、いつか完了し、必要ならスキップもできる」という単純なものです。

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 を同時に実行し、どれか1つが完了した時点で残りをスキップして終了します。

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

この意味はシンプルです。

  • アニメーションが先に終わる → 入力待ちをスキップして通常再生
  • ボタンが先に押される → アニメーションをスキップして次へ進む

つまり、スキップを例外処理ではなく、入力と演出の競争として表現できます。

この「入力も Chain として扱い、Race で競わせる」考え方を ChainRacePattern と呼んでいます。

Chain の基本ルール

独自の Chain を作る際の基本は次の3つです。

  • StartInternal()
    開始処理を書く。完了時に Complete() を呼ぶ
  • SkipInternal()
    開始後のスキップ時に直ちに終了状態へ進める
  • isFastForward
    開始直後に Skip() 確定なら true。不要な処理を省略するために利用する

Chain が自分のスキップ処理を持つことで、外側にスキップ用の分岐を増やさずに済みます。

実例1:Scene1 スキップの3パターン

Scene1 では、矩形が位置1→2→3→4と移動するアニメーションで、ChainRace の使い分けを示しています。

1. 全体スキップ

new ChainRace(
    new ChainButton(skipButton),
    new ChainSequence(移動12, 移動23, 移動34)
)

ボタンを押すと、演出全体が一気にスキップされます。

2. セクション単位スキップ

new ChainRace(new ChainButton(skipButton), 移動12),
new ChainRace(new ChainButton(skipButton), 移動23),
new ChainRace(new ChainButton(skipButton), 移動34)

押した時点のセクションだけをスキップし、次へ進みます。

3. スキップ不可区間

new ChainRace(new ChainButton(skipButton), 移動12),
new ChainSequence(移動23),
new ChainRace(new ChainButton(skipButton), 移動34)

セクション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 で入力と演出を競わせる
  • ChainRace で囲むかどうかでスキップ可否を制御できる
  • Chain が自分のスキップ処理を持つ

演出を追加してもスキップ処理が壊れにくく、スキップ用の分岐が外側に散りにくい。
感じていたつらさを、この仕組みでかなり減らせました。

注意: ChainRacePattern は現時点では提案段階の設計パターンです。
完成品のライブラリではなく、あくまで実装例として公開しています。必要最低限の構成に留めているため、用途や案件に応じて機能追加・調整して使うことを想定しています。

興味があれば、リポジトリやデモを見てみてください。フィードバックをいただけると励みになります。
MIT License で公開しているので、必要に応じて改変・利用してください。

38
27
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
38
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?