エンティティビューコンポーネント
はじめに
エンティティビューのフレームワークは、シミュレーション内部のエンティティとビュー側のコードを素早くバインドできるように設計されています。これは、Quantumエンティティビュー用のMonoBehaviour
のようなものです。
QuantumEntityViewComponent
クラスを継承したスクリプトをEntityView
のゲームオブジェクトに追加すると、スクリプトからEntityRef
・Game
・PredictedFrame
・VerifiedFrame
を取得したり、様々なオーバーライド可能な仮想メソッドを使用したりできます。
すべてのビューコンポーネントはQuantumEntityViewUpdater
(EVU)にまとめられ、そこから更新されます。
ビューコンポーネントはQuantumEntityViewPool
を使用しても正常に動作します。
ライフタイム
以下のコールバックは、(プールされた)エンティティビューとそのQuantumViewComponents
のライフサイクルを定義します。
OnInitialize() |
エンティティビューコンポーネントが初めて作成される際に呼び出されます。ここでは、ビューコンテキストは既に設定済みですが、Game ・VerifiedFrame ・PredictedFrame ・PredictedPreviousFrame はまだ取得できません。 |
OnActivate(Frame frame) |
エンティティビューの作成/有効(プールからの場合も含む)時に呼び出されます。例えば、新しいQuantumエンティティが作成されて、EVUが関連するEntityView を作成した際です。 |
OnDeactivate() |
エンティティビューが無効化される前、つまり破棄/プールに返却される際に呼び出されます。 |
OnUpdateView() |
Unityの更新時に、EVUのOnObservedGameUpdated() から呼び出されます。 |
OnLateUpdateView() |
UnityのLateUpdate() メソッドが、EVUで呼び出されます。 |
OnGameChanged() |
EVUが参照しているゲームが変更された後に呼び出されます。 |
コンテキスト
QuantumEntityViewComponent
は、コンテキストオブジェクトのジェネリクス型を1つオプションで定義できます。コンテキストオブジェクトはIQuantumViewContext
を継承した単純なクラス(MonoBehaviour
やシングルトンなど)で、ゲーム間でデータを共有するためのオプションです。
コンテキストは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()
を実行することもできますが、これは他の方法に比べて遅くなります。
EVUは、シーンビューコンポーネントを動的に追加/削除できます。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() {
// おそらく実際の速度を使用すべきだが、現在はまだKCCにその変数は用意されていません
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#
// コンテキスト、QuantumEntityViewUpdaterゲームオブジェクトに追加される
namespace Quantum {
using UnityEngine;
public class CustomViewContext : MonoBehaviour, IQuantumViewContext {
public Camera MyCamera;
}
}
// ビューコンポーネント、エンティティプレハブ(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