This document is about: QUANTUM 3
SWITCH TO

アニメーション

概要

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イベントを受け取って反応できます。そのために必要なステップは以下の通りです。

  1. イベントを受け取るメソッド(void Jump(EventPlayerJump e))を定義する
  2. 対象のイベントを購読する
  3. イベントを受信した際、イベントに含まれるEntityRefを以前キャッシュしたものと比較して、スクリプトがあるゲームオブジェクトが対象なのかどうかをチェックする
  4. 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が適切ですが、そうでない場合はポーリングベースのアニメーションが適切です。
Back to top