4 - Physics
概述
Fusion 104將檢查Fusion如何在伺服器授權遊戲中與PhysX互動。
在本章節的最後,專案將允許玩家生成一個物理控制的球並與之互動。
設定
預設下,Fusion將在主機端上運行物理模擬,客戶端將跟隨。然而,與本機預測的物件相比,這將使物理物件處於不同的時間,如果這些物體碰撞,這將給物理模擬帶來問題。
雙重時間是一個複雜的主題,可以用多種方式處理——有些是徹頭徹尾的駭客行為,有些則對一般應用程式來說過於昂貴,或者不能提供玩家期望的即時回饋。不幸的是,並沒有一個適用於所有情況的簡單的解決方案。
在本教學中,我們將使用Fusion的物理附加元件來本機預測物理物件,將物理控制的物件與玩家控制的虛擬人偶同時放置。這是一個堅實的解決方案,也可以在生產中使用,但請記住,在PhysX中運行預測和重新模擬是昂貴的(也就是各個刷新中有多次)。
為了取得Physics附加元件,請前往下載頁面,選擇Unity套件並將其匯入到專案中。
物理物件
已連網、PhysX控制的物件的預製件使用與常規Unity PhysX物件相同的Rigidbody
,但具有不同的Fusion元件以同步名為NetworkRigidbody
的視覺效果下層物件。就網路而言,這將取代NetworkTransform
。
- 在Unity編輯器中建立一個新的空的遊戲物件
- 重新命名
GameObject
為PhysxBall
- 新增一個新的
NetworkRigidbody3D
元件。 - Fusion將顯示一個關於遺失
NetworkObject
元件的警告,請繼續並按Add Network Object
。Fusion也會自動新增一個常規的Unity剛體,因為這是PhysX模擬所需要的。 - 新增一個球體下層到
PhysxBall
- 在所有方向將它縮放小到0.2
- 將下層物件拖到上層物件上的
NetworkRigidbody3D
元件的InterpolationTarget
中。 - 從球體移除碰撞器
- 在上層物件上建立一個新的球體碰撞器,並為其指定0.1的半徑,這樣它完全覆蓋下層物件。
- 新增一個新的指令碼到遊戲物件,並且稱其為
PhysxBall.cs
, - 最後拖曳整個物件到專案資料夾來建立一個預製件
- 儲存該場景以內嵌網路物件,並且從場景刪除預製件執行個體。
對於物理物件,建議分離視覺效果並將其指派為Interpolation Target
,但這並非總是必要的。碰撞器和剛體必須與網路剛體一起位於上層物件上。
PhysxBall指令碼
因為球是由PhysX驅動的,而網路剛體負責處理已連網資料,所以它比其運動學的表親需要更少的特殊程式碼來工作。需要新增到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.cs
中,簡單地新增一個行的按鈕旗標:
C#
using Fusion;
using UnityEngine;
public struct NetworkInputData : INetworkInput
{
public const byte MOUSEBUTTON0 = 1;
public const byte MOUSEBUTTON1 = 2;
public NetworkButtons buttons;
public Vector3 direction;
}
2. 基礎生成器
在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();
...
data.buttons.Set(NetworkInputData.MOUSEBUTTON0, _mouseButton0);
_mouseButton0 = false;
data.buttons.Set(NetworkInputData.MOUSEBUTTON1, _mouseButton1);
_mouseButton1 = false;
input.Set(data);
}
3. 玩家
Player.cs
持有生成實際球預製件的程式碼,因此除了需要這樣的預製件參照之外,
C#
[SerializeField] private PhysxBall _prefabPhysxBall;
Player
也必須調用生成,並使用先前建立的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 (HasStateAuthority && delay.ExpiredOrNotRunning(Runner))
{
if (data.buttons.IsSet(NetworkInputData.MOUSEBUTTON0))
{
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.IsSet(NetworkInputData.MOUSEBUTTON1))
{
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 );
});
}
}
}
}
為了使已連網物理工作,在運行器物件上需要RunnerSimulatePhysics3D
元件。因此,開啟BasicSpawner.cs
,在StartGame
函數中新增運行器元件的行之後新增以下行:
C#
gameObject.AddComponent<RunnerSimulatePhysics3D>();
最後,為了測試新球,請將建立的預製件指派到Player
預製件上的Prefab Physx Ball
欄位,然後組建並運行它。
下一章是 主機端模式基礎5 - 屬性更改
Back to top