This document is about: QUANTUM 3
SWITCH TO

Input

概述

輸入是Quantum核心架構的關鍵組成部分。 在確定性網絡庫中,系統的輸出是固定的,並且在給定特定輸入的情況下是預先確定的。 這意味著,只要網路中所有用戶端的輸入相同,輸出也將相同。

在DSL中定義

可以在任何DSL檔案中定義輸入。 例如,一個有移動方向和單個跳轉按鈕的輸入結構體看起來像這樣:

Qtn

input
{
    button Jump;
    FPVector3 Direction;
}

服務器負責批次處理並發送完整勾選集的輸入確認(所有玩家的輸入)。因此,這個結構應該盡可能地保持最小的大小。

命令

確定性命令是Quantum的另一種輸入路徑,可以有任意數據和大小,這使得它們非常適合特殊類型的輸入,如“購買此物品”、“傳送到某個地方”等。

Unity中輪詢

要向Quantum類比發送輸入,請在Unity內部輪詢。為此,請在遊戲場景中的MonoBehaviour內訂閱PollInput回調。

C#

  private void OnEnable()
  {
    QuantumCallback.Subscribe(this, (CallbackPollInput callback) => PollInput(callback));
  }

然後,在回調中,從輸入源讀取並填充輸入結構。

C#

  public void PollInput(CallbackPollInput callback)
   {
    Quantum.Input i = new Quantum.Input();

    var direction = new Vector3();
    direction.x = UnityEngine.Input.GetAxisRaw("Horizontal");
    direction.y = UnityEngine.Input.GetAxisRaw("Vertical");

    i.Jump = UnityEngine.Input.GetKey(KeyCode.Space);

    // convert to fixed point.
    i.Direction = direction.ToFPVector3();

    callback.SetInput(i, DeterministicInputFlags.Repeatable);
  }

注意:這裡的浮點到定點轉換是確定性的,因為它是在與類比共享之前完成的。

優化

儘管Quantum 3 delta壓縮了輸入,但為了獲得最佳頻寬,使原始Input數據盡可能緊湊仍然是一種很好的做法。 以下是一些優化它的方法。

按鈕

Button類型在Input DSL定義中使用,而不是使用布林值或類似的資料類型來表示按鍵。 這是因為它每個實例只使用一個位元,因此在可能的情況下使用是有利的。 雖然它們在網絡上只使用一個位元,但在本地它們將包含更多的遊戲狀態。 這是因為單個位元僅代表當前幀中是否按下了按鈕,其餘資訊在本地計算。
按鈕定義如下:

Qtn

input
{
    button Jump;
}

從Unity腳本輪詢按鈕值時的一個重要細節是輪詢當前按鈕狀態,即是否在當前幀按下按鈕。 通過這種管道,Quanutm會自動設定內部内容,允許用戶在類比程式碼上輪詢特定狀態,如WasPressed, IsDownWasReleased
這意味著,在Unity中,您不需要設定特定的狀態,如GetKeyUp()GetKeyDown(),因為使用這些狀態實際上是有問題的,因為Unity的運行速度與Quantum不同,因此其中一些狀態會遺失,使輸入感覺響應性降低。

因此,在Input結構中設定button的值時,始終輪詢當前按鈕狀態,如下所示:

C#

// In Unity, when polling a player's input
input.Jump = UnityEngine.Input.GetKey(KeyCode.Space);

按鈕的狀態也可以在Quantum類比程式碼中更新,這對於類比機器人等非玩家實體的按鈕變化特別有用,如果用戶選擇使用Input結構和button類型來更新機器人實體。 為了實現這一點,有必要在類比程式碼每幀中設定按鈕的狀態,如下所示:

C#

// In Quantum code
input.button.Update(frame, value);

這樣,特定狀態(按下、關閉、釋放)也會在內部生成。 不每幀更新按鈕狀態會導致這些狀態被錯誤設定。

編碼方向

在典型的設定中,運動通常使用方向向量來表示,通常在DSL檔案中定義如下:

Qtn

input
{
    FPVector2 Direction;
}

然而,FPVector2由兩個'FP'組成,佔用16個位元組的數據,這可能是發送的大量數據,特別是在同一個房間裏有許多用戶端的情況下。
優化它的一種方法是擴展Input結構並將方向向量編碼為Byte,而不是每次發送完整的向量。 其中一種實現管道如下:

首先,我們像普通一樣定義我們的輸入,但不是包含一個用於方向的FPVector2,而是用一個Byte替換它,在那裡我們將存儲編碼版本。

Qtn

input
{
    Byte EncodedDirection;
}

接下來,以擴展組件的管道擴展輸入結構體(請參閱:添加功能):

C#

namespace Quantum
{
    partial struct Input
    {
        public FPVector2 Direction
        {
            get
            {
                if (EncodedDirection == default)
                    return default;

                Int32 angle = ((Int32)EncodedDirection - 1) * 2;

                return FPVector2.Rotate(FPVector2.Up, angle * FP.Deg2Rad);
            }
            set
            {
                if (value == default)
                {
                    EncodedDirection = default;
                        return;
                }

                var angle = FPVector2.RadiansSigned(FPVector2.Up, value) * FP.Rad2Deg;

                angle = (((angle + 360) % 360) / 2) + 1;

                EncodedDirection = (Byte) (angle.AsInt);
            }
        }
    }
}

此實現允許與以前相同的用法,但它只佔用單個位元組,而不是16個位元組。 它通過使用Direction内容來實現這一點,該内容會自動對EncodedDirection中的值進行編碼和解碼。

Back to top