VRCTween
VRCTweenを使用すると、強力なDOTweenライブラリを活用して、VRChatワールド内に滑らかなアニメーションを作成できます。わずか数行のコードで、位置、回転、スケールなどをアニメーション化することが可能です。
概要
VRCTweenは、時間経過とともに値をスムーズに補間(トゥイーン)する組み込みのトゥイーンシステムです。フレームごとに位置や回転を逐一更新する代わりに、VRCTweenが計算やタイミングを自動的に処理します。
一般的な使用例:
- ボタン、パネル、メニューなどのUI要素をアニメーションさせる。
- オブジェクトを滑らかに動かす。
- ワールドのクオリティを向上させる。
VRCTweenはUnityで広く利用されているトゥイーンライブラリであるDOTweenを使用しており、UdonSharpおよびUdon Graphの両方で動作します。
基本的な使用方法
Tweenの作成
ターゲット型に対する拡張メソッド、または VRCTween の静的メソッドを使用してTweenを作成します。各メソッドは、Tweenの制御や設定に使用できる VRCTweenHandle を返します。
using VRC.SDK3.Components;
public class MyScript : UdonSharpBehaviour
{
public GameObject cube;
void Start()
{
// Move the cube up over 2 seconds.
VRCTweenHandle tweenHandle = cube.TweenPosition(new Vector3(0, 5, 0), 2f, VRCTweenEase.OutQuad);
}
}
コールバックの受け取り
Tweenの完了時に通知を受け取るには、ハンドルに対して .OnComplete() をチェーンします。
public class MyScript : UdonSharpBehaviour
{
void Start()
{
gameObject.TweenScale(Vector3.one * 2f, 1f, VRCTweenEase.OutBounce)
.OnComplete(this, nameof(OnScaleComplete));
}
public void OnScaleComplete()
{
Debug.Log("Scale animation complete!");
}
}
Tweenの種類
Tweenの作成メソッドは、対象の型(例: gameObject.TweenPosition(...))の拡張メソッドとして、あるいは VRCTween の静的メソッドとして利用可能です。いずれも VRCTweenHandle を返します。
- Transform: TweenPosition, TweenLocalPosition, TweenRotation, TweenLocalRotation, TweenScale
- Path: TweenPath, TweenLocalPath
- UI: TweenColor, TweenFade (Graphic), TweenFade (CanvasGroup), TweenValue (Slider), TweenAnchorPos, TweenSizeDelta
- Sprite: TweenColor, TweenFade (SpriteRenderer)
- Renderer: TweenColor, TweenFloat (Renderer)
- Light: TweenIntensity, TweenColor (Light)
- Audio: TweenVolume, TweenPitch (AudioSource)
詳細なコード例については、Built-in Tween Types を参照してください。
Virtual Tween
Virtual Tweenは、毎フレーム UdonBehaviour 上の変数に書き込むことで、任意の数値(float、int、Color、Vector3)をアニメーションさせます。組み込みのTweenタイプで目的の動作が実現できない場合に使用してください。詳細や例については Virtual Tweens を参照してください。
トゥイーンの制御と設定
VRCTweenHandle のインスタンスメソッドを使用して、トゥイーンの制御や設定を行います。設定メソッドはメソッドチェーンのためにハンドルを返します。
cube.TweenPosition(new Vector3(0, 5, 0), 2f, VRCTweenEase.OutQuad)
.From()
.SetDelay(0.5f)
.SetLoops(2, VRCTweenLoopType.Yoyo)
.OnComplete(this, nameof(OnDone));
APIの完全なリファレンスとイージングタイプ(ease type)の表については、Settings and Control を参照してください。
例
この例では、ハンドルの保存、コールバック、およびクリーンアップの方法を説明します。
using UdonSharp;
using UnityEngine;
using VRC.SDK3.Components;
public class TweenExample : UdonSharpBehaviour
{
public GameObject button;
private VRCTweenHandle scaleTween;
public override void Interact()
{
// Scale up and down when clicked.
scaleTween = button.TweenScale(Vector3.one * 1.2f, 0.15f, VRCTweenEase.OutQuad)
.OnComplete(this, nameof(OnTweenComplete));
}
public void OnTweenComplete()
{
// Scale back down.
button.TweenScale(Vector3.one, 0.15f, VRCTweenEase.OutQuad);
}
void OnDestroy()
{
// Clean up tweens when object is destroyed.
button.KillAllTweens();
}
}
ベストプラクティス
Tweenハンドルを保存する
後からTweenを制御する必要がある場合は、Tweenハンドルを保存しておきます。
private VRCTweenHandle myTween;
void Start()
{
myTween = gameObject.TweenPosition(Vector3.up, 2f, VRCTweenEase.OutQuad);
}
public void StopTween()
{
myTween.Kill();
}
Tweenをクリーンアップする
Tweenは完了すると自動的にクリーンアップされます。ただし、実行中のTween(無限ループや長時間実行されるTweenなど)は、オブジェクトが破棄される際に強制終了させるべきです。
void OnDestroy()
{
gameObject.KillAllTweens();
}
コールバックを使用してTweenを連結する
コールバックとカスタムイベント名を使用して、Tweenのシーケンスを作成します。
void Start()
{
cube.TweenPosition(Vector3.up * 5, 1f, VRCTweenEase.OutQuad)
.OnComplete(this, nameof(OnFirstTweenComplete));
}
public void OnFirstTweenComplete()
{
cube.TweenRotation(new Vector3(0, 180, 0), 1f, VRCTweenEase.InOutQuad)
.OnComplete(this, nameof(OnSecondTweenComplete));
}
public void OnSecondTweenComplete()
{
Debug.Log("Sequence complete!");
}
キャンセル可能なタイマーには DelayedCall を使用する
VRCTween.DelayedCall は、SendCustomEventDelayedSeconds の代わりに使用できるキャンセル可能なタイマーです。
private VRCTweenHandle timerHandle;
void Start()
{
// Schedule a delayed callback.
timerHandle = VRCTween.DelayedCall(this, nameof(OnTimerFinished), 3.0f);
}
public void CancelTimer()
{
// Cancel the timer at any time.
timerHandle.Kill();
}
public void OnTimerFinished()
{
Debug.Log("3 seconds have passed!");
}
Udon Graph
VRCTweenはUdon Graphで利用可能です。ノード検索で VRCTween および VRCTweenHandle ノードを探してください。
- "VRCTween TweenPosition"(またはその他の作成メソッド)を検索して、Tweenを作成します。
- GameObjectとパラメータを接続します。
- ノードから
VRCTweenHandleが出力されます。 VRCTweenHandleノード(Kill、Pause、SetDelay、OnCompleteなど)を使用して、制御や設定を行います。
コールバックについては、 VRCTweenHandle OnComplete ノードを使用します。
- TweenハンドルとUdonBehaviour(通常は "this")を接続します。
- カスタムイベント名を文字列で指定します。
- グラフ内に対応するカスタムイベントを実装します。
制限事項
- Tweenは各プレイヤーのローカル環境でのみ動作し、ネットワーク経由での自動同期は行われません。
- ネットワーク同期が必要なアニメーションについては、Tweenと併せてUdonのネットワーク機能の使用を検討してください。
- 非常に短いTweenの時間設定(0.01秒未満)では、アニメーションが滑らかに動作しない場合があります。
- Tweenのハンドルは、シーンインスタンスごとに一意となります。
入力値の検証
VRCTweenは、DOTweenの状態やUnityのTransformを破損させるような値を拒否します。この拒否によってUdonBehavior自体がクラッシュしないよう、例外は発生させません。そのため、「何も起きなかった」というトゥイーンは、通常、以下の入力値のいずれかが無効であったことを意味します。
生成メソッドにおいて、以下の場合は無効なハンドルを返し(トゥイーンの生成をスキップし)ます:
targetがnullである場合。durationが負の値、NaN、または無限大である場合。0は再利用可能なトゥイーンの作成において許可されています。- 位置、スケール、またはパスの経由点にNaN、無限大が含まれている、あるいは成分の絶対値がおよそ520,000ユニットを超えている場合。回転のトゥイーンは有限の値であることのみを要求するため、大きなオイラー角も許容されます。
- パスの
resolutionは、自動的に1〜50の範囲にクランプされます。この範囲外の値でもトゥイーンは作成されますが、解像度がクランプされた状態で実行されます。
設定や制御を行うメソッドにおいて、無効な引数が渡された場合は何も実行(no-op)されません:
SetDurationは、負の値、NaN、または無限大の値を無視します。0は許容されます。SetDelayは、負の値、NaN、または無限大の値を無視します。Gotoは、NaNや無限大を無視し、それ以外の場合はトゥイーンの長さにクランプします。ChangeEndValueは、生成時に行われるものと同じ有限値チェックおよび大きさチェックに失敗したfloat型/Vector型の値を無視します。
トゥイーンが実際に開始されたかどうかで処理を分岐させる必要がある場合は、生成後に handle.IsValid を確認してください。
パフォーマンスのヒント
一般的なヒント
- オブジェクト上のすべてのトゥイーンを一度にクリーンアップするには、
KillAllTweens()を使用してください。 - 何百ものトゥイーンを同時に作成することは避けましょう。負荷を分散させるために、フレームをずらして実行するようにしてください(以下の例を参照)。
- ほとんどのワールド(インタラクションによって5〜50個のトゥイーンがトリガーされる場合)では、新規にトゥイーンを作成しても全く問題ありません。DOTweenは内部でトゥイーンオブジェクトをプールするため、オーバーヘッドは最小限です。
多数のトゥイーンをずらして実行する
タイル状に並んだオブジェクトなど、多数のオブジェクトをアニメーションさせる必要がある場合は、すべてのトゥイーンを同じフレーム内で作成しないようにしてください。その代わり、それぞれの間に小さな遅延を設けて時間をかけて実行するようにします。
[SerializeField] private GameObject[] tiles;
[SerializeField] private float delayBetween = 0.05f;
private int _nextIndex;
public void AnimateAll()
{
_nextIndex = 0;
_AnimateNext();
}
public void _AnimateNext()
{
if (_nextIndex >= tiles.Length) return;
tiles[_nextIndex].TweenScale(Vector3.one, 0.3f, VRCTweenEase.OutBack);
_nextIndex++;
SendCustomEventDelayedSeconds(nameof(_AnimateNext), delayBetween);
}
こうすることで呼び出しごとに1つのトゥイーンが作成され、処理が多くのフレームに分散されます。視覚的には、すべてが同時に変化するよりも、カスケード状にずれて変化する魅力的な演出になります。
頻繁に実行される処理(ホットパス)でのトゥイーンの再利用
移動するターゲットを追従するUI要素や、毎フレームプレイヤーの入力に応答するオブジェクトなど、頻繁にトゥイーンを再設定する場合は、ChangeEndValue、SetDuration、SetEase を使用してハンドルを再利用することで、フレームごとのメモリ割り当てを回避できます。500個のトゥイーンを300フレームにわたって更新する内部ベンチマークでは、再利用パターンは破棄して再作成する方法と比較して メモリ割り当てが46分の1 になり、実行速度は 10倍 速くなりました。
この最適化は、トゥイーンが高頻度で作成・破棄される場合に重要となります。単発のアニメーション(ドアの開閉、ボタン、スケールのポップアップなど)では、単純に破棄して再作成するコードの方が読みやすく、十分に機能します。
VRCTweenHandle _moveHandle;
void Start()
{
// Create once with infinite loops so it stays alive after completing.
_moveHandle = gameObject.TweenPosition(Vector3.zero, 1f, VRCTweenEase.OutQuad)
.SetLoops(-1, VRCTweenLoopType.Restart)
.Pause();
}
public void MoveTo(Vector3 target, float duration)
{
// Reconfigure and restart without allocating.
_moveHandle.ChangeEndValue(target, true)
.SetDuration(duration)
.SetEase(VRCTweenEase.OutCubic);
_moveHandle.Restart();
}
詳細については、「設定と制御」内の Tween reuse を参照してください。
リソース
- DOTween Documentation - 基盤となっているライブラリについて学習できます。
- Ease Visualizer - さまざまなイージング(Ease)タイプの動きを確認できます。
最終更新: