0x00 介紹NetWorkManager
網絡管理器,用來控制多人遊戲項目的狀態,包括遊戲狀態管理、生成管理、場景管理,匹配以及允許訪問調試信息。可以參考下(網上參考)面兩張圖片:
第一個案例是官方案例
- 基礎實現篇(1-2)
- 拓展細化篇 (3)
第二個案例是一個簡易的聊天室(4)
最近項目測試用到的,記錄一下 ,通過兩個案例讓大家充分了解unet,希望對大家有所幫助。最終效果如圖所示(因測試需求需創建新玩家時修改不同標籤等數據,所以圖中是代碼生成玩家,稍後都會寫到):
0x00 簡介
-
首先說一下Network Manager HUD組件(即連接方式的UI選擇框):
- LAN Host:選擇後就相當於主機,並且也代表第一個玩家,等待別的玩家連接。
- LAN Client: 客戶端,輸入要連接的服務器連接即可。
- LAN Server Only:僅當做服務器,等待其他玩家連接。
-
[Command] 表示客戶端向服務端發送的命令,在服務端執行
-
[SyncVar]用於標識序列化變量,實現變量同步
-
[SyncEvent]用於標識序列化事件,實現事件同步
-
[Client]表示只能在客戶端調用
-
[ClientCallback]表示客戶端執行的回調
-
[ClientRpc]表示服務端向客戶端發送的命令,在客戶端執行
0x01 創建NetWorkManager
- 首先創建一個GameObject。(自己命名如:_NetWorKManager)
- 添加NetworkManager和NetworkManagerHUD這兩個組件。
如下所示:
因需求我是自己創建一個腳本,然後繼承的NetWorkManager,稍後會仔細說道。
0X02 創建玩家
- 首先在Hierarchy面板新建一個膠囊體Capsule(樣式自定義即可)重命名爲:Player
- 給玩家添加NetWorkIdentity組件,並且將Local Player Anthority勾選。
- 如需同步和自定義玩家位置需掛NetWorkTransform組件(細化裏面詳細講解)如圖所示:
- 最後把玩家拖製爲預製體,然後把預製體拖到NetwoekManager下的Spawn Info 的 PlayerPrefab中,將Hierrarchy中的Player刪除即可。
- 給玩家添加腳本,自定義命名即可(例子爲:PlayerController)首先來製作玩家的移動。(即wasd移動,直接上代碼)
#region 字段定義
private float horizontal;
private float vertical;
#endregion
void Update()
{
if (!isLocalPlayer)
{
return;
}
PlayerMove();
}
/// <summary>
/// 簡單的人物移動
/// </summary>
private void PlayerMove()
{
horizontal = Input.GetAxis("Horizontal") * Time.deltaTime * 150.0f;
vertical = Input.GetAxis("Vertical") * Time.deltaTime * 3.0f;
transform.Rotate(0, horizontal, 0);
transform.Translate(0, 0, vertical);
}
- 現在已經可以運行程序(點擊LAN Server即可出現)
- 因自帶的NetworkTransform容易出現玩家之間卡頓同步移動現象(掛在該腳本目的是爲了玩家之前能同步顯示位置) 所以我重寫了腳本如下所示:
/// <summary>
/// 修復networkTransform,優化卡頓,解決偶爾出現同時同時移動問題
/// </summary>
public class Player_SyncPosition : NetworkBehaviour
{
#region 字段
[SyncVar] private Vector3 _syncPos;
[SyncVar] private Quaternion _syncRot;
private Transform _myTransform;
[SerializeField] private float _lerpRate = 15;
#endregion
#region 系統方法
private void Start()
{
_myTransform = gameObject.transform;
}
void FixedUpdate()
{
TransformPosition();
LerpPosition();
}
#endregion
#region 系統方法
void LerpPosition()
{
if (!isLocalPlayer)
{
_myTransform.position = Vector3.Lerp(_myTransform.position, _syncPos, Time.deltaTime * _lerpRate);
_myTransform.rotation = Quaternion.Lerp(_myTransform.rotation, _syncRot, Time.deltaTime * _lerpRate);
}
}
[Command]
void CmdProvidePositionToServer(Vector3 pos, Quaternion rot)
{
_syncPos = pos;
_syncRot = rot;
}
[ClientCallback]
void TransformPosition()
{
if (isLocalPlayer)
{
CmdProvidePositionToServer(_myTransform.position, _myTransform.rotation);
}
}
#endregion
}
效果如圖所示(因爲大小限制所以看個大概吧):