雖然說unity的腳本有支援.net 4的語法,實際上是可以用.net C#硬幹server、client(上次在資策會上課就有學員用這種方法做server端),當然這樣的難度就高了,可能也必須要懂運作理論,否則寫出來的server可能在壓力測試下就 "崩皿潰" 了....
前幾天因為研究他的官方範例,這邊寫一下結論。
基本上unity有內建一套他們自己的網路通訊方式,也可以透過他們建構出的API實做。在通訊基礎上是透過Network View 這個component當做通訊的傳送門。當你在某個元件上附加Network View 屬性後,這個物件就具有網路同步資料的功能。
Network View 中有個屬性叫做observed,在這邊丟入你已經寫好、內容包含同步資料功能的script,那這個物件在遊戲開始運作之後,就會去傳送 & 接收那些資料。一個物件身上可以被賦予多個Network View屬性,他們會同時運作。
大綱講完,重點在實做部分,跟傳輸運作有關係的script API主要為:
function OnSerializeNetworkView(stream : BitStream, info : NetworkMessageInfo) {}
這是在Network class中提供的一個func. 主要負責message sent / receive,他會同步被network view所關注的script中的資訊,也就是當你寫了一個script內含OnSerializeNetworkView(){},並且丟到observed屬性中,則OnSerializeNetworkView()裡的code就會開始運作。基本上他透過BitStream物件收發網路上的資訊,使用上不需要了解封包的問題,也不需要知道如何切割封包,官方有個簡單的範例code:void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info) { // Always send transform (depending on reliability of the network view) if (stream.isWriting) { Vector3 pos = transform.localPosition; Quaternion rot = transform.localRotation; stream.Serialize(ref pos); stream.Serialize(ref rot); } // When receiving, buffer the information else { // Receive latest state information Vector3 pos = Vector3.zero; Quaternion rot = Quaternion.identity; stream.Serialize(ref pos); stream.Serialize(ref rot); } }
BitStream有兩種型態可供參考isReading、isWriting,當isWriting = true 時表示可以寫入資料相反的就是可以讀取資料。這兩個型態應該是互斥的,一個是true,另一個就是false。再透過Serialize()這個func.收發。
Serialize()在官網的解釋為 : Serializes different types of variables,但實際上他並不是所有形態都能收發,例如你想送一個array[],就不行了...
function Serialize (ref value : boolean) : void
function Serialize (ref value : char) : void
function Serialize (ref value : short) : void
function Serialize (ref value : int) : void
function Serialize (ref value : float, maxDelta : float = 0.00001F) : void
function Serialize (ref value : Quaternion, maxDelta : float = 0.00001F) : void
function Serialize (ref value : Vector3, maxDelta : float = 0.00001F) : void
function Serialize (ref value : NetworkPlayer) : void
function Serialize (ref viewID : NetworkViewID) : void
至於第二個變數NetworkMessageInfo,這是一個結構,當封包送出時他會將一些資訊記錄在這個結構中,例如封包送出的時間戳記等等,這部分的運用我還不了解,之後再補。
再來就是game中角色在運作時的方式,本篇不講伺服器運作和玩家連線機制的部分。
假設遊戲中的所有玩家都長得一樣,那表示不管誰進入伺服器,遊戲中都會new一個一模一樣的物件。這個預先建構好的物件可能會帶有以下script:
其中:
1.PersonController:控制角色運作,與網路傳輸無關。
2.Animation:角色可能帶有動畫,這個腳本控制角色的動畫
3.NetworkTransformSync:透過Network View控制資訊的傳輸,EX:角色的位置,轉向等等。
4.NetworkAnimationSync:透過Network View控制角色同步動畫,因為透過Serialize機制並不能傳送動畫本身,只能傳送控制指令,例如一個字串。
5.ThirdPersonNetworkInit:這是最重要的,在遊戲開始後,控制哪個腳本可以運行,哪個腳本不能運行。
官方中ThirdPersonNetworkInit的內容如下:
相反的,若是場景中的角色是遠端玩家控制,則會關閉本機控制的功能,由網路接收資料來控制角色。
再來就是game中角色在運作時的方式,本篇不講伺服器運作和玩家連線機制的部分。
假設遊戲中的所有玩家都長得一樣,那表示不管誰進入伺服器,遊戲中都會new一個一模一樣的物件。這個預先建構好的物件可能會帶有以下script:
其中:
1.PersonController:控制角色運作,與網路傳輸無關。
2.Animation:角色可能帶有動畫,這個腳本控制角色的動畫
3.NetworkTransformSync:透過Network View控制資訊的傳輸,EX:角色的位置,轉向等等。
4.NetworkAnimationSync:透過Network View控制角色同步動畫,因為透過Serialize機制並不能傳送動畫本身,只能傳送控制指令,例如一個字串。
5.ThirdPersonNetworkInit:這是最重要的,在遊戲開始後,控制哪個腳本可以運行,哪個腳本不能運行。
官方中ThirdPersonNetworkInit的內容如下:
function OnNetworkInstantiate (msg : NetworkMessageInfo) { // This is our own player if (networkView.isMine) { GetComponent(PersonController).enabled = true; GetComponent("NetworkTransformSync").enabled = false; GetComponent("NetworkAnimationSync").enabled = flase; } // This is just some remote controlled player else { name += "Remote"; GetComponent(PersonController).enabled = false; GetComponent("NetworkTransformSync").enabled = true; GetComponent("NetworkAnimationSync").enabled = true; } }OnNetworkInstantiate()是Network class提供的一個func.,當一個物件是透過Network.Instantiate()這函式new出來的時候,則物件可以呼叫這個func。而networkView.isMine會判斷目前這個物件是不是本機操作,若是,則會關閉角色所帶的同步位置 & 動畫的腳本,這邊要注意,關閉腳本,是表示腳本中的Update()不會運作,但是腳本中的其他函式一樣會運作,包括OnSerializeNetworkView(),如此一來角色就可由本機控制,並且透過同步的腳本傳送資料。
相反的,若是場景中的角色是遠端玩家控制,則會關閉本機控制的功能,由網路接收資料來控制角色。
阿貝高手,存起來慢慢看XD
回覆刪除