ローカルプレイヤービュー
はじめに
Unityスクリプトから、ローカルプレイヤー(または、複数のプレイヤー)のビューを表現するゲームオブジェクトの参照を取得できると役立つことも多いです。
これを実現する方法はいくつか存在し、このドキュメントではそれら有効なアプローチの理解を深めるための重要な概念を紹介します。
シミュレーションの基本的なセットアップ
ここで鍵となるのはPlayerRef
で、これはゲームに参加した各クライアントに割り当てられるユニークなインデックスです。
PlayerRef
は、エンティティやエンティティビューとは独立していて、単にプレイヤーを表すために存在します。デフォルトでは、実行時に作成されたエンティティは、一切PlayerRef
との関連を持ちません。
これらを関連付ける方法はゲームによって異なります。多くのケースでは、プレイヤーは1つのエンティティを操作しますが、プレイヤーが複数のエンティティを操作することも十分ありえます。
リンク機能はデフォルトでは提供されていないので、まず好きな方法で関連付けを確立するのが最初のステップになります。
最も一般的なアプローチは、以下のようなPlayerLink
コンポーネントを独自に定義することです。
- エンティティを操作するプレイヤーの
PlayerRef
を保持するためのQuantumコンポーネントを作成する。
Qtn
component PlayerLink
{
PlayerRef PlayerRef;
}
- 最適なタイミングで上記を設定する。一般的なアプローチでは、最初にプレイヤーがゲームに参加した際のエンティティ作成時にこれを設定します。
C#
namespace Quantum
{
using UnityEngine.Scripting;
[Preserve]
public unsafe class PlayerJoiningSystem : SystemSignalsOnly, ISignalOnPlayerAdded
{
public void OnPlayerAdded(Frame frame, PlayerRef player, bool firstTime)
{
// PlayerAvatarを参照するためにプレイヤーデータを取得する
var playerData = frame.GetPlayerData(player);
// キャラクターのエンティティを作成する
var character = frame.Create(playerData.PlayerAvatar);
// エンティティからPlayerLinkコンポーネントを取得する
var playerLink = frame.Unsafe.GetPointer<PlayerLink>(character);
// または、"frame.Add<PlayerLink>(character, out var playerLink);"でPlayerLinkを追加する
// コンポーネントにPlayerRefを割り当てる
playerLink->PlayerRef = player;
}
}
}
ビュー側でのPlayerLinkのポーリング
目的はローカルプレイヤーを表現するエンティティビューのゲームオブジェクトを探すことですが、最初にビューのゲームオブジェクトを表すEntityRef
にアクセスできるようにする必要があります。これを行う方法は多数ありますが、一般的なアプローチは簡単にEntityRef
へアクセスできるQuantumEntityViewComponent
を使用することです。
例えば、ビューコンポーネントを作成してそれが有効になった際に、エンティティに保持されているPlayerRef
を取得し、ローカルプレイヤーであるかをチェックします。
C#
using Quantum;
public unsafe class CharacterViewComponent : QuantumEntityViewComponent
{
public override void OnActivate(Frame frame)
{
if (frame.TryGet<PlayerLink>(EntityRef, out var playerLink))
{
var isLocalPlayer = Game.PlayerIsLocal(playerLink.PlayerRef);
// ローカルプレイヤーに基づく任意のロジックを追加する
}
}
}
ローカルエンティティビューの参照の格納
他のスクリプトからのアクセスを簡単にするため、ローカルエンティティビューをキャッシュすることも可能です。1つの方法は、QuantumEntityView
の参照を格納することです。または、ローカルプレイヤーのみで表示されるゲームUIを有効にするなどして、即座にロジックを実行することもできます。
QuantumViewContextに格納する
ローカルエンティティビューを保持するフィールドを持つコンテキストMonoBehaviour
を作成します。
C#
namespace Quantum
{
public class GameContext : QuantumMonoBehaviour, IQuantumViewContext
{
public QuantumEntityView LocalEntityView;
}
}
そして、コンテキスト型を持つEntityViewComponent
で、以下のようにして参照を格納します。
C#
using Quantum;
public unsafe class CharacterViewComponent : QuantumEntityViewComponent<GameContext>
{
public override void OnActivate(Frame frame)
{
if (frame.TryGet<PlayerLink>(EntityRef, out var playerLink))
{
var isLocalPlayer = Game.PlayerIsLocal(playerLink.PlayerRef);
if (isLocalPlayer == true)
{
// 後で簡単にアクセスできるように、ローカルプレイヤーの参照を保持する
ViewContext.LocalEntityView = EntityView;
}
}
}
public override void OnDeactivate()
{
// 例:エンティティビューが無効になったら、参照もクリアすることを確認する
ViewContext.LocalEntityView = null;
}
}
GameContext
コンポーネントは、QuantumEntityViewUpdater
ゲームオブジェクト自身か、その子要素に追加してください。
他のエンティティビューコンポーネントも同様にコンテキストにアクセスできるようにする必要があります。例えば、次のようになります。
C#
public class MyCustomViewComponent : QuantumEntityViewComponent<GameContex>
{
public override void OnActivate(Frame frame)
{
var localPlayerView = ViewContext.LocalEntityView;
}
}
静的に参照を格納する
より素早く簡単なアプローチは、参照をシングルトンに保存することです。もちろん、シングルトンの適用には注意が必要になるため、慎重に使用してください。
C#
using Quantum;
public unsafe class CharacterViewComponent : QuantumEntityViewComponent
{
public override void OnActivate(Frame frame)
{
if (frame.TryGet<PlayerLink>(EntityRef, out var playerLink))
{
var isLocalPlayer = Game.PlayerIsLocal(playerLink.PlayerRef);
if (isLocalPlayer == true)
{
// 後で簡単にアクセスできるように、ローカルプレイヤーの参照を保持する
LocalPlayerViewReference.Instance.LocalEntityView = EntityView;
}
}
}
public override void OnDeactivate()
{
// 例:エンティティビューが無効になったら、参照もクリアすることを確認する
LocalPlayerViewReference.Instance.LocalEntityView = null;
}
}
サーバーリプレイ
PlayerIsLocal
はほとんどのケースで動作しますが、リプレイ実行時はローカルプレイヤーが存在しないため動作しません。
リプレイを実行するケースで正しく動作させるためには、ユーザーは自身のリプレイロジックに基づいて監視対象のPlayerRef
を定義する必要があります。
詳細な情報については、リプレイのドキュメントをご覧ください。
Back to top