アニメーション
概要
Quantumでは、アニメーションを扱う方法が2つあります。
- Unityからゲームステートをポーリングする
Quantum Animator Addon
を使用した決定論的アニメーション
ポーリングベースのアニメーション
ほとんどのゲームは、アニメーションを使用してオブジェクトの状態をプレイヤーに伝えます。例えば、操作キャラクターの歩行/ジャンプのアニメーションは、実際には「その場」のアニメーションで、移動はコードで制御されます。
言い換えれば、各キャラクターのアニメーター(Unity)はステートレスで、ゲームシミュレーション(Quantum)からポーリングしたデータに基づいて、アニメーションパラメーターに渡す値を単純に取得します。
注意: ゲームプレイシステムが、Root Motion
に依存している場合や、アニメーション状態を認識する必要がある場合は、次のセクションをスキップしてください。
以下の基本的なコードスニペットでは、関連するUnityコンポーネントをキャッシュして、ビュー更新コールバックのQuantumGame
からフレームを取得、フレームから関連データを読み込んで、アニメーターに適用します。フレームAPIは、Unityから書き込みを行うと非決定論的になるため、Unityでは読み取り専用操作のみで使用してください。
C#
namespace Quantum
{
using UnityEngine;
public class CharacterAnimations : QuantumEntityViewComponent
{
private Animator _animator;
public override void OnInitialize()
{
_animator = GetComponentInChildren<Animator>();
}
public override void OnUpdateView()
{
var kcc = PredictedFrame.Get<CharacterController3D>(EntityRef);
_animator.SetFloat("Speed", kcc.Velocity.Magnitude.AsFloat);
}
}
}
トリガーイベント
一部のアニメーションは、ゲーム内で発生する特定のイベントに基づきます。例えば、プレイヤーがジャンプボタンを押したり、敵に攻撃を受けたりした場合です。通常これらのケースでは、シミュレーションからイベントを発生させて、ビューがそれを受け取ることが好ましいです。これによってモデルとビューが分離され、ポーリングベースのアニメーションとうまく連携します。
イベントとコールバックの詳細な説明については、マニュアルのQuantum ECS > Events & Callbacks
ページをご覧ください。
キャラクターがジャンプする時に、QuantumのシステムからQuantumイベントをトリガーできます。
C#
namespace Quantum
{
using Photon.Deterministic;
public unsafe struct PlayerMovementFilter
{
public EntityRef EntityRef;
public PlayerID* PlayerID;
public Transform3D* Transform;
public CharacterController3D* Kcc;
}
unsafe class MovementSystem : SystemMainThreadFilter<PlayerMovementFilter>
{
public override void Update(Frame frame, ref PlayerMovementFilter filter)
{
var input = frame.GetPlayerInput(filter.PlayerID->PlayerRef);
if (input->Jump.WasPressed)
{
frame.Events.PlayerJump(filter.EntityRef);
filter.Kcc->Jump(f);
}
}
}
}
Unity側では、UnityコンポーネントがPlayerJump
イベントを受け取って反応できます。そのために必要なステップは以下の通りです。
- イベントを受け取るメソッド(
void Jump(EventPlayerJump e)
)を定義する - 対象のイベントを購読する
- イベントを受信した際、イベントに含まれる
EntityRef
を以前キャッシュしたものと比較して、スクリプトがあるゲームオブジェクトが対象なのかどうかをチェックする - Unityアニメーターでパラメーターをトリガー/設定する
.qtn
ファイルからイベントを定義できます。
Qtn
event PlayerJump { EntityRef EntityRef; }
Unityコンポーネントでイベントに反応します。
C#
namespace Quantum
{
using UnityEngine;
public class CharacterAnimations : QuantumEntityViewComponent
{
private Animator _animator;
public override void OnInitialize()
{
_animator = GetComponentInChildren<Animator>();
QuantumEvent.Subscribe<EventPlayerJump>(this, OnPlayerJump);
}
private void OnPlayerJump(EventPlayerJump e)
{
if (e.EntityRef == EntityRef)
{
_animator.SetTrigger("Jump");
}
}
}
}
ヒント
- 2D/3Dモデルとアニメーターコンポーネントは、子オブジェクトに配置します。
- イベントはゲームステートの一部ではないため、途中参加/再参加したプレイヤーは利用できません。そのため、ゲームが既に開始している場合は、最初に最新のゲームステートをポーリングして、アニメーション状態を初期化することを推奨します。
- 100%の精度でトリガーされる必要があるアニメーション(例:勝利演出)には、同期イベントを使用してください。
- 即時の応答が必要なアニメーション(例:攻撃を受ける)には、通常の非同期イベントを使用してください。
EventCanceled
コールバックを使用して、キャンセルされた非同期イベントによってトリガーされたアニメーションを自然に元に戻します。これは、予測中に発生したイベントが、確定フレームでロールバックされた場合に発生することがあります。
決定論的アニメーション
決定論的アニメーションシステムの主な利点は、ティック単位で正確なアニメーションが、すべてのクライアント間で100%同期され、ロールバックが発生しても正しい状態に即時に移行することです。これは理想的に聞こえるかもしれませんが、アニメーション状態がシミュレーションのゲームステートの一部になるため、パフォーマンスに大きく影響を与えます。実際には、決定論的アニメーションシステムを必要として、メリットが得られるゲームはわずかで、格闘ゲームや一部のスポーツゲームなどです。
Quantum Animatorによって、決定論的アニメーションが実現できます。このツールは、Unityのアニメーターコントローラーの情報をベイクし、状態・状態間の遷移・モーションクリップなどのすべての構成をインポートします。
Quantum 3からは、コードはオープンソースとなり、Addons > Animator
ページからダウンロード可能です。このページでは、概要やツールのインポートや使用方法のクイックガイドも提供されています。
機能は限定的なものになっているので、必要に応じて調整が必要になるかもしれません。
ヒント
- Quantum Animatorを使用する前に、アニメーションがゲームプレイに結びついているのか、それとも単なる視覚的表現なのかを検討してください。前者の場合はQuantum Animatorが適切ですが、そうでない場合はポーリングベースのアニメーションが適切です。