【Unity 插件推薦】幻鏡連結助力多人遊戲開發,Mirror 插件實戰分享!

目錄
【Unity 插件推薦】幻鏡連結助力多人遊戲開發,Mirror 插件實戰分享!

 

前言

 

終於來了!之前有許多小夥伴私訊我,想看如何實現多人遊戲的完整流程,這次就來滿足大家的需求!關於 Mirror  插件,其實我已經關注很久,最近終於有時間整理出來。這篇 Mirror 結合 Unity教學實戰,將帶你一步步了解並掌握多人遊戲的實現流程!

Mirror 是一個簡單且高效的開源 Unity 多人遊戲網路框架,不僅功能強大,而且在 Unity 資源商店中免費提供!這篇文章將帶你一步步了解如何利用 Mirror 開發多人線上遊戲,內容涵蓋【插件的匯入】、【網路管理器的建立】、【玩家同步】、【控制】、【動畫】、【聊天功能】與【場景切換】等多項實用技巧,文中還附上【專案原始碼】與【補充說明】,幫助開發者快速上手,跨越技術門檻,實現即時互動的遊戲體驗!如果你對多人遊戲開發充滿熱情,千萬不要錯過這篇文章。

 

【Unity 插件推薦】幻鏡連結助力多人遊戲開發,Mirror 插件實戰分享!

 

 

Unity Mirror 插件介紹

 

Mirror 是一款專為 Unity遊戲開發的開源網路解決方案,適用於多人遊戲和其他需要即時互動的應用程序。它簡化了網路遊戲的開發,提供直觀的 API 和強大的工具支援,讓開發者能專注於遊戲內容的創作,而不必擔心網路通訊的複雜性Mirror 基於 Unity 的 Transport 系統,支援多種網路拓撲結構,並且完全開放原始碼,方便開發者進行定制與擴展

 

Mirror Logo 圖片

 

功能特色

  1. 高效能的網路傳輸
    Mirror 使用輕量級的傳輸層,支援高效能數據同步,適合即時性要求高的【多人遊戲】。
  2. 易於使用的 API
    直觀的 API 設計,簡化了網路功能的集成,開發者只需編寫少量代碼即可實現【玩家同步】和【狀態更新】
  3. 跨平台支援
    Mirror支援多種平台,包括 【Windows】、【Unity】、【iOS】、【Android】 和 【WebGL】,開發者可以一次開發,多平台發布。
  4. 擴展性強
    Mirror 提供了開放源碼,並支援各種網路拓撲結構,如【主從模式】和【P2P 模式】,開發者可以根據遊戲需求進行擴展與優化。
  5. 整合性工具
    Mirror 提供整合性工具,如【Network Manager】和【Network Transform】,幫助開發者快速配置網路邏輯,節省開發時間。
  6. 社群與開源優勢
    Mirror 擁有活躍的開發社群,開發者可以從開源代碼中學習並參與項目貢獻,獲得即時的技術支援。

 

適用場景

  1. 即時對戰遊戲
    適用於【FPS】、【MOBA】和【競速遊戲】,Mirror 的高效數據同步功能確保玩家之間的互動能夠即時響應。
  2. 合作遊戲
    適用於【合作闖關】、【沙盒世界】,Mirror 可輕鬆實現多名玩家的協同合作與資源共享。。
  3. 大型多人遊戲 (MMO)
    支援【大型地圖分區】與【負載平衡】,適用於 MMO 類型的多人遊戲,提供穩定的網路體驗。
  4. 多人 VR/AR 體驗
    提供多人 VRAR 互動支持,讓玩家能在虛擬或增強現實中實現流暢的即時互動。
  5. 模擬與訓練應用
    適合用於多人【模擬器】或【教學訓練平台】,確保數據同步與互動的高穩定性。

 

 

Unity Mirror 插件導入 

 

https://assetstore.unity.com/ packages /tools/network/mirror-129321

 

導入 Mirror 插件

 

 

Unity Mirror 簡單介紹

 

一、RPC 調用

有三個關鍵字如果被用於修飾函數,則函數不會在本地調用,而是在遠端調用。 [Command]、[ClientRpc]、[TargetRpc]。

  • Command 在客戶端調用,在服務端執行,並且方法名稱以"Cmd"開頭。
  • ClientRpc 在服務端調用,在所有與服務端連接的客戶端執行,並且方法名稱以"Rpc"開頭。
  • TargetRpc 在服務端調用,在指定的與服務端連接的客戶端執行,該方法至少有一個,NetworkConnection 的形參,用來確定是在哪一個客戶端執行,並且方法名稱以"Target"開頭。
  • ServerCallback:只能由伺服器調用,在伺服器上執行。且方法名稱以"Server"開頭。用法和 TargetRpc 類似

