4 - Physics
概述
Fusion 104將研究Fusion如何在伺服器授權的遊戲中與PhysX進行互動。
在本節結束時,該項目將允許玩家生成一個物理控制的球並與之互動。
設置
在托管模式下,Fusion將在主機上執行物理學模擬,客戶機將跟隨,然而應用程式可以選擇允許客戶機預測甚至是物理學控制對象。
要打開這個功能,進入Fusion選單,選擇Network Project Config
。這將在檢查器中打開Fusion的配置文件。在Server Physics Mode
下選擇Client Prediction
。
啟用客戶端預測在計算上更加負擔,但可以提供更精確的運動。
物理對象
聯網的PhysX控制對象的預制件使用與普通Unity PhysX對象相同的Rigidbody
,但有一個不同的Fusion組件來同步視覺子對象,稱為NetworkRigidbody
。就聯網而言,它取代了NetworkTransform
。
- 在Unity編輯器中創建一個新的空遊戲對象。
- 重命名
GameObject
為PhysxBall
。 - 添加一個新的
NetworkRigidbody
組件。 - Fusion將顯示一個關於缺少
NetworkObject
組件的警告,所以繼續按Add Network Object
。Fusion將自動添加一個普通的Unity RigidBody,因為PhysX模擬需要這個。 - 將
Interpolation Data Source
改為Predicted
,並將其設置為World Space
。 - 為
PhysxBall
添加一個球體子實體。 - 在所有方向上將子體縮小到0.2
- 將子對象拖入父對象上的NetworkTransform組件的
InterpolationTarget
。 - 從球體中移除碰撞器
- 在父對象上創建一個新的半徑為0.1的球體碰撞器,使其完全覆蓋子對象。
- 在遊戲對象上添加一個新的腳本,並將其稱為
PhysxBall.cs
。 - 將整個對象拖入項目文件夾,創建一個預制件。
- 保存場景以創建網路對象,並從場景中刪除預制事件。
The PhysxBall 腳本
由於球是由PhysX驅動的,並且NetworkRigidbody負責處理網路數據,因此它需要的特殊代碼要比其他相關運動體少。只需在PhysxBall.cs
中添加一個計時器,該計時器將在幾秒鐘後使球失效(這與運動球的情況完全相同),以及一個設置初始前進速度的方法。
這兩個方法都由Init()
方法涵蓋,例如以下:
C#
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);
}
}
輸入
為了生成球,需要按照與運動球相同的三個步驟擴展代碼,但改為使用鼠標的第二個按鈕:
1. NetworkInputData
在NetworkInputData.cs
中簡單添加一個新的按鈕標誌:
C#
using Fusion;
using UnityEngine;
public struct NetworkInputData : INetworkInput
{
public const byte MOUSEBUTTON1 = 0x01;
public const byte MOUSEBUTTON2 = 0x02;
public byte buttons;
public Vector3 direction;
}
2. BasicSpawner
在BasicSpawner.cs
中,以與第一個相同的方式連結第二個鼠標按鈕,並相應地設置標誌:
C#
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);
}
3. Player
Player.cs
持有生成實際球的預制件的代碼,所以除了需要像這樣的預制件引用外,
C#
[SerializeField] private PhysxBall _prefabPhysxBall;
Player
還必須呼叫spawn並使用之前創建的Init()
方法設置速度(只是一個常數乘以最後的前進方向)。
C#
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
字段,構建並執行。