This page is a work in progress and could be pending updates.

Fusion 104 - Physics

概述

Fusion 104將研究Fusion如何在伺服器授權的遊戲中與PhysX進行互動。

在本節結束時,該項目將允許玩家生成一個物理控制的球並與之互動。

請查閱手冊,了解本主題的深入設置

Back To Top

設置

在托管模式下,Fusion將在主機上執行物理學模擬,客戶機將跟隨,然而應用程式可以選擇允許客戶機預測甚至是物理學控制對象。

要打開這個功能,進入Fusion選單,選擇Network Project Config。這將在檢查器中打開Fusion的配置文件。在Server Physics Mode下選擇Client Prediction

啟用客戶端預測在計算上更加負擔,但可以提供更精確的運動。

Back To Top

物理對象

聯網的PhysX控制對象的預制件使用與普通Unity PhysX對象相同的Rigidbody,但有一個不同的Fusion組件來同步視覺子對象,稱為NetworkRigidbody。就聯網而言,它取代了NetworkTransform

  1. 在Unity編輯器中創建一個新的空遊戲對象。
  2. 重命名GameObjectPhysxBall
  3. 添加一個新的NetworkRigidbody組件。
  4. Fusion將顯示一個關於缺少NetworkObject組件的警告,所以繼續按Add Network Object。Fusion將自動添加一個普通的Unity RigidBody,因為PhysX模擬需要這個。
  5. Interpolation Data Source改為Predicted,並將其設置為World Space
  6. PhysxBall添加一個球體子實體。
  7. 在所有方向上將子體縮小到0.2
  8. 將子對象拖入父對象上的NetworkTransform組件的InterpolationTarget
  9. 從球體中移除碰撞器
  10. 在父對象上創建一個新的半徑為0.1的球體碰撞器,使其完全覆蓋子對象。
  11. 在遊戲對象上添加一個新的腳本,並將其稱為PhysxBall.cs
  12. 將整個對象拖入項目文件夾,創建一個預制件。
  13. 保存場景以創建網路對象,並從場景中刪除預制事件。

Ball Prefab
球體預制件

Back To Top

The PhysxBall 腳本

由於球是由PhysX驅動的,並且NetworkRigidbody負責處理網路數據,因此它需要的特殊代碼要比其他相關運動體少。只需在PhysxBall.cs中添加一個計時器,該計時器將在幾秒鐘後使球失效(這與運動球的情況完全相同),以及一個設置初始前進速度的方法。

這兩個方法都由Init()方法涵蓋,例如以下:

using UnityEngine;
using Fusion;

public class PhysxBall : NetworkBehaviour
{
  [Networked] private TickTimer life { get; set; }

  public void Init(Vector3 forward)
  {
    life = TickTimer.CreateFromSeconds(Runner, 5.0f);
    GetComponent<Rigidbody>().velocity = forward;
  }

  public override void FixedUpdateNetwork()
  {
    if(life.Expired(Runner))
      Runner.Despawn(Object);
  }
}

Back To Top

輸入

為了生成球,需要按照與運動球相同的三個步驟擴展代碼,但改為使用鼠標的第二個按鈕:

1. NetworkInputData

NetworkInputData.cs中簡單添加一個新的按鈕標誌:

using Fusion;
using UnityEngine;

public struct NetworkInputData : INetworkInput
{
  public const byte MOUSEBUTTON1 = 0x01;
  public const byte MOUSEBUTTON2 = 0x02;

  public byte buttons;
  public Vector3 direction;
}

Back To Top

2. BasicSpawner

BasicSpawner.cs中,以與第一個相同的方式連結第二個鼠標按鈕,並相應地設置標誌:

  private bool _mouseButton0;
  private bool _mouseButton1;
  private void Update()
  {
    _mouseButton0 = _mouseButton0 || Input.GetMouseButton(0);
    _mouseButton1 = _mouseButton1 || Input.GetMouseButton(1);
  }

  public void OnInput(NetworkRunner runner, NetworkInput input)
  {
    var data = new NetworkInputData();

    ...

    if (_mouseButton1)
      data.buttons |= NetworkInputData.MOUSEBUTTON2;
    _mouseButton1 = false;

    input.Set(data);
  }

Back To Top

3. Player

Player.cs持有生成實際球的預制件的代碼,所以除了需要像這樣的預制件引用外,

[SerializeField] private PhysxBall _prefabPhysxBall;

Player還必須呼叫spawn並使用之前創建的Init()方法設置速度(只是一個常數乘以最後的前進方向)。

public override void FixedUpdateNetwork()
{
  if (GetInput(out NetworkInputData data))
  {
    data.direction.Normalize();
    _cc.Move(5*data.direction*Runner.DeltaTime);

    if (data.direction.sqrMagnitude > 0)
      _forward = data.direction;

    if (delay.ExpiredOrNotRunning(Runner))
    {
      if ((data.buttons & NetworkInputData.MOUSEBUTTON1) != 0)
      {
        delay = TickTimer.CreateFromSeconds(Runner, 0.5f);
        Runner.Spawn(_prefabBall, 
          transform.position+_forward,
          Quaternion.LookRotation(_forward), 
          Object.InputAuthority, 
          (runner, o) =>
          {
            // Initialize the Ball before synchronizing it
            o.GetComponent<Ball>().Init();
          });
      }
      else if ((data.buttons & NetworkInputData.MOUSEBUTTON2) != 0)
      {
        delay = TickTimer.CreateFromSeconds(Runner, 0.5f);
        Runner.Spawn(_prefabPhysxBall, 
          transform.position+_forward, 
          Quaternion.LookRotation(_forward),           
          Object.InputAuthority, 
          (runner, o) =>
          {
            o.GetComponent<PhysxBall>().Init( 10*_forward );
          });
      }
    }
  }
}

最後,為了測試新球,將創建的預制件分配給Player預制件上的Prefab Physx Ball字段,構建並執行。

To Document Top