今天花了些時看Dino的教學,也下載了整個專案下來,但怎樣都找不到雙端移動機制的處理,而且,整個教學也好像不是那麼的完整。本來以為按步就班的跟著他的腳步就可以從頭到尾的實現一個連線的動作遊戲,但看樣子也只能當做起蒙般的教學,很多謎題也還是要自己解決。今天看的影片中比較有印象的是Lobby部份,因此,就趁著今天的文章來記錄一下這中間的過程。
Lobby(大廳)通常是玩家登入後還沒有正式進入遊玩場景時的一個過渡場景,這個地方隨著遊戲玩法不同可能會有不同的功能,像是聊天、整理物品,但最後都是可以決定進入正式遊戲的一個進入點。而在開Room的遊戲概念下,通常這裡就是配對或是等待人員到齊後可以正式進入遊戲的地方。
影片中簡化到最簡單的形態,只利用人員是否到位來進行切入遊戲場景的功能展示。但也在這樣的範例中看到了幾個重要的連線撰寫方式。像是以繼承NetworkManager
方式來達到行為改變但又保有連線功能的寫法。以及最主要的當一個連線的場景轉換到另一個連線場景時要怎麼進行。接下來的記錄過程就先從繼承後改寫行為這裡出發。
首先注意到的就是
virtual void OnStartClient() {}
virtual void OnStartLocalPlayer() {}
virtual void OnStartAuthority() {}
前二個API之前就有討論過,但第三個API,看教學和他的範例裡多數使用OnStartAuthority
,可是從官方的註解裡看到這三個API的順序實際上是有前後關係的
OnStartAuthority
OnStartClient
OnStartLocalPlayer
也就是OnStartAuthority是最先的,在教學程式範例碼中反而不太看到OnStartLocalPlayer
,這樣要如區別這是代表本機端又是自己的玩家?我對於什麼時機用這個三個API有些混亂了。
回到Lobby的實做,這二個method寫法很重要
public override void OnClientDisconnect(NetworkConnection conn)
{
base.OnClientDisconnect(conn);
OnClientDisconnected?.Invoke();
}
public override void OnServerConnect(NetworkConnection conn)
{
if (numPlayers >= maxConnections)
{
conn.Disconnect();
return;
}
if (SceneManager.GetActiveScene().name != menuScene)
{
conn.Disconnect();
return;
}
}
雖然在NetworkBehaviour
裡很常看到method前會放
但在NetworkManager
裡卻完全沒有類似的Attribute(目前的範例還沒有看到過)。所以在Manager這,應該雙端都會執行,但可以利用不同的method來達到某些區分。像是這段程式碼,在OnServerConnect
裡的行為引起了連線中斷時,應該會送給client端斷線的訊息。而Client端接收到會處理斷線行為,而Server端則會接收到client已端斷線的訊息,進而呼叫OnClientDisconnect
。從這二個method的引用,若是有Client & Server的處理順序圖,會更容易讓人理解其流程。但怎麼找都沒有看到官方的文件裡有這樣的連線順序圖,如果有個像是,會相當有用的。
轉景的部份在概念上就是產生代表Lobby的Player,而後對此Player繼承NetworkBehaviour後改寫行為。而轉入到遊玩場景後,則用另一個代表在Level的Player進行表示,並將原先Lobby Player移除。在官方給的Room範例裡,也有相同概念的用法,特別是官方的這個範例,此處的Room比較像是Lobby,而不是像實際遊玩時開設的Room。
public override void OnRoomServerPlayersReady()
{
// calling the base method calls ServerChangeScene as soon as all players are in Ready state.
#if UNITY_SERVER
base.OnRoomServerPlayersReady();
#else
showStartButton = true;
#endif
}
而在官方的這個範例中,可以看到就算是在NetworkManager的空間中,沒有Attribute可用,也仍是有在同一個method裡區分Server或是Client而給予不同行為的需求,所以特定利用了PreProcessor的方式來進行定義。這雖然是個不錯的小技巧,但又增加了一些使用上的難度和架構上的複雜度。
正常來說,隨著範例愈看愈多,會更清楚的了解到要怎麼使用。但到目前為止,卻是愈加的覺得混亂,畢盡每天能花在這上面的時間有限,雖然跟著影片好像學得快一些,但有疑問的地方也不停的堆積起來,沒有少過。只好再花些時間把教學影片重看個幾遍,看能不能找到一個完整串連起來的方法。