This document is about: QUANTUM 3
SWITCH TO

Animation

概述

在 Quantum 中,有兩種不同的方式來處理動畫:

  • 從 Unity 輪詢遊戲狀態;及,
  • 使用Quantum Animator Addon的確定性動畫。

基於輪詢的動畫

大多數遊戲使用動畫來向玩家傳達物件的狀態。例如,當可玩角色行走或跳躍時,動畫實際上是 原地 動畫,而感知到的移動是由代碼驅動的。

換句話說,管理角色(Unity)動畫控制器的腳本是無狀態的,僅根據從遊戲模擬(在 Quantum 中)輪詢的數據推導出值,並將其作為動畫參數傳遞。

__注意: __ 如果遊戲系統依賴 根運動 或需要知道動畫狀態,請跳至下一節。

以下是一個代碼片段,展示了緩存相關 Unity 組件的基本方法,並從更新視圖回調中獲取 QuantumGame 的一幀,然後從該幀中讀取相關數據並應用到動畫控制器上。在 Unity 中,請確保僅使用幀 API 進行 只準備好的 操作,因為從 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與先前緩存的,檢查事件是否針對腳本所在的 GameObject。
  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");
      }
    }
  }
}

提示

  • 將模型及其動畫控制器組件放在子物件上。
  • 事件不是遊戲狀態的一部分,因此對於遲加入/重新加入的玩家不可用。因此,如果遊戲已經開始,建議首先通過輪詢最新的遊戲狀態來初始化動畫狀態。
  • 對於需要 100% 準確觸發的動畫(例如勝利慶祝),使用同步事件。
  • 對於需要快速響應的動畫(例如被擊中),使用常規的非同步事件。
  • 使用EventCanceled回調來優雅地退出由取消的非同步事件觸發的動畫。這可能發生在事件作為預測的一部分觸發,但在驗證幀期間被回滾時。

確定性動畫

使用確定性動畫系統的主要優勢是幀精確的動畫,這些動畫在所有客戶端之間 100% 同步,並且在回滾時會立即恢復到正確的狀態。雖然這聽起來很理想,但它會帶來性能影響,因為動畫及其狀態現在是模擬遊戲狀態的一部分。實際上,只有少數遊戲需要並受益於確定性動畫系統;其中包括格鬥遊戲和 某些 體育遊戲。

Quantum Animator 是一個實現確定性動畫的工具。它通過從 Unity 的 Mecanim 控制器烘焙信息並導入每個配置(例如狀態、狀態之間的轉換、運動剪輯等)來工作。

自 Quantum 3 起,代碼已開源,並可在Addons > Animator頁面下載。該頁面還提供了工具的概述和快速指南,說明如何導入和使用它。

請記住,它的功能有限,可能需要根據您的需求進行調整。

提示

  • 在使用 Quantum Animator 之前,請考慮動畫是否與遊戲玩法綁定,或者僅僅是其視覺表現。如果是前者,Quantum Animator 是一個合適的解決方案;否則,基於輪詢的動畫是更好的選擇。
Back to top