This document is about: QUANTUM 3
SWITCH TO

ローカルプレイヤービュー

はじめに

Unityスクリプトから、ローカルプレイヤー(または、複数のプレイヤー)のビューを表現するゲームオブジェクトの参照を取得できると役立つことも多いです。

これを実現する方法はいくつか存在し、このドキュメントではそれら有効なアプローチの理解を深めるための重要な概念を紹介します。

シミュレーションの基本的なセットアップ

ここで鍵となるのはPlayerRefで、これはゲームに参加した各クライアントに割り当てられるユニークなインデックスです。

PlayerRefは、エンティティやエンティティビューとは独立していて、単にプレイヤーを表すために存在します。デフォルトでは、実行時に作成されたエンティティは、一切PlayerRefとの関連を持ちません。

これらを関連付ける方法はゲームによって異なります。多くのケースでは、プレイヤーは1つのエンティティを操作しますが、プレイヤーが複数のエンティティを操作することも十分ありえます。

リンク機能はデフォルトでは提供されていないので、まず好きな方法で関連付けを確立するのが最初のステップになります。
最も一般的なアプローチは、以下のようなPlayerLinkコンポーネントを独自に定義することです。

  1. エンティティを操作するプレイヤーのPlayerRefを保持するためのQuantumコンポーネントを作成する。

Qtn

component PlayerLink
{
    PlayerRef PlayerRef;
}
  1. 最適なタイミングで上記を設定する。一般的なアプローチでは、最初にプレイヤーがゲームに参加した際のエンティティ作成時にこれを設定します。

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;
    }
  }
}

目的はローカルプレイヤーを表現するエンティティビューのゲームオブジェクトを探すことですが、最初にビューのゲームオブジェクトを表す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