使用如下:

 

using Mirror;

using UnityEngine;

public class MyNetworkBehaviour : NetworkBehaviour

{

   [Command]

   void CmdFire()

   {

       // 在服務器上調用

   }

   [ClientRpc]

   void RpcGetHit()

   {

       // 在客戶端上調用

   }

}


例如某個客戶端角色得分加分:

 

# TargetRpc

NetworkIdentity netIdentity = GetComponent<NetworkIdentity();

TargetShowMessage(netIdentity.connectionToClient,1);

[TargetRpc]

private void TargetShowMessage(NetworkConnection target, int count)

{

   sumCount += count;//加分

}

# ServerCallback

[ServerCallback]

private void ServerPlayerReady(NetworkConnection connection)

{

   // 將指定客戶端標記為已準備狀態的邏輯

}
 

二、錯誤注意

  1. 場景內所有掛在了你的程式碼的物體都會預設加入 network identity,但 network manager 元件與 network identity 元件放在一個物件上會報錯。
  2. 如果物體內有 network manager 組件但是沒有 Kcp transport 組件,會報錯。
  3. 如果場景內有多個 network manager 元件,會報錯。
  4. 如果角色預製體託不進 player prefab 欄,可能是沒有掛在 network identity 元件。
  5. 角色代碼必須有 if (!isLocalPlayer) return;否則。 。 。後果自己知道。

 

 

Unity Mirror 基本使用

 

一、創建場景的網路管理器

網路管理器是多人遊戲的核心控制元件。網路管理器是多人遊戲的核心控制元件。

在起始場景中建立一個空遊戲對象,然後新增新建立的網路管理器元件(networkManager,Kcp Transport,networkManagerHUD 元件)。

 

網路管理器是多人遊戲的核心控制元件。網路管理器是多人遊戲的核心控制元件。  在起始場景中建立一個空遊戲對象,然後新增新建立的網路管理器元件(networkManager,Kcp Transport,networkManagerHUD 元件)。

 

kcp transport 組件掛載在 networkManager 的 transport 上。

 

kcp transport 組件掛載在 networkManager 的 transport 上。

 

並配置 Scene 場景,offline 和 online 是離線介面和遊戲介面,比如說我們新建一個 offline 場景,在裡面放一個 network manager 的 network managerHUD,然後再新建一個online 場景,把他們都註冊到 build setting(生成設定)裡的 build 裡的場景列中(拖進去),offline 在上。然後我們進入 offline 場景,運行,點擊 host,便會進入 online(線上場景)。
 

二、創建一個玩家

建立玩家物件 Player,為玩家新增 networkIdentity 作為在網路同步的唯一識別。一般遊戲內除了包含 network manager 組件的物件都要掛在此組件,包括即將孵化的。這東西只有兩個選項,一個勾選框 Server Only,意思是只有服務端能操作,大家依照自己的需求勾選。第二個是 visible,裡面有三個選項:預設(Default)、強制隱藏(Force Hidden)、強制顯示(ForceShown),個人覺得沒啥用,大家預設就行。

 

建立玩家物件 Player,為玩家新增 networkIdentity 作為在網路同步的唯一識別。一般遊戲內除了包含 network manager 組件的物件都要掛在此組件,包括即將孵化的。這東西只有兩個選項,一個勾選框 Server Only,意思是只有服務端能操作,大家依照自己的需求勾選。第二個是 visible,裡面有三個選項:預設(Default)、強制隱藏(Force Hidden)、強制顯示(ForceShown),個人覺得沒啥用,大家預設就行。

 

只有掛載了 networkIdentity,網路中樞才能辨識到這個物件,並對之進行同步。接下來將 Player 當作一個预制体儲存,並在場景中刪除,後拖曳預製體到網路中樞(networkManager)的 Player Prefab 插槽中,以後它的產生就完全依靠網路中樞在連接到主機後自動產生。

自動建立播放器(Auto Create Player):預設勾選,勾選的話當連接伺服器時會自動產生上面的「玩家預製件」。
 

只有掛載了 networkIdentity,網路中樞才能辨識到這個物件,並對之進行同步。接下來將 Player 當作一個预制体儲存,並在場景中刪除,後拖曳預製體到網路中樞(networkManager)的 Player Prefab 插槽中,以後它的產生就完全依靠網路中樞在連接到主機後自動產生。  自動建立播放器(Auto Create Player):預設勾選,勾選的話當連接伺服器時會自動產生上面的「玩家預製件」。

 

註:如果角色預製體託不進 player prefab 欄,可能是沒有掛在 network identity 元件

為玩家新增 Network Transform,同步網路中連網遊戲物件的位置、旋轉與縮放,並勾選 networkTransport 的 Client Authority 屬性。

Mirror 目前提供 2 種 Network Transform:
 

為玩家新增 Network Transform,同步網路中連網遊戲物件的位置、旋轉與縮放,並勾選 networkTransport 的 Client Authority 屬性。  Mirror 目前提供 2 種 Network Transform:

 

Reliable:低帶寬,與Rpcs/Cmds/等相同的延遲。

Unreliable:高帶寬,極低延遲。

使用Reliable,除非需要超低延遲。
 

為玩家新增 Network Transform,同步網路中連網遊戲物件的位置、旋轉與縮放,並勾選 networkTransport 的 Client Authority 屬性。  Mirror 目前提供 2 種 Network Transform:

 

註:後面我們會利用玩家 body 的 Scale 來翻轉,這裡給 body 也加上 Network Transform 程式碼,記勾選 Sync Scale。

 

註:後面我們會利用玩家 body 的 Scale 來翻轉,這裡給 body 也加上 Network Transform 程式碼,記勾選 Sync Scale。

 

三、新增玩家初始生成位置

建立幾個空物件作為玩家的初始生成位置,新增 Network Start Position 腳本,並將物件拖曳到適當的位置。

 

建立幾個空物件作為玩家的初始生成位置,新增 Network Start Position 腳本,並將物件拖曳到適當的位置。

 

並在 NetworkManager 中選擇隨機(Random)或輪詢(Round Robin)的出生點選擇方式。

 

1.Random:生成為隨機(可能相同的生成位置將被兩個或更多玩家使用)

2.Round Robin:循環(使用每個可用位置,直到客戶端數超過生成點數)。
 

1.Random:生成為隨機(可能相同的生成位置將被兩個或更多玩家使用)  2.Round Robin:循環(使用每個可用位置,直到客戶端數超過生成點數)。

 

效果:

 

效果:

 

四、玩家控制

網路同步需要注意的一些事情:

  1. 需要用到連網功能的腳本都要加入 using Mirror 來使用對應 API,並且繼承 NetworkBehaviour 而不是 MonoBehaviour。
  2. 涉及玩家輸入時,首先要進行 isLocalPlayer 的判斷,透過 islocalplayer 來判斷是否具有目前物件的權限。

為控制遊戲對象,新增一個簡單的人物控制腳本為 PlayerControl.cs,繼承 NetworkBehaviour。

 

using UnityEngine;

using Mirror;

public class PlayerControl : NetworkBehaviour //MonoBehaviour --> NetworkBehaviour

{

   private Rigidbody2D rb; // 剛體組件

   void Start()

   {

       rb = GetComponent<Rigidbody2D>(); // 獲取剛體組件

   }

   //速度:每秒移動5個單位長度

   public float moveSpeed = 5;

   void Update()

   {

       if (!isLocalPlayer) return; //不應操作非本地玩家

       Move();

   }

   void Move()

   {

       //通過鍵盤獲取水平軸的值,範圍在-1到1

       float horizontal = Input.GetAxisRaw("Horizontal");

       rb.velocity = new Vector2(horizontal * moveSpeed, rb.velocity.y); // 設置剛體速度

       if (horizontal != 0)

       {

           transform.GetChild(0).localScale = new Vector3(-horizontal, 1, 1); // 翻轉角色

       }

   } 

}


效果:

 

效果:

 

 

五、同步攝影機

對於在每個客戶端獨立產生的物件(這裡以每位玩家的 camera 為例),需要將 start 方法修改為 OnStartLocalPlayer(),這樣可以避免多個客戶端的攝影機被修改為同一台。

OnStartLocalPlayer:僅在 client 執行,當腳本所在物體為玩家角色時調用,用來設定追蹤相機,角色初始化等。

 

public override void OnStartLocalPlayer()

{

   rb = GetComponent<Rigidbody2D>(); // 獲取剛體組件

    

   //攝像機與角色綁定

   Camera.main.transform.SetParent(transform);

   Camera.main.transform.localPosition = new Vector3(0, 0, Camera.main.transform.position.z);

}   

 

效果:
 

效果:

 

六、同步不同角色的名字和顏色修改

同步變數需要加入同步變數的標記[SyncVar(hook=nameof(FunctionExecOnClient))],當同步變數改變時就會呼叫後面的 FunctionExecOnClient 方法。

當伺服器的場景中的一個 SyncVar 的值發生變化時,就同步給其它所有客戶端。

對於同步變數的修改,使用[Command]標記(針對方法的標記,方法名稱以 Cmd 開頭)。
 

using TMPro;

public TMP_Text nameText;

//需要把name和顏色同步給其他玩家,添加同步變量的標記[SyncVar(hook=nameof(FunctionExecOnClient))]

[SyncVar(hook = nameof(OnPlayerNameChanged))]

public string playerName;

[SyncVar(hook = nameof(OnPlayerColorChanged))]

private Color playerColor;

//申明OnPlayerNameChanged和OnPlayerColorChanged這兩個方法

//第一個變量(oldstr)是同步變量修改前的值,第二個(newstr)是同步變量修改後的值

private void OnPlayerNameChanged(string oldstr, string newstr)

{

   nameText.text = newstr;

}

private void OnPlayerColorChanged(Color oldCor, Color newCor)

{

   nameText.color = newCor;

}

void Update()

{

  if (!isLocalPlayer) return; //不應操作非本地玩家

  

  Move();

  if (Input.GetKeyDown(KeyCode.Space))

  {

      //隨機生成顏色和名字

      ChangedColorAndName();

  }

}

public override void OnStartLocalPlayer()

{

   //。。。

   //開始就隨機生成顏色和名字

   ChangedColorAndName();

}

//player 的隨機名稱和顏色

private void ChangedColorAndName()

{

   //隨機名稱和顏色

   var tempName = $"Player{Random.Range(1, 999)}";

   var tempColor = new Color(Random.Range(0, 1f), Random.Range(0, 1f), Random.Range(0, 1f), 1);

   //同步變量進行修改

   CmdSetupPlayer(tempName, tempColor);

}

//對於同步變量的修改,使用[Command]標記(針對方法的標記,方法名以Cmd開頭)

//通過這個方法同時對name和顏色進行修改

[Command]

private void CmdSetupPlayer(string name, Color color)

{

   playerName = name;

   playerColor = color;

}
 

效果:

 

效果:

 

七、同步動畫

掛載 Network Animator 元件。

 

掛載 Network Animator 元件。

 

private Animator anim; // 動畫組件

anim = gameObject.GetComponentInChildren<Animator>(); // 獲取動畫組件

public override void OnStartLocalPlayer()

{

  //。。。

  

  anim = gameObject.GetComponentInChildren<Animator>(); // 獲取動畫組件

}

void Update()

{

   if (!isLocalPlayer) return; //不應操作非本地玩家

   //。。。

   

   //攻擊動畫控制

   if (Input.GetMouseButtonDown(0))

   {

       anim.SetTrigger("isAttack");

       anim.SetBool("isIdle", false);

   }else{

       anim.SetBool("isIdle", true);

   }

}

 

效果:

 

效果:

 

八、同步子彈

bomb 就是普通的炸彈預製體。

 

bomb 就是普通的炸彈預製體。

 

方法一

[ClientRpc]關鍵字,服務端可以向所有的連接的客戶端發送同步指令,方法名稱也需要 Rpc 開頭。

 

public GameObject bomb;//炸彈預制體

void Update()

{

   if (!isLocalPlayer) return; //不應操作非本地玩家

   //。。。

   

   //生成炸彈

   if (Input.GetMouseButtonDown(1))

   {

       Cmdshoot();

   }

}

[Command]

private void Cmdshoot()

{

   RpcWeaponFire();

}

[ClientRpc]

private void RpcWeaponFire()

{

   GameObject b = Instantiate(bomb, transform.position, Quaternion.identity);

   b.transform.Translate(1, 0, 0);//防止子彈撞到角色

   b.GetComponent<Rigidbody2D>().AddForce(Vector2.up * 500f);

}

 

效果:

 

效果:

 

方法二

NetworkManager 最下面有個列表(Registered Spawnable Prefab),他是用來放遊戲中需要孵化的物體的,比如說 enemy(敵人),bullet(子彈)啊,都給它拖進去。

 

NetworkManager 最下面有個列表(Registered Spawnable Prefab),他是用來放遊戲中需要孵化的物體的,比如說 enemy(敵人),bullet(子彈)啊,都給它拖進去。

 

ps:記得給炸彈添加 Network Identity 組件,不然拖不進去。

 

public GameObject bomb;//炸彈預制體

void Update()

{

   if (!isLocalPlayer) return; //不應操作非本地玩家

   //。。。

   

   //生成炸彈

   if (Input.GetMouseButtonDown(1))

   {

       Cmdshoot();

   }

}

[Command]

private void Cmdshoot()

{

   GameObject b = Instantiate(bomb, transform.position, Quaternion.identity);

   b.transform.Translate(1, 0, 0);//防止子彈撞到角色

   b.GetComponent<Rigidbody2D>().AddForce(Vector2.up * 500f);

   Destroy(b, 2.0f);//兩秒後刪除

   NetworkServer.Spawn(b);//服務器孵化,同步客戶端

}

 

效果:

 

效果:

 

問題:

你會發現客戶端對炸彈施加的 AddForce 力並沒有效果,原因是我們沒有添加同步剛體的元件,為炸彈添加 Network Rigidbody 2D 元件。

 

你會發現客戶端對炸彈施加的 AddForce 力並沒有效果,原因是我們沒有添加同步剛體的元件,為炸彈添加 Network Rigidbody 2D 元件。

 

效果:

 

效果:

 

九、聊天功能

新增 ChatController 腳本。

 

using UnityEngine;

using Mirror;

using TMPro;

using UnityEngine.UI;

public class ChatController : NetworkBehaviour

{

   public TMP_InputField chatText;//輸入框

   public Button chatBtn;//發送按鈕

   public GameObject chatInfo;//聊天框內容預制體

   public GameObject chatFrame;//聊天框

   public PlayerController playerController ;

   [SyncVar(hook = nameof(OnChatTextStringChanged))]

   public string chatTextString;

   private void OnChatTextStringChanged(string oldstr, string newstr)

   {

       //添加聊天內容

       GameObject ci = Instantiate(chatInfo);

       ci.GetComponent<TMP_Text>().text = newstr;

       ci.transform.SetParent(chatFrame.transform);

   }

   void Awake()

   {

       chatBtn.onClick.AddListener(SendBtn);

   }

   public void SendBtn()

   {

       if (player != null)

       {

           playerController.CmdSendPLayerMessage(chatText.text);

       }

   }

}
 

修改 PlayerController,呼叫傳送人物名字。
 

private ChatController chatController;

void Awake()

{

   chatController = FindObjectOfType<ChatController>();

}

public override void OnStartLocalPlayer()

{

    //。。。

    

   chatController.playerController = this;

}

[Command]

public void CmdSendPLayerMessage(string message)

{

   if (chatController != null)

   {

       chatController.chatTextString = playerName + "說:" + message;

   }

}


繪製 UI 頁面,記得新增 Network Identity 元件。

 

 繪製 UI 頁面,記得新增 Network Identity 元件。

 

記得給聊天的 UI canvas 掛載 Network Identity 腳本。

 

記得給聊天的 UI canvas 掛載 Network Identity 腳本。

 

效果:

 

效果:

 

十、場景同步切換

新建三個場景 NetworkManager 物件上。

 

新建三個場景 NetworkManager 物件上。

 

新增 ScenceController 程式碼,控制 NetworkManagerHUD 的顯隱。

 

using UnityEngine;

using UnityEngine.UI;

using Mirror;

using UnityEngine.SceneManagement;

public class ScenceController : MonoBehaviour

{

   private void Update()   {

           Scene scene = SceneManager.GetActiveScene();

           //控制NetworkManagerHUD的顯隱

           if(scene.name == "Main"){

               GetComponent<NetworkManagerHUD>().enabled = false;

           }else{

               GetComponent<NetworkManagerHUD>().enabled = true;

           }

   }

   

   //開始遊戲,場景切換

   public void ButtonLoadScene()

   {

       SceneManager.LoadScene("SampleScene1");

   }

}
 

HUD 的顯隱,報錯 HUD 視圖你不在主場景顯示。

Main 場景為遊戲開始頁面,預設就放一個按鈕,按鈕呼叫 ButtonLoadScene 方法,Network Manager 只需要在初始場景掛載即可(及 Main 場景),前面程式碼已經控制了 NetworkManager。

 

Main 場景為遊戲開始頁面,預設就放一個按鈕,按鈕呼叫 ButtonLoadScene 方法,Network Manager 只需要在初始場景掛載即可(及 Main 場景),前面程式碼已經控制了 NetworkManager。

 

掛載對應的場景。


 

掛載對應的場景。

 

SampleScene1 和 SampleScene2 場景基本上沒啥區別,更前面的遊戲頁面一樣,刪除原本的 NetworkManager 對象,防止與主介面 Main 場景的衝突。
 

SampleScene1 和 SampleScene2 場景基本上沒啥區別,更前面的遊戲頁面一樣,刪除原本的 NetworkManager 對象,防止與主介面 Main 場景的衝突。

 

SampleScene1 和 SampleScene2 場景基本上沒啥區別,更前面的遊戲頁面一樣,刪除原本的 NetworkManager 對象,防止與主介面 Main 場景的衝突。

 

新增 ButtonChangeScene 方法,控制遊戲內的場景切換,方法掛載在 SampleScene1 和 SampleScene2 場景的場景切換按鈕上。

 

//同步切換場景

public void ButtonChangeScene()

{

   if (isServer)

   {

       var scene = SceneManager.GetActiveScene();

       NetworkManager.singleton.ServerChangeScene

       (

           scene.name == "SampleScene1" ? "SampleScene2" : “SampleScene1”

       );

   }

   else

   {

       Debug.Log("你不是host");

   }

}
 

效果:

 

效果:

 

十一、重新繪製一個 HUD 介面

NetworkManagerHUD(需要配合 Network Manager 元件),他會自動繪製一個 GUI:

 

NetworkManagerHUD(需要配合 Network Manager 元件),他會自動繪製一個 GUI:

 

 

Host(主機):相當於又是伺服器又是客戶端。

Client:連接服務端,後面是服務端 IP 位址,localhost 為本機端口,相當於自己連接自己。

Server Only:只當服務端。

但是,這個 UI 介面不太好看,所以我們通常不用這個元件,都會自己做 GUI。

在場景中新增三個按鈕。

 

Host(主機):相當於又是伺服器又是客戶端。  Client:連接服務端,後面是服務端 IP 位址,localhost 為本機端口,相當於自己連接自己。  Server Only:只當服務端。  但是,這個 UI 介面不太好看,所以我們通常不用這個元件,都會自己做 GUI。  在場景中新增三個按鈕。

 

新增 MyNetworkManagerHUD 程式碼,掛載在遊戲頁面,實例程式碼。

 

using UnityEngine;

using UnityEngine.UI;

using Mirror;

public class MyNetworkManagerHUD : MonoBehaviour

{

   private NetworkManager networkManager; // 創建 NetworkManager 對象

   public GameObject btn;

   public GUISkin mySkin;

   private GameObject startHost;//啟動網絡主機按鈕

   private GameObject startClient;//啟動網絡客戶端按鈕

   private GameObject stopHost;//停止網絡主機或客戶端按鈕

   void Awake()

   {

       networkManager = FindObjectOfType<NetworkManager>();

       startHost = GameObject.Find("StartHost");

       startClient = GameObject.Find("StartClient");

       stopHost = GameObject.Find("StopHost");

       startHost.GetComponent<Button>().onClick.AddListener(OnStartHost);

       startClient.GetComponent<Button>().onClick.AddListener(StartClient);

       stopHost.GetComponent<Button>().onClick.AddListener(StopHost);

   }

   private void Update()

   {

       // GetComponent<NetworkManagerHUD>().enabled = true;

       if (!NetworkClient.isConnected && !NetworkServer.active) // 檢查客戶端和服務器的連接狀態

       {

           startHost.SetActive(true);

           startClient.SetActive(true);

           stopHost.SetActive(false);

       }

       else

       {

           startHost.SetActive(false);

           startClient.SetActive(false);

           stopHost.SetActive(true);

       }

   }

    private void OnStartHost()

   {

       networkManager.StartHost(); // 啟動網絡主機

   }

   private void StartClient()

   {

       networkManager.StartClient(); // 啟動網絡客戶端

   }

   private void StopHost()

   {

       networkManager.StopHost(); // 停止網絡主機或客戶端

   }

}

 

當然,原廠的 NetworkManagerHUD 元件就沒用了,可以刪除了,記得同步刪除前面控制 NetworkManagerHUD 顯隱的程式碼。

運行效果:
 

運行效果:

 

十二、查找伺服器

使用 network discoveryHUD+network discovery 元件取代原先的 NetworkManagerHUD。

這個 network discovery 元件也需要配合 network manager 使用,他可以列出區域網路內所有的伺服器,其中有個 transport 欄,我們需要把與 network manager 元件在一起的 Kcp transport 元件拖進去,不然無法運作。
 

使用 network discoveryHUD+network discovery 元件取代原先的 NetworkManagerHUD。  這個 network discovery 元件也需要配合 network manager 使用,他可以列出區域網路內所有的伺服器,其中有個 transport 欄,我們需要把與 network manager 元件在一起的 Kcp transport 元件拖進去,不然無法運作。

 

network discoveryHUD,與 networkmanagerHUD 差不多,唯獨少了一個 Client,多了一個 find server。

 

network discoveryHUD,與 networkmanagerHUD 差不多,唯獨少了一個 Client,多了一個 find server。

 

作用是點擊 find server 就會把區域網路內的所有比賽(伺服器)列出來,但僅限區域網路。

運行效果:

 

運行效果:

 

十四、角色死亡復活

 

// 角色是否死亡的標志

[SyncVar(hook = nameof(OnIsDeadChanged))]

public bool isDead = false;

// 當角色死亡狀態改變時的回調方法

void OnIsDeadChanged(bool oldValue, bool newValue)

{

    if (newValue)

    {

        // 執行死亡邏輯,例如播放死亡動畫、禁用角色控制等

        Debug.Log("Player has died.");

        Destroy(gameObject, 2f); // 延遲2秒後銷毀角色對象

    }

}

void Update()

{

    if (Input.GetKeyDown(KeyCode.T))

    {

         CmdDestroyPlayerServer();

         

         // 創建一個新的Camera對象

         GameObject cameraObject = new GameObject("Main Camera");

         // 添加Camera組件到對象上

         Camera cameraComponent = cameraObject.AddComponent<Camera>();

         // 設置攝像機的位置和旋轉

         cameraComponent.transform.position = new Vector3(0, 0, -10f);

         cameraComponent.transform.rotation = Quaternion.identity;

     }

}

[Command]

private void CmdDestroyPlayerServer()

{

   isDead = true;

}
 

其他地方書寫復活方法(重新生成角色)。

 

public class GameManager : MonoBehaviour

{

   void Update()

   {

       if (Input.GetKeyDown(KeyCode.R))

       {

          //讓當前客戶端覆活角色

            NetworkClient.AddPlayer();

       } 

   }

}


效果:

 

效果:


十三、自己編一個 network manager

這裡簡單實作一個創建角色的功能。

 

using Mirror;

using UnityEngine;

using UnityEngine.UI;

public class MyNetworkManager : NetworkManager//繼承network manager類

{

   public InputField myname; // 輸入玩家名稱的InputField

   // 在服務器啟動時調用

   public override void OnStartServer()

   {

       Debug.Log("啟動服務器");

       // 啟動服務器

       base.OnStartServer();

       // 注冊CreateMMOCharacterMessage消息的處理方法

       NetworkServer.RegisterHandler<CreateMMOCharacterMessage>(OnCreateCharacter);

   }

   public override void OnStopServer()

   {

       Debug.Log("關閉服務器");

       // 關閉服務器

       base.OnStopServer();

   }

   public override void OnServerConnect(NetworkConnectionToClient conn)

   {

       Debug.Log("處理連接事件");

       // 處理連接事件

       base.OnServerConnect(conn);

   }

   public override void OnServerDisconnect(NetworkConnectionToClient conn)

   {

       Debug.Log("處理斷開事件");

       // 處理斷開事件

       base.OnServerDisconnect(conn);

   }

   // CreateMMOCharacterMessage消息結構體

   public struct CreateMMOCharacterMessage : NetworkMessage

   {

       public string playername; // 玩家名稱

   }

   // 在客戶端連接到服務器時調用

   public override void OnClientConnect()

   {

       base.OnClientConnect();

       // 在這里發送消息,或者您想要的任何其他地方

       CreateMMOCharacterMessage characterMessage = new CreateMMOCharacterMessage       {

           // playername = myname.text // 設置玩家名稱為InputField中的文本

           playername = "測試" // 設置玩家名稱為InputField中的文本

       };

       NetworkClient.Send(characterMessage); // 發送消息給服務器

   }

   // 創建角色的方法,在收到CreateMMOCharacterMessage消息時調用

   // 參數conn:與服務器的連接;參數message:接收到的消息

   void OnCreateCharacter(NetworkConnectionToClient conn, CreateMMOCharacterMessage message)

   {

       //PlayerPrefab是在Network Manager的Inspector中指定的,

       //但您可以在每個比賽中使用不同的預制體,例如:

       GameObject gameobject = Instantiate(playerPrefab); // 實例化玩家預制體

       //根據遊戲的需要,應用消息中的數據

       Player player = gameobject.GetComponent<Player>();

       player.playerName = message.playername; // 將玩家名稱賦值給Playercode組件中的playername變量

       //將此遊戲對象添加為連接上的玩家的控制對象

       NetworkServer.AddPlayerForConnection(conn, gameobject);

   }

}
 

移除原來的 NetworkManager,掛載自己寫的程式碼,移除自動的建立角色的勾選,不然開始會建立兩個主角。

 

移除原來的 NetworkManager,掛載自己寫的程式碼,移除自動的建立角色的勾選,不然開始會建立兩個主角。

 

運作效果,正常。

 

運作效果,正常。

 

AOI 迷霧效果實現

將 Spatial Hashing Interest Management 元件與您的網路管理員相同的物件中。

 

將 Spatial Hashing Interest Management 元件與您的網路管理員相同的物件中。

 

參數:可見距離、多久顯示出來、3d&2d 切換、調試滑桿。

走近才顯示物品:

 

參數:可見距離、多久顯示出來、3d&2d 切換、調試滑桿。  走近才顯示物品:

 

 

開房間的功能

 

官方其實已經有 demo,在 Mirror/Examples/MultipleMatches/Scenes/Main,我們可以先看看效果。

官方其實已經有 demo,在 Mirror/Examples/MultipleMatches/Scenes/Main,我們可以先看看效果。

 

 

連接線上伺服器(待續)

 

此為 Linux 伺服器,修改線上伺服器 ip 和連接埠號。

 

此為 Linux 伺服器,修改線上伺服器 ip 和連接埠號。

 

對應埠記得去伺服器加安全群組白名單。

 

對應埠記得去伺服器加安全群組白名單。

 

移除 HUD 腳本元件。

 

移除 HUD 腳本元件。

 

書寫程式碼,控制是伺服器還是客戶端。
 

書寫程式碼,控制是伺服器還是客戶端。

 

先打包一個伺服器,所以先勾選是伺服器。

 

先打包一個伺服器,所以先勾選是伺服器。

 

然後打包一個 Linux 伺服器端程式。

 

然後打包一個 Linux 伺服器端程式。

 

ps:沒有的記得先去安裝 unity 模組。

 

沒有的記得先去安裝 unity 模組。

 

把伺服器端程式全部上傳到伺服器上。

先把可執行檔新增權限。

 

把伺服器端程式全部上傳到伺服器上。  先把可執行檔新增權限。

 

運行可執行程序。

 

運行可執行程序。

 

然後就可以正常打包客戶端,連接伺服器遊玩了。

打包記得去除 AppIsServer 的勾選和修改 Target Platfom 為 windows。

連線成功。

 

然後就可以正常打包客戶端,連接伺服器遊玩了。  打包記得去除 AppIsServer 的勾選和修改 Target Platfom 為 windows。  連線成功。

 

 

Unity Mirror 相關教學影片

 

 

 

 

相似插件

 

另外,之前有介紹過類似的插件 Photon,感興趣的夥伴可以去看看,兩者各有特色,可以根據需求選擇合適的工具!

【Unity 插件推薦】用光子引擎實現多人線上遊戲,Photon PUN2 框架實作教學!

 

Photon Engine Logo 圖片

 

 

幻鏡連結插件下載點

 

【Mirror

GitHub 下載連結:Mirror

Asset Store下載連結:Mirror

官方網站:Mirror

官方文檔:Mirror

專案原始碼:Mirror (原作者用心分享了專案的主要功能思路與代碼,若需要完整原始碼,原作者提供下載服務,僅收取辛苦費,作為對創作的支持與肯定。)

聲明:本平台僅介紹資訊,未參與收費行為,亦未收取任何費用。

————————————————

以上內容改編節錄 CSDN 作者:向宇it

 

更多好用插件:【Unity 好用插件推薦】持續更新,一起讓遊戲開發事半功倍!

 

 

 

本文原創(或整理)於亞洲電玩通,未經作者與本站同意不得隨意引用、轉載、改編或截錄。

特約作家簡介

X
A
Y
B
JamXu的頭像
JamXu
十年遊戲研發
二十年遊戲台主
三十年遊戲玩家

經中華網龍遊戲企劃進入遊戲圈,然後被雷打到去學程式前後端又學了點設計帶帶幾個研發團隊,見證了 3D 渲染技術及遊戲引擎互相進步,也見證了研發代理的更迭與博弈遊戲的興起,再毅然研究起 SEO 網路行銷社群廣告投放,深信自研自賣才是最大贏家,期望能為台灣研發重回輝煌時光貢獻一點力量。如果你也有遊戲夢,歡迎交流認識。


支持贊助 / DONATE

 

亞洲電玩通只是很小的力量,但仍希望為復甦台灣遊戲研發貢獻一點動能,如果您喜歡亞洲電玩通的文章,或是覺得它們對您有幫助,歡迎給予一些支持鼓勵,不論是按讚追蹤或是贊助,讓亞洲電玩通持續產出,感謝。

亞洲電玩通AsiaGameMaster - Steam 遊戲鑑賞家
亞洲電玩通AsiaGameMaster - FB 粉絲專頁
亞洲電玩通AsiaGameMaster - IG 粉絲專頁
亞洲電玩通AsiaGameMaster - Twitter
亞洲電玩通AsiaGameMaster - Yoytube 粉絲專頁
亞洲電玩通AsiaGameMaster - Tiktok

BTC

亞洲電玩通AsiaGameMaster - BTC 鏈贊助地址

352Bw8r46rfXv6jno8qt9Bc3xx6ptTcPze

 

ETH

亞洲電玩通AsiaGameMaster - ETH 鏈贊助地址

0x795442E321a953363a442C76d39f3fbf9b6bC666

 

TRON

亞洲電玩通AsiaGameMaster - TRON 鏈贊助地址

TCNcVmin18LbnXfdWZsY5pzcFvYe1MoD6f

延伸閱讀