This document is about: QUANTUM 3
SWITCH TO

Entity View Component

概述

實體視圖框架的設計目的是快速將實體的模擬內部邏輯與視圖端代碼綁定。它是一個簡單的實體元件系統,類似於 MonoBehaviours,但專為 Quantum 實體視圖設計。

透過將衍生自QuantumEntityViewComponent類別的腳本添加到 EntityView 下的任何遊戲物件,該腳本即可立即存取EntityRefGamePredictedFrameVerifiedFrame,並可覆寫各種虛擬方法。

所有視圖元件都集中在QuantumEntityViewUpdater(EVU) 上,並從那裡進行更新。

視圖元件與QuantumEntityViewPool配合良好。

生命週期

以下回調定義了(池化的)實體視圖及其QuantumViewComponents的生命週期。

OnInitialize() 當實體視圖元件首次創建時調用。此時視圖上下文已設置,但尚無法存取Game, VerifiedFrame, PredictedFramePredictedPreviousFrame
OnActivate(Frame frame) 當實體視圖被創建或啟用(例如從池中取出)時調用,例如當新的 Quantum 實體被創建且 EVU 創建了關聯的 EntityView 時。
OnDeactivate() 在實體視圖被停用(無論是銷毀還是返回池中)之前調用。
OnUpdateView() 在 Unity 更新時調用,源自 EVU 的OnObservedGameUpdated()
OnLateUpdateView() 在 EVU 的 Unity LateUpdate() 方法中調用。
OnGameChanged() 當 EVU 中觀察的遊戲發生變化後調用。

上下文

QuantumEntityViewComponent可以定義一個可選的泛型類型,用於上下文物件。上下文物件是一個簡單的類別(可以是 MonoBehaviour、單例等),衍生自IQuantumViewContext。這是一個在遊戲不同部分之間共享數據的選項。

上下文必須是QuantumEntityViewUpdater遊戲物件的子物件,並且必須在Awake()期間添加,才能自動加載並供視圖元件使用。

C#

namespace Quantum {
  using UnityEngine;
  public class MyGameContext : QuantumMonoBehaviour, IQuantumViewContext {
    public GameObject Template;
  }
}

上下文可以通過ViewContext屬性存取。

C#

namespace Quantum {
  using UnityEngine;
    public class MyViewScript : QuantumEntityViewComponent<MyGameContext> {
      GameObject _go;

      public override void OnInitialize() {
        _go = Instantiate(ViewContext.Template);
      }
  }
}   

在 EVU 上可以存取所有已加載的上下文類型的字典:Dictionary<Type, IQuantumViewContext> Context

場景視圖元件

QuantumSceneViewComponent是一個沒有關聯實體的視圖元件。它可以添加到場景中的任何物件上,以存取視圖元件屬性,但必須明確添加到QuantumEntityViewUpdater中。

可以直接使用Updater欄位引用 EVU。

或者開啟UseFindUpdater,這會在 OnEnable() 時執行FindFirstObjectByType(),可能會被認為是較慢的操作。

ViewUpdater 也允許動態添加和移除場景視圖元件。雖然OnInitialize()OnDeactivate()會立即調用,但OnActivate()會延遲到下一次 Update 調用。

QuantumEntityViewUpdater.AddViewComponent(IQuantumViewComponent viewComponent)
QuantumEntityViewUpdater.RemoveViewComponent(IQuantumViewComponent viewComponent)

範例

根據角色控制器狀態設置角色動畫。

C#

namespace Quantum {
  using UnityEngine;

  public class CharacterViewAnimations : QuantumEntityViewComponent {
    private Animator _animator;

    public override void OnInitialize() {
      _animator = GetComponentInChildren<Animator>();
    }

    public override void OnUpdateView() {
      // probably should use RealSpeed, but the variable isn't been written to in the KCC code currently
      var kcc = PredictedFrame.Get<KCC>(EntityRef);
      var kinematicSpeed = kcc.Data.KinematicVelocity.Magnitude;

      _animator.SetFloat("Speed", kinematicSpeed.AsFloat * 10);
      _animator.SetBool("Jump", kcc.Data.HasJumped);
      _animator.SetBool("FreeFall", !kcc.Data.IsGrounded);
      _animator.SetBool("Grounded", kcc.Data.IsGrounded);
    }
  }
}

鏡頭跟隨行為範例:

C#

// Context, added to QuantumEntityViewUpdater game object
namespace Quantum {
  using UnityEngine;

  public class CustomViewContext : MonoBehaviour, IQuantumViewContext {
    public Camera MyCamera;
  }
}

// View component, added to entity prefab (QuantumEntityView)
namespace Quantum {
  using UnityEngine;

  public class QuantumCameraFollow : QuantumEntityViewComponent<CustomViewContext> {
    public Vector3 Offset;
    public float LerpSpeed = 4;
    private bool _isPlayerLocal;

    public override void OnActivate(Frame frame) {
      var playerLink = frame.Get<PlayerLink>(EntityRef);
      _isPlayerLocal = Game.PlayerIsLocal(playerLink.Player);

    }

    public override void OnUpdateView() {
      if (_isPlayerLocal == false) {
        return;
      }

      var myPosition = transform.position;
      var desiredPos = myPosition + Offset;
      var currentCameraPos = ViewContext.MyCamera.transform.position;

      ViewContext.MyCamera.transform.position = Vector3.Lerp(currentCameraPos, desiredPos, Time.deltaTime * LerpSpeed);
      ViewContext.MyCamera.transform.LookAt(transform);
    }
  }
}
Back to top