トゥイーン

Time サービスのクロックで駆動する、31 種類のイージングカーブを備えたポーズ対応の値アニメーション。

任意の値を A から B へ時間をかけてアニメーションさせます — ポーズメニューへの対応は追加コストなしです。

インターフェースITweenService
オフスイッチNullTweenService
アセンブリCommonGameSystem.Core
起動ブート時に自動登録 — セットアップ不要

できること

トゥイーンとは、開始値と終了値の間を一定時間かけて滑らかに補間することです。Tween サービスは各 tick でその値を計算し、イージングカーブが加速の形を決めます(ゆっくり始めて加速する、行き過ぎてから収まる、バウンドする、など)。各値をオブジェクトに適用するコールバックは利用者が用意します — フレームワークは計算だけを行います。リフレクションも、自動的なプロパティ書き込みも、外部依存もありません。

すべてのトゥイーンは Time サービスのクロック — Gameplay、UI、Background — のいずれかにバインドされるため、追加コードなしでアニメーションがポーズメニューやスローモーションに対応します。Gameplay クロック上のドア開閉トゥイーンはプレイヤーがポーズすると凍結し、UI クロック上のメニューフェードは動き続けます。

クイックスタート

Awake または Start でサービスを一度だけ解決し、キャッシュします:

using CommonGameSystem.Core;
using UnityEngine;

[DefaultExecutionOrder(100)] // Run after the framework has started.
public class MyMovingThing : MonoBehaviour
{
    private ITweenService _tween;

    private void Awake()
    {
        _tween = ServiceLocator.Resolve<ITweenService>();
    }

    private void StartMove()
    {
        _tween.To(
            from: transform.position,
            to: new Vector3(5f, 0f, 0f),
            durationSeconds: 0.5f,
            onUpdate: pos => transform.position = pos,
            ease: EaseType.OutQuad
        );
    }
}

API リファレンス

型付き To / From オーバーロード群

サービスがサポートする値型はちょうど 6 つで、それぞれに型付きオーバーロードのセットがあります:

float · Vector2 · Vector3 · Vector4 · Color · Quaternion

各型には 4 つのオーバーロード — To または From、デフォルトクロックまたは明示的な Clock パラメーター付き — があり、合計 24 メソッドです。すべて同じ形をしています(ここでは float で示します。6 つの型のどれにでも置き換えられます):

IDisposable To(float from, float to, float durationSeconds,
               Action<float> onUpdate,
               EaseType? ease = null,
               Func<float, float> customEase = null,
               Action onComplete = null);

IDisposable To(float from, float to, float durationSeconds, Clock clock,
               Action<float> onUpdate,
               EaseType? ease = null,
               Func<float, float> customEase = null,
               Action onComplete = null);

IDisposable From(float from, float current, float durationSeconds,
                 Action<float> onUpdate,
                 EaseType? ease = null,
                 Func<float, float> customEase = null,
                 Action onComplete = null);

IDisposable From(float from, float current, float durationSeconds, Clock clock,
                 Action<float> onUpdate,
                 EaseType? ease = null,
                 Func<float, float> customEase = null,
                 Action onComplete = null);

From(a, current, ...)To(a, current, ...) と同じ操作です — ある値から現在値へ戻すアニメーション(たとえばパンチイン風のスケール演出)では、この名前のほうが単に読みやすいというだけです。

意図的にジェネリックな To<T> メソッドは存在しません。値型に対するオープンジェネリックメソッドが実行時に失敗し得る Unity の AOT(IL2CPP)コンパイルの下でも、固定の型付きオーバーロードセットなら確実に動作します。Quaternion のトゥイーンは Quaternion.Slerp を使って最短弧に沿って回転します。

ToFrom はどちらも IDisposable トークンを返します — トゥイーンを早期にキャンセルするには、それを Dispose してください。

パラメーター

  • fromto(または current) — 開始値と終了値。
  • durationSeconds — アニメーションの長さ(秒)。0 の場合は即座に to で完了します。
  • clock — 省略可能。Clock.Gameplay(デフォルト)はゲームと一緒にポーズし、Clock.UI はポーズメニュー中も動き続け、Clock.Background は常に動きます。
  • onUpdate — 補間値とともに毎 tick 呼ばれます。オブジェクトへの適用は利用者が行います。
  • ease — 省略可能な EaseType。省略するとデフォルトのイージングになり、下記の 31 カーブから選ぶこともできます。
  • customEase — 進捗(0〜1)をイージング済み進捗にマッピングする省略可能な Func<float, float>。指定すると ease より優先されます。
  • onComplete — トゥイーンが 100% に達したときに一度だけ発火します。キャンセル時には発火しません

31 種類のイージングカーブ

EaseType は Linear に加えて 10 のカーブファミリーをカバーし、それぞれに 3 つの方向 — In(動きに向かって加速)、Out(動きから減速)、InOut(両方)— があります:

ファミリーメンバー特徴
LinearLinear一定速度、イージングなし
QuadInQuad · OutQuad · InOutQuad穏やかな加速(2 乗)
CubicInCubic · OutCubic · InOutCubic中程度の加速(3 乗)
QuartInQuart · OutQuart · InOutQuart強い加速
QuintInQuint · OutQuint · InOutQuint非常に強い加速
SineInSine · OutSine · InOutSine柔らかい波ベースのイージング
ExpoInExpo · OutExpo · InOutExpo劇的な指数的立ち上がり
CircInCirc · OutCirc · InOutCirc円弧。片端で急峻
BackInBack · OutBack · InOutBack目標を行き過ぎてから収まる
ElasticInElastic · OutElastic · InOutElasticバネのように目標を通り過ぎて振動する
BounceInBounce · OutBounce · InOutBounce境界でボールのように跳ねる

経験則: ほとんどの UI モーションには OutQuadOutCubic、遊び心のあるポップインには OutBack、カートゥーン調の強調には OutBounce と Elastic 系を使います。

診断

  • int ActiveCount { get; } — 生きているトゥイーンの数。診断専用、メインスレッド専用です。

パネルを 0.3 秒でフェードインさせ、完了時にログを出します:

CanvasGroup panel = GetComponent<CanvasGroup>();

_tween.To(
    from: 0f,
    to: 1f,
    durationSeconds: 0.3f,
    clock: Clock.UI, // UI clock: keep running while the pause menu is open.
    onUpdate: alpha => panel.alpha = alpha,
    ease: EaseType.OutCubic,
    onComplete: () => Debug.Log("Fade complete!")
);

トークンを Dispose してトゥイーンをキャンセルします:

float score = 0f;
IDisposable token = _tween.To(0f, 100f, 1f, v => score = v);
// ... later, if you want to stop early:
token.Dispose();  // The tween cancels; onComplete does NOT fire.

無効化する

ServiceLocator.Replace<ITweenService>(new NullTweenService());

これですべてのトゥイーンが無効化されます。ToFrom は共有の空トークンを返し、コールバックは発火せず、ticker オブジェクトも生成されません。エディターツールや自動テストでアニメーションを無効化するのに便利です。no-op 版でも入力の検証は行われます。null の onUpdate、無効な ClockEaseType、NaN・無限大・負の durationSeconds は引き続きスローします — アニメーションを切っていてもバグは見えたままです。

よくある落とし穴

  • 正しいクロックを選ぶ。 間違ったクロックを選んでもエラーにはなりませんが、アニメーションの感触が狂います — たとえば Clock.UI にバインドされていたせいで、ポーズ中も動き続けるゲームプレイアニメーションなど。各クロックがポーズとスローモーションでどう振る舞うかは Time サービスを参照してください。
  • Quaternion のイージングはオーバーシュートをクランプする。 オーバーシュート系カーブ(InBackOutBackInElasticOutElastic)では、回転の目に見えるオーバーシュートは起きません。Quaternion.Slerp が係数を 0〜1 の範囲にクランプするためです。オーバーシュート区間の間、回転は終了値に留まります。
  • キャンセルと完了は別物。 トゥイーンのトークンを Dispose すると静かにキャンセルされ、onComplete は発火しません。持続時間の最後まで到達した場合は onComplete が発火します。
  • デリゲートのアロケーションは利用者側のコスト。 サービスは内部のトゥイーンスロットをプールしますが、onUpdate のラムダ(および customEase のクロージャ)は呼び出しごとに利用者側でアロケートされます。アロケーション禁止のタイトなループでは、デリゲートを一度フィールドに保存し、新しいラムダを書く代わりに毎回そのフィールドを渡してください。
  • 完了後のトークンを保持し続けない。 完了したトゥイーンのスロットは後続のトゥイーンに再利用されます。古くなったトークンは検出されて無視されるため、遅れて Dispose しても害はありませんが、保持し続けているのはライフタイムバグの兆候です。撃ちっぱなしのトゥイーンなら、トークンを保存する必要はまったくありません。

関連ページ

  • Time — トゥイーンがバインドされるクロック
  • Tween Sequencing — 順次・並列のトゥイーンタイムライン
  • Scheduler — 同じクロック上での遅延実行と繰り返しタイマー