トゥイーン
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 を使って最短弧に沿って回転します。
To と From はどちらも IDisposable トークンを返します — トゥイーンを早期にキャンセルするには、それを Dispose してください。
パラメーター
from、to(または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(両方)— があります:
| ファミリー | メンバー | 特徴 |
|---|---|---|
| Linear | Linear | 一定速度、イージングなし |
| Quad | InQuad · OutQuad · InOutQuad | 穏やかな加速(2 乗) |
| Cubic | InCubic · OutCubic · InOutCubic | 中程度の加速(3 乗) |
| Quart | InQuart · OutQuart · InOutQuart | 強い加速 |
| Quint | InQuint · OutQuint · InOutQuint | 非常に強い加速 |
| Sine | InSine · OutSine · InOutSine | 柔らかい波ベースのイージング |
| Expo | InExpo · OutExpo · InOutExpo | 劇的な指数的立ち上がり |
| Circ | InCirc · OutCirc · InOutCirc | 円弧。片端で急峻 |
| Back | InBack · OutBack · InOutBack | 目標を行き過ぎてから収まる |
| Elastic | InElastic · OutElastic · InOutElastic | バネのように目標を通り過ぎて振動する |
| Bounce | InBounce · OutBounce · InOutBounce | 境界でボールのように跳ねる |
経験則: ほとんどの UI モーションには OutQuad か OutCubic、遊び心のあるポップインには 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());
これですべてのトゥイーンが無効化されます。To と From は共有の空トークンを返し、コールバックは発火せず、ticker オブジェクトも生成されません。エディターツールや自動テストでアニメーションを無効化するのに便利です。no-op 版でも入力の検証は行われます。null の onUpdate、無効な Clock や EaseType、NaN・無限大・負の durationSeconds は引き続きスローします — アニメーションを切っていてもバグは見えたままです。
よくある落とし穴
- 正しいクロックを選ぶ。 間違ったクロックを選んでもエラーにはなりませんが、アニメーションの感触が狂います — たとえば
Clock.UIにバインドされていたせいで、ポーズ中も動き続けるゲームプレイアニメーションなど。各クロックがポーズとスローモーションでどう振る舞うかは Time サービスを参照してください。 - Quaternion のイージングはオーバーシュートをクランプする。 オーバーシュート系カーブ(
InBack、OutBack、InElastic、OutElastic)では、回転の目に見えるオーバーシュートは起きません。Quaternion.Slerpが係数を 0〜1 の範囲にクランプするためです。オーバーシュート区間の間、回転は終了値に留まります。 - キャンセルと完了は別物。 トゥイーンのトークンを Dispose すると静かにキャンセルされ、
onCompleteは発火しません。持続時間の最後まで到達した場合はonCompleteが発火します。 - デリゲートのアロケーションは利用者側のコスト。 サービスは内部のトゥイーンスロットをプールしますが、
onUpdateのラムダ(およびcustomEaseのクロージャ)は呼び出しごとに利用者側でアロケートされます。アロケーション禁止のタイトなループでは、デリゲートを一度フィールドに保存し、新しいラムダを書く代わりに毎回そのフィールドを渡してください。 - 完了後のトークンを保持し続けない。 完了したトゥイーンのスロットは後続のトゥイーンに再利用されます。古くなったトークンは検出されて無視されるため、遅れて Dispose しても害はありませんが、保持し続けているのはライフタイムバグの兆候です。撃ちっぱなしのトゥイーンなら、トークンを保存する必要はまったくありません。
関連ページ
- Time — トゥイーンがバインドされるクロック
- Tween Sequencing — 順次・並列のトゥイーンタイムライン
- Scheduler — 同じクロック上での遅延実行と繰り返しタイマー