This document is about: QUANTUM 3
SWITCH TO

Local Player View

簡介

在 Unity 腳本中,獲取代表本地玩家(或多個本地玩家,因為可能有多個)視圖的遊戲物件引用通常很有用。

有幾種方法可以實現這一點。本文檔介紹核心概念,以幫助您理解可用的方法。

基本模擬設置

這裡的關鍵概念是 PlayerRef,它是分配給每個加入遊戲的客戶端的唯一索引。

PlayerRef 獨立於實體或實體視圖,它的存在僅是為了代表玩家。預設情況下,執行時創建的實體與 PlayerRef 沒有固有的連接。

這種連接的建立方式因遊戲而異。在大多數情況下,一個玩家控制一個實體,但玩家完全有可能控制多個實體。

由於默認不提供這種鏈接,因此第一步是按照自己的喜好建立它。
一種非常常見的方法是定義一個自定義的PlayerLink組件,如下所述:

  1. 創建一個 Quantum 組件,用於存儲控制實體的玩家的PlayerRef

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)
    {
      // Get the player data in order to access its PlayerAvatar
      var playerData = frame.GetPlayerData(player);

      // Create the character entity
      var character = frame.Create(playerData.PlayerAvatar);

      // Get the PlayerLink component from the entity
      var playerLink = frame.Unsafe.GetPointer<PlayerLink>(character);
      // OR, add the playerLink "frame.Add<PlayerLink>(character, out var playerLink);"

      // Assign the player ref to the component
      playerLink->PlayerRef = player;
    }
  }
}

在視圖端輪詢玩家鏈接

由於目標是找到代表本地玩家的實體視圖 GameObject,因此首先需要能夠訪問代表視圖遊戲物件的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);
      // Add any desired logic based on this
    }
  }
}

存儲本地實體視圖的引用

然後可以緩存本地實體視圖,以便其他腳本輕鬆訪問。一種選擇是立即存儲對QuantumEntityView的引用。或者立即執行一些邏輯,例如啟用只應對本地玩家活躍的遊戲 UI 等。

在 Quantum 視圖上下文中存儲
創建一個上下文 MonoBehaviour,其中包含一個將存儲本地實體視圖的字段:

C#

namespace Quantum
{
  public class GameContext : QuantumMonoBehaviour, IQuantumViewContext
  {
    public QuantumEntityView LocalEntityView;
  }
}

讓一個實體視圖組件實現帶有上下文類型的基類,並以類似方式存儲引用:

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)
        {
            // Store the local player reference so it can be easily accessed later
            ViewContext.LocalEntityView = EntityView;
        }
    }
  }

  public override void OnDeactivate()
  {
    // Make sure to also clear the reference when, for example, the entity view is deactivated
    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)
        {
            // Store the local player reference so it can be easily accessed later
            LocalPlayerViewReference.Instance.LocalEntityView = EntityView;
        }
    }
  }

  public override void OnDeactivate()
  {
    // Make sure to also clear the reference when, for example, the entity view is deactivated
    LocalPlayerViewReference.Instance.LocalEntityView = null;
  }
}

伺服器回放

PlayerIsLocal在大多數情況下都能正常工作,但在運行回放時,本地玩家的定義將不存在。
對於回放的使用場景,用戶必須根據自己的回放邏輯定義正在觀察的 PlayerRef,才能使其正常工作。

有關更多信息,請查看回放文檔。

Back to top