過去一週的網頁瀏覽次數

2011年12月10日 星期六

unity3D的網路資料傳輸 & 角色控制

本篇不說連線控制的部分,目前針對使用Network View屬性進行網路資料同步的架構 & 角色控制說明。


雖然說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有兩種型態可供參考isReadingisWriting,當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的內容如下:
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(),如此一來角色就可由本機控制,並且透過同步的腳本傳送資料。


相反的,若是場景中的角色是遠端玩家控制,則會關閉本機控制的功能,由網路接收資料來控制角色。

1 則留言: