1. 程式人生 > >Unity多人遊戲和網路功能(二) 使用網路管理類

Unity多人遊戲和網路功能(二) 使用網路管理類

[本文翻譯自Unity 5.2的官方文件]

NetworkManager是一個可以管理多玩家遊戲的網路狀態的元件。實際上,它是完全用HLAPI實現的,因此開發者可以使用其他的方式實現他的所有功能。然而,NetworkManager把很多有用的功能整合在了一起,並且使建立,執行和除錯一個多玩家遊戲儘可能的簡單。

使用NetworkManager可以不寫一行程式碼,它在編輯器上為所有功能都提供了可以配置的控制選項。NetworkManagerHUD提供了一個簡單的,預設的執行時人機互動介面,允許網路遊戲能被玩家所控制。對於高階的使用者,開發者可以從NetworkManager派生一個新類,然後重寫他的所有虛擬函式來定製他的行為。

NetworkManager提供的功能包括:

  • 遊戲狀態管理

  • 遊戲物體派生(Spawning)管理

  • 場景管理

  • 除錯資訊

  • 比賽的組織(Matchmaking)

  • 個性化定製

開始使用NetworkManager

NetworkManager可以作為多玩家遊戲的核心控制組件。首先在開始場景中建立一個空的物體,或者選擇一個方便的管理物體。然後新增NetworkManager元件(Network/NetworkManager)。新增加的NetworkManager元件像下面這個樣子:

編輯器中的這個檢視允許你配置和控制很多網路相關的配置。

NetworkManagerHUD是另外一個和NetworkManager一起工作的元件。他在遊戲執行時可以提供一個簡單的使用者介面用來控制網路的狀態。這對於開始一個網路工程是有用的。但是不建議最為遊戲最終的UI。NetworkManagerHUD如下圖所示:

真正的遊戲應該擁有一個更好的控制遊戲狀態的介面,可以讓玩家選擇玩哪種遊戲。但是在開始的時候,我們可以用他方便的開始遊戲的開發。

遊戲狀態管理

一個多玩家網路遊戲可以有三種執行模式:作為客戶端,作為專用的伺服器,或者作為同時執行客戶端和伺服器的伺服器。網路功能被設計成在這三種模式下可以使用相同的程式碼和資源。開發單機版遊戲和多人版遊戲應該是相同的事情。

NetworkManager提供了所有三種模式下使用的方法。NetworkManager.StartClient(), NetworkManager.StartServer() 和NetworkManager.StartHost() 隨時可以在指令碼中呼叫,所以他們可以被鍵盤輸入觸發呼叫或從使用者介面上觸發。預設的執行時控制器也可以呼叫相同的函式。同時,NetworkManagerHUD介面在執行時也提供觸發這些函式的開關。

不管用哪個方法來改變遊戲狀態,網路地址和埠都應該被正確的配置。當伺服器或伺服器啟動的時候,埠號將作為本地的監聽埠。當客戶端被啟動的時候,網路地址將作為連線到的地址,網路埠是連線到的埠號。

派生物體(Spawning)管理

NetworkManager可以管理從預設體中派生出來的聯網物體。大多數遊戲都用一個預設體作為主要的玩家物體,所以NetworkManager裡有一個槽位可以把這個玩家預設體拖放進去。當玩家預設體設定了之後,當有新玩家加入的時候,這個玩家物體將會被自動建立。在伺服器上,他將作為本地玩家,在遠端客戶端上將作為遠端玩家。要注意的是,拖放進來的預設體必須要帶有網路標識元件(NetworkIdentity)。

除了玩家物體,需要動態建立的其他物體必須首先在客戶端場景中註冊。這可以通過ClientScene.RegisterPrefab()函式完成,或者將預設體拖放到NetworkManager的派生列表中,這樣NetworkManager就可以自動的建立他們。NetworkManager的派生配置檢視如下:

當玩家預設體配置完之後,以伺服器模式執行,你就應該能看到玩家物體被派生出來了。停止遊戲就可以讓玩家物體被銷燬掉。運行遊戲的另外一份拷貝,並且以客戶端的身份連線進來,應該就能看到另外一個玩家物體被建立了,停止掉客戶端會使這個客戶端物體被銷燬掉。

玩家物體的建立是通過NetworkManager的預設實現(NetworkManager.OnServerAddPlayer)完成的。如果你希望定製玩家物體被建立的方式,可以重寫這個虛擬函式。預設的實現如下所示:

public virtual void OnServerAddPlayer(NetworkConnection conn,
short playerControllerId)
{
var player = (GameObject)GameObject.Instantiate(playerPrefab,
playerSpawnPos, Quaternion.identity);
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
要注意的是,在建立新的玩家物體的時候,函式NetworkManager.AddPlayerForConnected()必須被呼叫,以讓他能和特定的客戶端連線關聯起來。這將派生出這個物體,所以不一定非得為玩家物體呼叫函式NetworkServer.Spawn()。

開始位置

要控制玩家物體的派生位置,可以使用NetworkStartPosition元件。NetworkManager會在場景中尋找具有NetworkStartPosition的物體,如果找到了,就在其中的一個所標識的位置上派生玩家物體,並相應的調整物體的轉向。使用者可以通過NetworkManager.startPositions變數訪問到開始位置的列表,或者也可以在處理函式OnServerAddPlayer()中使用幫助函式NetworkManager.GetStartPosition()確定合適的開始位置。

場景管理

大多數遊戲都擁有不止一個場景。通常最少有一個帶標題和開始按鈕的場景,加上實際玩遊戲的場景。NetworkManager能自動管理多玩家遊戲內的場景狀態和場景切換。在NetworkManager的檢視面板中有兩個槽位,離線場景和上線場景。把場景物體拖放到相應的槽位上就能啟用場景的管理功能。

當一個伺服器或伺服器啟動之後,上線場景將被載入進來,併成為當前的聯網場景。所有連線到伺服器的客戶端也會被指引來載入這個場景。場景的名字被儲存在networkSceneName屬性中。

當網路斷開的時候(伺服器或伺服器關閉,或者客戶端斷開連線),離線場景將被載入。遊戲可以在退出多人遊戲狀態的時候自動返回主選單場景。

你也可以在遊戲進行的時候呼叫NetworkManager.ServerChangeScene()函式來切換場景,這會使所有連線的客戶端也切換場景,並修改networkSceneName屬性。

當場景管理正在工作的時候,任何修改遊戲狀態的函式呼叫(如NetworkManager.StartHost()或StopClient())都會引起場景的切換。這會應用到執行時控制UI上。所以通過設計場景並呼叫這些函式的方式,可以很容易的控制多玩家遊戲的流程。

要注意的是,場景切換會導致場景中的所有物體都被銷燬,這也包括NetworkManager本身。所以如果你希望NetworkManager在場景切換的時候被儲存下來,需要選中NetworkManager上的”Don’t Destroy On Load”選項。一般情況下,這是最合適的配置。但是,也有可能需要給每個場景帶單獨的NetworkManager,以派生不同的預設物體,或者進行不同的場景切換控制。

除錯資訊

NetworkManagerHUD檢視面板可以在執行時顯示額外的網路狀態資訊,包括:

  • 網路連線狀態

  • 活動的伺服器上帶有網路標識的物件

  • 活動的客戶端上帶有網路標識的物件

  • 連線的客戶端

同時,註冊的客戶端訊息處理函式也可以在預覽視窗中顯示:

比賽安排

NetworkManager執行時UI和檢視視窗上可以配置比賽安排伺服器。可以使用函式NetworkManager.StartMatchmaker()開啟比賽安排功能,然後將一個NetworkMatch物體賦值給NetworkManager.matchmaker屬性。一旦啟用,預設的UI將使用NetworkManager的回撥函式進行簡單的比賽安排。

在NetworkManager類裡面有虛擬函式,可以用來在派生類中定製比賽安排的處理。

個性化定製

NetworkManager裡面提供了很多虛擬函式,可以在派生類中重寫來定製處理過程。當實現這些函式的時候,需要注意預設的處理函式的實現。如在OnServerAddPlayer()函式中,函式NetworkServer.AddPlayer()必須被呼叫,以啟用連線上的玩家物體。

在伺服器和伺服器上呼叫的函式有:

// 客戶端連線時被呼叫
public virtual voidOnServerConnect(NetworkConnection conn);

// 客戶端斷開連線是被呼叫
public virtual void OnServerDisconnect(NetworkConnectionconn)
{
NetworkServer.DestroyPlayersForConnection(conn);
}

// 客戶端準備好的時候呼叫
public virtual voidOnServerReady(NetworkConnection conn)
{
NetworkServer.SetClientReady(conn);
}

// 當有一個新的客戶端加入的時候呼叫
public virtual voidOnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
var player =(GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos,Quaternion.identity);
NetworkServer.AddPlayerForConnection(conn,player, playerControllerId);
}

// 一個客戶端的玩家物體被移除的時候呼叫
public virtual voidOnServerRemovePlayer(NetworkConnection conn, short playerControllerId)
{
PlayerController player;
if (conn.GetPlayer(playerControllerId, outplayer))
{
if (player.NetworkIdentity != null&& player.NetworkIdentity.gameObject != null)
NetworkServer.Destroy(player.NetworkIdentity.gameObject);
}
}

// 有網路錯誤發生的時候呼叫
public virtual void OnServerError(NetworkConnection conn, int errorCode);

在客戶端上被呼叫函式有:

// 客戶端連線到伺服器的時候呼叫
public virtual voidOnClientConnect(NetworkConnection conn)
{
ClientScene.Ready(conn);
ClientScene.AddPlayer(0);
}

// 客戶端從伺服器斷開連線的時候呼叫
public virtual voidOnClientDisconnect(NetworkConnection conn)
{
StopClient();
}

// 有網路錯誤發生的時候呼叫
public virtual voidOnClientError(NetworkConnection conn, int errorCode);

// 被伺服器告知還沒準備好的時候呼叫
public virtual voidOnClientNotReady(NetworkConnection conn);

在比賽安排中的函式有:

// 有比賽被建立的時候呼叫
public virtual voidOnMatchCreate(CreateMatchResponse matchInfo)

// 接收到比賽列表的時候呼叫
public virtual voidOnMatchList(ListMatchResponse matchList)

// 加入比賽的時候呼叫
public voidOnMatchJoined(JoinMatchResponse matchInfo)

轉載自:

歡迎關注我的微信個人訂閱號
這裡寫圖片描述
每天多學一點0.0