Unity3d多人在線教程

[轉載]Unity3d多人在線教程

  (2013-02-25 16:02:49)
標籤: 

轉載

 
原文地址: Unity3d多人在線教程 做者: lsy0031

[轉載]Unity3d多人在線教程

Unity 多個玩家開發教程html

Unity多人在線教程[轉載]Unity3d多人在線教程服務器

歡迎Unity用戶,在這兒你將學習網絡的使用。網絡

但願大家過得愉快而且但願這個教程對大家有所幫助。

1。簡介
編輯器

這個教程的目的是展現Unity網絡功能,咱們將告訴你如何建立一個基本的以及用Master服務器/客戶端,UDP服務器/客戶端加強的網絡應用程序來進行網絡鏈接。在這個教程裏咱們將使用Unity iPhone 1.6, iPhone 3GS和來自於官網的Startrooper的案例。ide

2。開始函數

在開始前我先要了解一些知識點:oop

[轉載]Unity3d多人在線教程用於基本的和網絡強化的組件。學習

[轉載]Unity3d多人在線教程建立一個服務器和客戶端測試

[轉載]Unity3d多人在線教程使用Master Server網站

[轉載]Unity3d多人在線教程使用直接鏈接的方法

[轉載]Unity3d多人在線教程使用UDP廣播服務器

[轉載]Unity3d多人在線教程在網絡上建立一個簡單的場景

[轉載]Unity3d多人在線教程把StartTrooper遊戲變成多人在線遊戲

[轉載]Unity3d多人在線教程使用其它的Unity組件以及更多其它功能

你應該有:

[轉載]Unity3d多人在線教程Unity iPhone 1.6.

[轉載]Unity3d多人在線教程iPhone或者iPod

[轉載]Unity3d多人在線教程有關網絡和他們如何工做方面的知識。

[轉載]Unity3d多人在線教程高級的C#和JavaScript應用能力。

[轉載]Unity3d多人在線教程基本的Unity的使用技巧,你能夠從這兒找到更多的信息

注意事項:

[轉載]Unity3d多人在線教程Untiy支持.NET 1.1和2.1

你能夠經過:Edit->Project Settings->Player->Enable Unity Networking  來開啓或關閉網絡功能。

[轉載]Unity3d多人在線教程Unity網絡支持wifi,3G和GSM連接。

[轉載]Unity3d多人在線教程你能鏈接兩個不一樣的Unity平臺,例如,你能夠從Unity桌面連接到Unity iPhone,從Unity Web播放器連接到Unity iPhone,等等。

3。建立你的第一個用戶/服務器程序

在這個章節裏,咱們將建立包括一個簡單的多人在線的基礎應用程序,在網絡上建立第一個移動物體和基本的客戶端和服務器端的交互的例子。這個例子咱們使用了似有的多人在線組件。例如:Network和NetworkView.咱們將用直接鏈接的方法鏈接客戶端和服務器。

3。1。準備場景

如今讓咱們從一個簡單的場景開始,你的第一步:

[轉載]Unity3d多人在線教程建立一個新工程。

[轉載]Unity3d多人在線教程建立一個新的預製物體而後給它命名:Player

[轉載]Unity3d多人在線教程建立一個新的方塊物體

[轉載]Unity3d多人在線教程把你的Hierarchy面板的方塊物體拖到預製物體上,而後從場景中刪除這個方塊。

[轉載]Unity3d多人在線教程建立一個新的Plane而後給它命名:Ground。並設置:Position(0,0,0),Rotation(0,0,0),Scale(5,5,5).

[轉載]Unity3d多人在線教程建立一個平行燈光,並設置:Position(0,15,0),Rotation(25,0,0),Scale(1,1,1),Shadows->Type->Soft Shadows

最後,保存你的場景並命名:MainGame.

如今看起來應該像這樣子:[轉載]Unity3d多人在線教程
3。2。建立腳本並添加腳本

接下來你將學習如何建立服務器和客戶端,在網絡中實例化場景和物體,移動物體以及把全部的對象鏈接起來。

3。2。1。服務器和客戶端

咱們將開始最重要的部分——服務器和客戶端的建立。

[轉載]Unity3d多人在線教程建立一個新的JavaScript文件而後命名它爲ConnectionGUI

[轉載]Unity3d多人在線教程把這個腳本文件拖給層級面板裏的Main Camera(主攝像機),而後打開這個文件建立一些變量:

var remoteIP="127.0.0.1";

var remotePort=25000;

var listenPort=25000;

var useNAT=false;

var yourIP="";

var yourPort="";

 

[轉載]Unity3d多人在線教程如今咱們將用Unity GUI爲服務器建立一個接口而後鏈接它。


function OnGUI()

{

    //檢查你是否鏈接到服務器。

   if(Network.peerType==NetworkPeerType.Disconnected)

   {

      if(GUI.Button(new Rect(10,50,100,30),"Connect"))

      {

         Network.useNat=useNAT;

         //鏈接到服務器

         Network.Connect(remoteIP,remotePort);

       }

       if(GUI.Button(new Rect(10,50,100,30),"Start Server"))

       {

           Network.usenat=useNAT;

           //建立服務器

           Network.InitializeServer(32,listenPort);

           //通知咱們場景中的物體network已經準備好了。

           for(var go:GameObject in FindObjectsOfType(GameObject))

           {

              go.SendMessage("OnNetworkLoadedLevel",SendMessageOptions.DontRequireReceiver);

           }

       }

        //添加IP地址和端口號

      remoteIP=GUI.TextField(new Rect(120,10,100,20),remoteIP);

      remotePort=parseInt(GUI.TextField(new Rect(230,10,40,20),remotePort.ToString()));

      }

       else

      {

         //獲得你的IP地址和端口

         ipaddress=Network.player.ipAddress;

         port=Network.player.port.ToString();

         GUI.Label(new Rect(140,20,250,40),"IP Address:"+ipaddress+":"+port);

         if(GUI.Button(new Rect(10,10,100,50),"Disconnect"))

         {

              //從服務器上斷開鏈接

              Network.Disconnect(200);

         }

    }

}

注意下面的函數,這個函數當有人鏈接成功後時被調用。同時通知場景中全部對象網絡已經準備好了。

function OnConnectedToServer()

{

     //通知場景中的物體網絡已經準備好了

     for(var go:GameObject in FindObjectsOfType(GameObject)) 

     {

         go.SendMessage("OnNetworkLoadedLevel",SendMessageOptions.DontRequireReceiver);    

     }

}

Play模式你的屏幕應該是這樣的:[轉載]Unity3d多人在線教程

[轉載]Unity3d多人在線教程

如今能夠測試你的服務器和用戶端了。設置:Player Settings(Edit->Project Settings->Player)去設置你的iPhone Bundle Identifier而且切換默認的Screen Orientation爲Landscape Right。編譯你的工程到iPhone而且在編輯器中建立一個服務器。嘗試用在服務器屏幕中找到的IP地址鏈接到服務器。若是一切正常的話。你將能看到「Disconnect」按鈕而後你的IP地址同時出如今兩屏幕上。注意兩個應用程序必須在相同的網絡上。

 

3。2。2。在網絡上實例化場景和物體。

如今咱們須要在Player(Cube)而後[寫代碼去實例化它:

[轉載]Unity3d多人在線教程選擇Player預製物體而後添加一個NetworkView:

[轉載]Unity3d多人在線教程改變組件的同步狀態Synchronization參數爲Reliable Delta Compressed.這是須要你給全部的用戶顯示同步。

[轉載]Unity3d多人在線教程添加一個Rigidbody給你Player預製。

如今在網絡上實例化你的Player和物體:

[轉載]Unity3d多人在線教程建立一個新的空的GameObjecj而後命名爲:Spawn.Object參數:Position(0,5,0),Rotation(0,0,0),Scale(1,1,1)。

[轉載]Unity3d多人在線教程建立一個新的JavaScript文件而後命名Instantiate

[轉載]Unity3d多人在線教程打開文件寫下如下代碼:

var SpaceCraft:Transform;

 

function OnNetworkLoadedLevel()

{

     //當網絡加載後實例化SpaceCraft。

     Network.Instantiate(SpaceCraft,transform.position,transform.rotation,0);

}

 

function OnPlayerDisconnected(player:NetworkPlayer)

{

     Network.RemoveRPCs(player,0);

     Network.DestroyPlayerObjects(player);

}

 

[轉載]Unity3d多人在線教程把這個腳本拖放到Spawn物體上。

[轉載]Unity3d多人在線教程選擇Spawn物體而後拖放到Player參數到"Player(Transform)"變量上。

 

如今測試遊戲,你將會看到服務器和每個鏈接到的用戶將會有他們的Player(Cube)。咱們來建立一個簡單的測試:

[轉載]Unity3d多人在線教程建立一個新的JavaScript文件並命名Control.

[轉載]Unity3d多人在線教程添加這段代碼

function OnGUI()

{

     if(GUI.Button(new Rect(20,100,50,50),"up"))

     {

           GameObject.Find("Player(Clone)").transform.position=new Vector3(0,5,0);

     }
}

 

[轉載]Unity3d多人在線教程把這個文件拖放到Spawn物體上

[轉載]Unity3d多人在線教程編譯這個工程,建立一個服務器而且鏈接它。如今你能夠看到每個客戶端有發球本身的Player(Cube)。

你的編輯屏幕應該看起來像這樣:

[轉載]Unity3d多人在線教程

小結

恭喜你!你已經學會了建立了一個多人程序所必要的基礎知識。

[轉載]Unity3d多人在線教程爲多人遊戲準備一個基本的場景

[轉載]Unity3d多人在線教程建立一個服務器。

[轉載]Unity3d多人在線教程建立一個客戶端。

[轉載]Unity3d多人在線教程使用直接鏈接。

[轉載]Unity3d多人在線教程使用基本的network組件。

[轉載]Unity3d多人在線教程在newwork上實例化一個場景和物體。

[轉載]Unity3d多人在線教程把這些都鏈接在一塊兒。

Download the whole NetworkExampla project:

http://asprofas.xz.lt/mp_documentation/images/NetworkExsample.zip

下一個章節,咱們將在包括及建立一個高級的網絡設置的思路上進行拓展。

4。利用Startrooper這個遊戲執行多人在線的建立。

在這個章節裏,你將學會如何把StarTrooper遊戲由單人變成多人遊戲。咱們將用複雜的組件和三種不一樣的鏈接方式:直接鏈接(在第四章),MasterServer鏈接和UDP廣播鏈接。在最後這個章節裏你將在多人模式下有能力去環繞飛行而且擊敗其它的用。

從Unity官方網站下載StarTrooper而且弄明白它:

http://asprofas.xz.lt/mp_documentation/images/mpStarTrooper.zip

4。1。改變場景

咱們將要把這個單人遊戲修改一下,後面會進一步深刻修改。

[轉載]Unity3d多人在線教程打開下載好的StarTrooper工程文件。

[轉載]Unity3d多人在線教程選擇StarTrooper場景

[轉載]Unity3d多人在線教程在Hierarchy面板裏選擇SpaceCraftFBX文件。

[轉載]Unity3d多人在線教程添加一個NetworkView組件。

[轉載]Unity3d多人在線教程從Player上移除控制腳本。

[轉載]Unity3d多人在線教程從對象移除Missile Launcher腳本。

[轉載]Unity3d多人在線教程給對象上添加一個尾跡渲染器。

[轉載]Unity3d多人在線教程設置尾跡渲染器Materials->Element 0->missleTracer

[轉載]Unity3d多人在線教程建立一個新的空物體並命名Spawn.設置Transform參數:Position(0,30,11),Rotation(0,0,0),Scale(1,1,1).

4。2。整合

如今咱們將要改變而且整合網絡到這個工程的。讓咱們爲網絡準備這個場景。完成後咱們將建立一個服務器和客戶端。

4。2。1。整合物體和場景

如今咱們須要建立一個腳本爲的是在網絡中轉換咱們的剛體:

[轉載]Unity3d多人在線教程首先,這咱們的新腳本建立兩個文件夾分別是:「NetworkFiles」和「Plugins」這個是存入C#文件的。

[轉載]Unity3d多人在線教程建立一個C#文件並命名它爲NetworkRigidbody.

把NetworkRigidbody.cs文件拖放到Plugins文件夾。

[轉載]Unity3d多人在線教程別管這個文件是怎麼回事,只要明白要須要它的地方就能用得上就能夠了。

[轉載]Unity3d多人在線教程你能夠把這個腳本用在任何你想要的工程中,由於它適合全部的剛體對象。

[轉載]Unity3d多人在線教程打開你的NetworkRigidbody.cs文件並輸入如下代碼:


using UnityEngine;

using System.Collections; 

public class NetworkRigidbody : MonoBehaviour

{

   public double m_InterpolationBackTime = 0.1;

   public double m_ExtrapolationLimit = 0.5; 

   internal struct  State

   {

      internal double timestamp;

      internal Vector3 pos;

      internal Vector3 velocity;

      internal Quaternion rot;

      internal Vector3 angularVelocity;

    } 

     //咱們儲存20個狀態用「playback」信息 

    State[] m_BufferedState = new State[20]; //與用到的slots(插槽)保持聯繫。

    int m_TimestampCount; 

 

    void OnSerializeNetworkView(BitStream stream, NetworkMessageInfo info)

    {

        // 發送數據給服務器 

        if (stream.isWriting)

        {

             Vector3 pos = rigidbody.position;

             Quaternion rot = rigidbody.rotation;

             Vector3 velocity = rigidbody.velocity;

             Vector3 angularVelocity = rigidbody.angularVelocity;

 

             stream.Serialize(ref pos);

             stream.Serialize(ref velocity);

             stream.Serialize(ref rot);

             stream.Serialize(ref angularVelocity);

         }

         // 從遠程客戶端讀取數據。

         else

         {

             Vector3 pos = Vector3.zero; 

             Vector3 velocity = Vector3.zero; 

             Quaternion rot = Quaternion.identity;

             Vector3 angularVelocity = Vector3.zero;

             stream.Serialize(ref pos);

             stream.Serialize(ref velocity);

             stream.Serialize(ref rot);

             stream.Serialize(ref angularVelocity);

             //切換buffer另外一邊,刪除狀態20

             for (int i=m_Buffered State.Length-1;i>=1;i--)

             {

                  m_BufferedState[i] = m_BufferedState[i-1];

              } 

              //  在slot 0記錄當前狀態              

              State state;

              state.timestamp = info.timestamp;

              state.pos = pos;

              state.velocity = velocity;

              state.rot = rot;

              state.angularVelocity = angularVelocity;

              m_BufferedState[0] = state;

              

              //更新用slot計數,而後永遠不超出buffer的大小。

              // Slot不是真正的釋放,這僅僅是確認buffer是填滿了而且未初始化的slot是否

              //沒有用

               m_TimestampCount = Mathf.Min(m_TimestampCount + 1, m_BufferedState.Length);  

               // 檢查狀態是否正常,若是這個是不協調的你能夠從新調整或

               //者丟掉非正常的狀態。這裏沒有作什麼。

               for (int i=0;i<m_TimestampCount-1;i++)

               {

                    if (m_BufferedState[i].timestamp < m_BufferedState[i+1].timestamp)

                         Debug.Log("State inconsistent");

                }

            }

         }

        // 咱們有一個interpolationBackTime的窗口在咱們本質上播放

        // 經過有interpolationBackTime普通的ping,你將一般用來填寫。

        // 而且僅僅沒有更過的數據到達咱們將用的額外polation(位置?)。

        void Update ()

        {

             //這個是剛體的目標playback time。

             double interpolationTime = Network.time - m_InterpolationBackTime;  

              // 使用interpolation若是目標playback time是呈如今buffer裏面

             if (m_BufferedState[0].timestamp > interpolationTime)

             {

                  //檢查buffer而且查找正確的狀態去play back。

                  for (int i=0;i<m_TimestampCount;i++)

                 {

                     if (m_BufferedState[i].timestamp <= interpolationTime || i == m_TimestampCount-1)

                     {

                            //一個slot的狀態比最好的playback狀態更新(<100ms)

                            State rhs = m_BufferedState[Mathf.Max(i-1, 0)];

                            // The best playback state (closest to 100 ms old (default time))

                            // 最好的playback狀態(最接近100ms時長(默認時間))

                            State lhs = m_BufferedState[i];                             

                            // 用兩個slots的時間去測定插值是不是必要的。

                            double length = rhs.timestamp - lhs.timestamp;

                         float t = 0.0F;

                            // 時間差越接近於100毫秒t越接近於1,在這種狀況下只用rhs。

                             //例如:

                            // Time是10.000,因此sampleTime是9.900

                            // lhs.time是9.910 rhs.time是9.980length是0.070

                            // t是9.900 - 9.910 / 0.070 = 0.14。因此它用了rhs的14%,lhs的86% 

                            if (length > 0.0001)

                           t = (float)((interpolationTime - lhs.timestamp) / length); 

                              // 若是 t=0 =>直接使用lhs

                        transform.localPosition = Vector3.Lerp(lhs.pos, rhs.pos, t);

                     transform.localRotation = Quaternion.Slerp(lhs.rot, rhs.rot, t);

                     return;

                     }

                  }

              }

               //使用插值

               else

               {

                 State latest = m_BufferedState[0];    

                 float extrapolationLength = (float)(interpolationTime - latest.timestamp);

                   // 不爲多於500毫秒的插值,你須要仔細的作。

                    if (extrapolationLength < m_ExtrapolationLimit)

                 {

                       float axisLength = extrapolationLength * latest.angularVelocity.magnitude * Mathf.Rad2Deg; Quaternion angularRotation = Quaternion.AngleAxis(axisLength, latest.angularVelocity); 

                       rigidbody.position = latest.pos + latest.velocity * extrapolationLength;         

                       rigidbody.rotation = angularRotation * latest.rot; rigidbody.velocity = latest.velocity;

                       rigidbody.angularVelocity = latest.angularVelocity;

                  }

             }

        }

  } 

[轉載]Unity3d多人在線教程在Hierarchy選擇你的SpaceCraftFBX物體(記住不在Project面板裏的那個遊戲對象)

[轉載]Unity3d多人在線教程添加NetworkRigidboddy.CS腳本到你的選擇的物體上。

[轉載]Unity3d多人在線教程關閉NetworkRigidbody組件(僅僅是在組件上打上個標記)。咱們將在之後用一些條件下激活它。

[轉載]Unity3d多人在線教程在Network View組件中:改變Observed把SpaceCraftFBX(Transform)換成SpaceCraftFBX(NetworkRigidbody)參數.

[轉載]Unity3d多人在線教程建立一個新的JavaScript文件並命名爲RigidAssign

[轉載]Unity3d多人在線教程把RigidAssign.js腳本添加到你的物體上而後編輯這個文件:

function OnNetworkInstantiate (msg : NetworkMessageInfo) 

{

    if (networkView.isMine)

    {

        var _NetworkRigidbody : NetworkRigidbody = GetComponent("NetworkRigidbody");        

        _NetworkRigidbody.enabled = false;

    }

    else

    {

         name += "Remote";

        var _NetworkRigidbody2 :NetworkRigidbody = GetComponent("NetworkRigidbody");

        _NetworkRigidbody2.enabled = true;

     }

}

 

建立一個新的預製物體,給它命名:SpaceCraft。而後把它放到預製文件夾裏。

[轉載]Unity3d多人在線教程把你的SpaceCraftFBX從Hierarchy面板拖到Project面板裏新的預製物體(SpaceCraft)。

[轉載]Unity3d多人在線教程從場景中刪除SpaceCraftFBX文件。

[轉載]Unity3d多人在線教程爲你的SpaceCraft預製物體建立「SpaceCraft」標籤(tag)

[轉載]Unity3d多人在線教程再選中你的SpaceCraft預置物體把標籤指定給它:點擊"Untagged"而且選擇"SpaceCraft"

如今看像下面這個樣子[轉載]Unity3d多人在線教程

如今爲Network準備了SpaceCraft!

[轉載]Unity3d多人在線教程建立一個新的JS文件而且命名Instantialte.js

[轉載]Unity3d多人在線教程把這個腳本文件拖給Hierarchy面板裏的Spawn物體,而後編寫如下代碼:

var SpaceCraft : Transform;  

function OnNetworkLoadedLevel ()

{

  // Instantiating SpaceCraft when Network is loaded

  // 實例化SpaceCraft當網絡加載完成的時候

  Network.Instantiate(SpaceCraft, transform.position, transform.rotation, 0);

}

function OnPlayerDisconnected (player : NetworkPlayer)

{

   // Removing player if Network is disconnected

   // 移除player,當網絡斷開鏈接。

   Debug.Log("Server destroying player");

   Network.RemoveRPCs(player, 0);

   Network.DestroyPlayerObjects(player);

[轉載]Unity3d多人在線教程選擇Spawn物體在Hierarchy而且設置Space Craft參數給SpaceCraft(Transform)(從列表選擇你的SpaceCraft預設)

[轉載]Unity3d多人在線教程從Hierachy面板裏選擇Main Camera物體。

[轉載]Unity3d多人在線教程打開Smooth Follow腳本而且稍做修改:

var target : Transform;

var distance : float = 10.0;

var height : float = 5.0;

var heightDamping : float = 2.0;

var rotationDamping : float = 3.0;  

function LateUpdate ()

{

    if(GameObject.FindWithTag("SpaceCraft"))

    {

         if (!target)

             target = GameObject.FindWithTag("SpaceCraft").transform;  

              // 計算當前的選擇角度

             var wantedRotationAngle : float = target.eulerAngles.y;

             var wantedHeight : float = target.position.y + height;

             var currentRotationAngle : float = transform.eulerAngles.y;

             var currentHeight : float = transform.position.y;

             // 減幅y軸方向的旋轉。 

             var dt : float = Time.deltaTime;

             currentRotationAngle = Mathf.LerpAngle (currentRotationAngle, wantedRotationAngle, rotationDamping * dt);

             //減幅高度

             currentHeight = Mathf.Lerp (currentHeight, wantedHeight, heightDamping * dt);

             //轉換角度變成旋轉 

             var currentRotation : Quaternion = Quaternion.Euler (0, currentRotationAngle, 0);

             // 設置cmera的位置在x-z平面成:

             // 與後面的target的距離多少米

             transform.position = target.position;

             var pos : Vector3 = target.position - currentRotation * Vector3.forward * distance;

             pos.y = currentHeight;

             // 設置攝像機的高度

             transform.position = pos;

             // 老是朝向目標

             transform.LookAt (target);

      }

}

 

[轉載]Unity3d多人在線教程把Player Controls腳本拖到Main Camera上,而後編輯。

[轉載]Unity3d多人在線教程把代碼修改爲這樣的:

var turnSpeed : float = 3.0;

var maxTurnLean : float = 70.0;

var maxTilt : float = 50.0;  

var sensitivity : float = 0.5;  

var forwardForce : float = 5.0;

var guiSpeedElement : Transform;

var craft : GameObject;  

 

private var normalizedSpeed : float = 0.2;

private var euler : Vector3 = Vector3.zero;  

var horizontalOrientation : boolean = true;  

function Awake ()

{

    if (horizontalOrientation)

    {

       iPhoneSettings.screenOrientation = iPhoneScreenOrientation.LandscapeLeft;

    }

    else

    {

       iPhoneSettings.screenOrientation = iPhoneScreenOrientation.Portrait;

     } 

     guiSpeedElement = GameObject.Find("speed").transform;

     guiSpeedElement.position = new Vector3 (0, normalizedSpeed, 0);

  } 

function FixedUpdate ()

{

    if(GameObject.FindWithTag("SpaceCraft"))

    {

       GameObject.FindWithTag("SpaceCraft").rigidbody.AddRelativeForce(0, 0, normalizedSpeed * (forwardForce*3)); 

       var accelerator : Vector3 = iPhoneInput.acceleration;

       if (horizontalOrientation)

       {

           var t : float = accelerator.x;

           accelerator.x = -accelerator.y;

           accelerator.y = t;

       } 

       // 基於重力感應旋轉

       euler.y += accelerator.x * turnSpeed;

        // Since we set absolute lean position, do some extra smoothing on it

       euler.z = Mathf.Lerp(euler.z, -accelerator.x * maxTurnLean, 0.2); 

        //因爲咱們的設置絕對依賴position,因此作了一些額外的平滑。

       euler.x = Mathf.Lerp(euler.x, accelerator.y * maxTilt, 0.2);

       // 應用旋轉而且應用一些平滑

       var rot : Quaternion = Quaternion.Euler(euler);

       GameObject.FindWithTag("SpaceCraft").transform.rotation = Quaternion.Lerp (transform.rotation, rot, sensitivity);

     }

}

function Update ()

{

    for (var evt : iPhoneTouch in iPhoneInput.touches)

    {

        if (evt.phase == iPhoneTouchPhase.Moved)

        {

            normalizedSpeed = evt.position.y / Screen.height;

            guiSpeedElement.position = new Vector3 (0, normalizedSpeed, 0);

         }

      }

 }

[轉載]Unity3d多人在線教程添加腳本Missile launcher腳本給Main Camera。設置Missile(導彈)參數爲MissilePrefab。

[轉載]Unity3d多人在線教程打開Missile Launcher而後編輯。

[轉載]Unity3d多人在線教程咱們添加一個計時器給shooting(射擊)同時也做一些小小的調整。

var missile : GameObject;

var timer : int = 0; 

function FixedUpdate()

{

   timer++;

function Update ()

{

    if ((Input.GetMouseButtonDown (0))&&(timer>10))

    {

        // 若是SpaceCraft 存在的話

        if(GameObject.FindWithTag("SpaceCraft"))

        {

           var position : Vector3 = new Vector3(0, -0.2, 1) * 10.0;

           position = GameObject.FindWithTag("SpaceCraft").transform.TransformPoint(position);

           //實例化

           var thisMissile : GameObject = Network.Instantiate (missile, position, GameObject.FindWithTag("SpaceCraft").transform.rotation,0) as GameObject;

           Physics.IgnoreCollision(thisMissile.collider, GameObject.FindWithTag("SpaceCraft").collider); 

           timer = 0;

            }

       }

}

[轉載]Unity3d多人在線教程建立新的標籤「Missile」而後分配給missilePrefab預製物體。

[轉載]Unity3d多人在線教程選擇missilePrefab物體而且打開MissileTrajector腳原本編輯。

[轉載]Unity3d多人在線教程咱們將使它有能力擊敗其它的SpaceCraft

var explosion : GameObject;  

function OnCollisionEnter(collision : Collision)

{

    if(GameObject.FindWithTag("SpaceCraft"))

    {

        if(((collision.gameObject.tag == "Untagged")||(collision.gameObject.tag == "SpaceCraft"))&&(collision.gameObject.tag != "Missile"))

        {

             var contact : ContactPoint = collision.contacts[0];

             Instantiate (explosion, contact.point + (contact.normal * 5.0) , Quaternion.identity); 

              if (collision.gameObject.tag == "SpaceCraft")

              {

                 Instantiate (explosion, contact.point + (contact.normal * 5.0) , camera.main.transform.rotation);

                 collision.gameObject.transform.position = GameObject.Find("Spawn").transform.position;

               }

               Destroy (gameObject);

            }

      }

function FixedUpdate ()

{

     if(GameObject.FindWithTag("Missile"))

     {

         rigidbody.AddForce (transform.TransformDirection (Vector3.forward + Vector3(0,0.1,0)) * 720.0);

      }

 

你已經爲網絡準備好場景和物體了。

4。2。2。服務器/客戶端。

如今是時候給這個遊戲建立服務器了。咱們將要建立三個不一樣的類型的servers(服務器)。

[轉載]Unity3d多人在線教程建立一個新場景並保存爲服務器。這個場景被用做服務器。

[轉載]Unity3d多人在線教程建立一個新場景並保存爲UDPServer。這個場景爲用做UDP廣播鏈接。

[轉載]Unity3d多人在線教程建立一個新場景保存爲MasterServer。這個場景被用做MasterServer。

[轉載]Unity3d多人在線教程再建立一個新場景,保存爲一個空場景。這個場景用做遊戲斷開時或啓動一個新遊戲以前清除掉全部的東西。

[轉載]Unity3d多人在線教程把全部新建的場景到File->Building Settings->Add Open Scene. 你的ServerChoose應該在列表裏是第一個例子。如:

提示:你能夠建立一個文件夾把這些都放到一塊兒。

 

[轉載]Unity3d多人在線教程

 

[轉載]Unity3d多人在線教程打開ServerChoose場景

[轉載]Unity3d多人在線教程建立一個新的JS文件並命名它爲Menu。咱們將用這個場景及這個腳原本選擇不一樣類型的服務器。

[轉載]Unity3d多人在線教程把這個腳本添加給主攝像機(Main Camera)。

function OnGUI()

{

    GUI.Label(new Rect((Screen.width/2)-80,(Screen.height/2)-130,200,50),"SELECT CONNECTION TYPE");

    GUI.Label(new Rect((Screen.width-220),(Screen.height-30),220,30),"STAR-TROOPER MULTIPLAYER DEMO"); 

    if(GUI.Button(new Rect((Screen.width/2)-100,(Screen.height/ 2)-100,200,50),"Master Server Connection"))

    {

          Application.LoadLevel("MasterServer");

     } 

     if(GUI.Button(new Rect((Screen.width/2)-100,(Screen.height/2)-40,200,50),"Direct Connection"))

     {

          Application.LoadLevel("StarTrooper");

     } 

     if(GUI.Button(new Rect((Screen.width/2)-100,(Screen.height/2)+20,200,50),"UDP Connection"))

     {

          Application.LoadLevel("UDPServer");

     }

 }

[轉載]Unity3d多人在線教程打開MasterServer場景

[轉載]Unity3d多人在線教程建立一個新的JS文件並命名它NetworkLevelLoad。咱們將用這個腳本把StarTrooper場景和物體加載網絡中來。

[轉載]Unity3d多人在線教程建立一個新的Empty GameObject並命名它ConnectionGUI。

[轉載]Unity3d多人在線教程把NetworkLevelLoad腳本添加到ConnectionGUI遊戲物體上

 

private var lastLevelPrefix = 0;

function Awake ()

{

    // 網絡場景加載完成在一個分離的通道 

    DontDestroyOnLoad(this);

    networkView.group = 1;

    Application.LoadLevel("EmptyScene");

function OnGUI ()

{

    //當network運行(服務器和客戶端)而後顯示場景「StarTrooper」

    if (Network.peerType != NetworkPeerType.Disconnected)

    {

         if (GUI.Button(new Rect(350,10,100,30),"StarTrooper"))

         {

             //確信沒有舊的RPC調用是在緩衝的而後發送加載的場景命令

             Network.RemoveRPCsInGroup(0);

             Network.RemoveRPCsInGroup(1);

             //加載場景用增長後的level prefix(爲查看ID)

             networkView.RPC( "LoadLevel", RPCMode.AllBuffered, "StarTrooper", lastLevelPrefix + 1);

         }

     }

@RPC

function LoadLevel (level : String, levelPrefix : int)

{

      Debug.Log("Loading level " + level + " with prefix " + levelPrefix); lastLevelPrefix = levelPrefix;

      // 咱們在網絡上沒有理由在默認的通道去發送更多的數據,由於咱們將要加載場景,全部的這個物體將被刪除。

      Network.SetSendingEnabled(0, false);  

      //咱們須要中止接受由於首先場景必須被加載。

      //一旦場景加載完畢,RPC和其餘狀態的更新依附到場景中物體被容許去發射。

      Network.isMessageQueueRunning = false;  

      // 全部的newtork views從一個場景加載將獲得一個prefix在他們NetworkViewID中。

      //這個將預防舊的來自於客戶端的更新泄露進一個新建立的場景

      Network.SetLevelPrefix(levelPrefix);

      Application.LoadLevel(level); yield; yield;

      // Allow receiving data again容許再一次加載數據

      Network.isMessageQueueRunning = true;

      //如今場景已經加載完畢而後咱們能夠開始發送咱們的數據。

      Network.SetSendingEnabled(0, true);  

      //通知咱們的物體場景和網絡已經準備好了。

      var go : Transform[] = FindObjectsOfType(Transform);

      var go_len = go.length;  

      for (var i=0;i<go_len;i++)

      {

          go[i].SendMessage("OnNetworkLoadedLevel",SendMessageOptions.DontRequireReceiver);

       }

function OnDisconnectedFromServer ()

{

      Application.LoadLevel("EmptyScene");

}  

@script RequireComponent(NetworkView)

// Ensure that this script has added a Netw

 

確信這個腳本已經自動添加了NetworkView,另外從Component菜單添加這個腳本workLevelLoad.

  建立一個新的JavaScript文件而且命名MasterServerGUI。用這個腳本咱們將建立一個Master Server/Client,一些GUI將用到它。

把這個文件添加給ConnectionGUI物體而且打開這個腳本去編輯:

DontDestroyOnLoad(this);

  

var gameName = "YourGameName";

var serverPort = 25002;

private var timeoutHostList = 0.0;

private var lastHostListRequest = -1000.0;

private var hostListRefreshTimeout = 10.0;

private var natCapable : ConnectionTesterStatus = ConnectionTesterStatus.Undetermined;

private var filterNATHosts = false;

private var probingPublicIP = false;

private var doneTesting = false;

private var timer : float = 0.0; 

 

private var windowRect = Rect (Screen.width-300,0,300,100);

private var hideTest = false;

private var testMessage = "Undetermined NAT capabilities";  

 

// 若是沒有運行客戶端啓用這個在服務器的機器上。

//MasterServer.dedicatedServer = true; 

 

function OnFailedToConnectToMasterServer(info: NetworkConnectionError)

{

     Debug.Log(info);

function OnFailedToConnect(info: NetworkConnectionError)

{

     Debug.Log(info);

function OnGUI ()

{

     ShowGUI();

}  

function Awake ()

{

     // 開始鏈接測試

     natCapable = Network.TestConnection(); 

     //  這個機器有什麼種類的IP?TestConnection也在測試結果中顯示。

     if (Network.HavePublicAddress())

         Debug.Log("This machine has a public IP address");

     else

         Debug.Log("This machine has a private IP address");

   } 

function Update()

{

       // 若是測試不肯定,保持運行

       if (!doneTesting)

        {

              TestConnection();

        }

function TestConnection()

{

     // 開始/輪詢鏈接測試,在一個標籤裏面報告結果而且對結果作出相應的反應。

      natCapable = Network.TestConnection();

      switch (natCapable)

      {

          case

             ConnectionTesterStatus.Error:

             testMessage = "Problem determining NAT capabilities";

             doneTesting = true;

             break;  

          case

             ConnectionTesterStatus.Undetermined:

             testMessage = "Undetermined NAT capabilities";

             doneTesting = false;

             break;  

          case

             ConnectionTesterStatus.PrivateIPNoNATPunchthrough:

             testMessage = "Cannot do NAT punchthrough, filtering NAT enabled hosts for client connections," +" local LAN games only.";

             filterNATHosts = true; Network.useNat = true;

             doneTesting = true;

             break; 

         case

             ConnectionTesterStatus.PrivateIPHasNATPunchThrough:

         if (probingPublicIP)

             testMessage = "Non-connectable public IP address (port "+ serverPort +" blocked),"+" NAT punchthrough can circumvent the firewall.";

         else

             testMessage = "NAT punchthrough capable. Enabling NAT punchthrough functionality.";

              // NAT功能在服務器開始的時候是可用的,若是主機須要它在此基礎上客戶應該啓用它,               Network.useNat = true; doneTesting = true;

               break; 

          case

               ConnectionTesterStatus.PublicIPIsConnectable:

               testMessage = "Directly connectable public IP address.";

               Network.useNat = false; doneTesting = true; break;  

               //這種狀況是比較特殊,由於咱們如今須要檢查是否能夠經過使用NAT穿通         case

               ConnectionTesterStatus.PublicIPPortBlocked:

               testMessage = "Non-connectble public IP address (port " + serverPort +" blocked),"+" running a server is impossible."; 

               Network.useNat = false;

               // 若是沒有NAT穿透,測試將被搭建在這個公共的IP,強制一個測試

           if (!probingPublicIP)

           {

                Debug.Log("Testing if firewall can be circumnvented");

                natCapable = Network.TestConnectionNAT();

                probingPublicIP = true; timer = Time.time + 10;

           }

           //NAT穿透測試被執行可是咱們仍然是阻塞的。 

          else if (Time.time > timer)

          {

                probingPublicIP = false;

                // reset

                Network.useNat = true;

                doneTesting = true;

           }

          break;

       case

             ConnectionTesterStatus.PublicIPNoServerStarted:

             testMessage = "Public IP address but server not initialized," +"it must be started to check server accessibility. Restart connection test when ready.";

             break;

        default: testMessage = "Error in test routine, got " + natCapable;

       }

 } 

function ShowGUI()

{

   if (GUI.Button (new Rect(100,10,120,30),"Retest connection"))

   {

         Debug.Log("Redoing connection test");

         probingPublicIP = false; doneTesting = false;

         natCapable = Network.TestConnection(true);

    } 

    if (Network.peerType == NetworkPeerType.Disconnected)

    {

         // 開始一個新的服務器

         if (GUI.Button(new Rect(10,10,90,30),"Start Server"))

         {

               Network.InitializeServer(32, serverPort); MasterServer.updateRate = 3;

               MasterServer.RegisterHost(gameName, "stuff", "profas chat test");

          } 

          // 刷新主機

          if (GUI.Button(new Rect(10,40,210,30),"Refresh available Servers") || Time.realtimeSinceStartup > lastHostListRequest + hostListRefreshTimeout)

          {

               MasterServer.ClearHostList(); MasterServer.RequestHostList (gameName);

               lastHostListRequest = Time.realtimeSinceStartup; Debug.Log("Refresh Click");

          } 

          var data : HostData[] = MasterServer.PollHostList();  

          var _cnt : int = 0;

          for (var element in data)

          {

               // Do not display NAT enabled games if we cannot do NAT punchthrough 

               //不顯示NAT功能的遊戲,若是咱們不能這樣作NAT穿透

               if ( !(filterNATHosts && element.useNat) )

               {

                    var name = element.gameName + " " + element.connectedPlayers + " / " + element.playerLimit;

                    var hostInfo; hostInfo = "[";

                    // Here we display all IP addresses, there can be multiple in cases where

                    // internal LAN connections are being attempted. In the GUI we could just display    connect to the  

                    // the first one in order not confuse the end user, but internally Unity will

                    // do a connection check on all IP addresses in the element.ip list, and  

                    // first valid one.

                    //在這個這裏咱們顯示全部IP地址,能夠有不一樣狀況內部局域網鏈接被嘗試。在GUI裏,咱們能夠僅僅顯示第一個爲了避免混淆終端用戶,可是內部Unity將作一個鏈接檢查在全部的IP地址上在element.ip列表裏,而且鏈接到第一個有效的ip。

                    for (var host in element.ip)

                    {

                         hostInfo = hostInfo + host + ":" + element.port + " ";

                     } hostInfo = hostInfo + "]";  

                    if (GUI.Button(new Rect(20,(_cnt*50)+90,400,40),hostInfo.ToString()))

                    {

                         // Enable NAT functionality based on what the hosts if configured to do

                         //主機是否配置決定是否啓用NAT功能。

                         Network.useNat = element.useNat;  

                         if (Network.useNat)

                              print("Using Nat punchthrough to connect");

                         else

                              print("Connecting directly to host"); 

                              Network.Connect(element.ip, element.port);

 

                     }

                }

            }

      }

      else

      {

            if (GUI.Button (new Rect(10,10,90,30),"Disconnect"))

            {

                   Network.Disconnect();

                   MasterServer.UnregisterHost();

             }

        }

  } 

 

如今你能夠用Master Server來測試你的工程了

[轉載]Unity3d多人在線教程去Edit -> Project Settings -> Player而後設置你的iPhone Bundle Identifier而且改變Default Screen Orientation 成 Landscape Left.

[轉載]Unity3d多人在線教程編譯你的工程到iPhone。

[轉載]Unity3d多人在線教程運行Server場景在編輯器。

[轉載]Unity3d多人在線教程點擊在編輯器裏面Master Server Connection和iPhone上。

[轉載]Unity3d多人在線教程點擊Start Server在編輯器。

[轉載]Unity3d多人在線教程服務器應該應用在iPhone上(若是沒有,點擊刷新可用服務器)。

[轉載]Unity3d多人在線教程鏈接到服務器從iPhone。

[轉載]Unity3d多人在線教程點擊StarTrooper 按鈕在編輯器或者在iPhone上。

[轉載]Unity3d多人在線教程你的圖片應該看起來像這張圖片:

[轉載]Unity3d多人在線教程

咱們已經完成了咱們的Master Server

如今咱們須要去建立一個第二種鏈接方式 – UDP廣播鏈接:

[轉載]Unity3d多人在線教程打開UDPServer

[轉載]Unity3d多人在線教程建立一個新的C#文件而且命名他UDPConnectionGUI.

[轉載]Unity3d多人在線教程把UDPConnection文件移到Plugins文件夾。

[轉載]Unity3d多人在線教程建立一個新的空物體而且命名它UDPServer.

[轉載]Unity3d多人在線教程指定UDPConnectionGUI文件到UDPServer 物體。(或者在你寫了接下來的代碼之後分配他)。

[轉載]Unity3d多人在線教程分配一個NetworkView組件到UDPServer物體而且改變Observed參數給UDPServer(Transform)。

[轉載]Unity3d多人在線教程分配NetworkLevelLoad腳本文件給UDPServer物體。

[轉載]Unity3d多人在線教程打開UDPCOnnectionGUI而後寫如下代碼:

using UnityEngine;

using System.Collections;

using System.Net;

using System.Net.Sockets;

using System.Threading;

 

public class UDPConnectionGUI : MonoBehaviour

{

     private UdpClient server;

     private UdpClient client;

     private IPEndPoint receivePoint;

     private string port = "6767";

     private int listenPort = 25001;

     private string ip = "0.0.0.0";

     private string ip_broadcast = "255.255.255.255";

     private bool youServer = false;

     private bool connected = false;

     private string server_name = "";

     private int clear_list = 0;

     public void Update()

     {

          if(clear_list++>200)

          {

               server_name = "";

               clear_list = 0;

           }

     } 

     public void Start()

     {

           Debug.Log("Start"); LoadClient();

      }  

      public void LoadClient()

      {

           client = new UdpClient(System.Convert.ToInt32(port));

           receivePoint = new IPEndPoint(IPAddress.Parse(ip),System.Convert.ToInt32(port));

           Thread startClient = new Thread(new ThreadStart(start_client));

           startClient.Start();

       }  

       public void start_client()

       {

           bool continueLoop =true; 

           try 

           {

               while(continueLoop)

               {

                    byte[] recData = client.Receive(ref receivePoint);

                    System.Text.ASCIIEncoding encode = new System.Text.ASCIIEncoding();

                    server_name = encode.GetString(recData); if(connected) { server_name = "";

                    client.Close();

                    break;

                }

           }

       }

       catch {}

    } 

    public void start_server()

    {

        try

        {

             while(true)

            {

                 System.Text.ASCIIEncoding encode = new System.Text.ASCIIEncoding();  

                 byte[] sendData = encode.GetBytes(Network.player.ipAddress.ToString());

                 server.Send(sendData,sendData.Length,ip_broadcast,System.Convert.ToInt32(port));

                 Thread.Sleep(100);

             }

          }

          catch {}

      }  

      void OnGUI()

      {

          if(!youServer)

          {

              if(GUI.Button(new Rect(10,10,100,30),"Start Server"))

              {

                   youServer = true;

                   Network.InitializeServer(32, listenPort);

                   string ipaddress = Network.player.ipAddress.ToString();

                   ip = ipaddress;  

                   client.Close();

                   server = new UdpClient(System.Convert.ToInt32(port));

                   receivePoint = new IPEndPoint(IPAddress.Parse(ipaddress),System.Convert.ToInt32(port));

                   Thread startServer = new Thread(new ThreadStart(start_server));

                   startServer.Start();

             }  

             if(server_name!="")

             {

                 if(GUI.Button(new Rect(20,100,200,50),server_name))

                 {

                      connected = true; Network.Connect(server_name, listenPort);

                 }

             }

        }

        else

        {

              if(GUI.Button(new Rect(10,10,100,30),"Disconnect"))

              {

                  Network.Disconnect();

                  youServer = false; server.Close();

                  LoadClient();

               }

          }

     }

}

如今你能夠測試這個鏈接類型:

[轉載]Unity3d多人在線教程按上面的要求設置你的Player Settings(若是你剛剛沒有改變它們的話)。

[轉載]Unity3d多人在線教程把工程編譯到iPhone。

[轉載]Unity3d多人在線教程在編輯器播放UDPServer場景。

[轉載]Unity3d多人在線教程從編輯器裏面點擊Start Server開啓服務器。

[轉載]Unity3d多人在線教程當IP address 按鈕顯示的時候從iPhone鏈接到服務器。

[轉載]Unity3d多人在線教程你的場景應該看起來像這樣:

[轉載]Unity3d多人在線教程

咱們已經完成咱們的UDP廣播服務器

 如今咱們須要去建立一個第三種鏈接方式 – 直接鏈接:

[轉載]Unity3d多人在線教程打開StarTrooper場景

[轉載]Unity3d多人在線教程建立一個新的JavaScript文件而且命名它ConnectionGUI.

[轉載]Unity3d多人在線教程指定ConnectionGUI.js文件給Main Camera而且添寫如下代碼:

var remoteIP = "127.0.0.1";

var remotePort = 25000;

var listenPort = 25000; 

var useNAT = false; 、

var yourIP = "";

var yourPort = "";

function Awake()

{

    if (FindObjectOfType(MasterServerGUI))

        this.enabled = false; 

    if(FindObjectOfType(UDPConnectionGUI))

        this.enabled = false;

}

function OnGUI ()

{

    if (Network.peerType == NetworkPeerType.Disconnected)

    {

       // If not connected若是沒有鏈接

       if (GUI.Button (new Rect(10,10,100,30),"Connect"))

       {

           Network.useNat = useNAT;

           // Connecting to the server鏈接服務器

           Network.Connect(remoteIP, remotePort);

       }

       if (GUI.Button (new Rect(10,50,100,30),"Start Server"))

       {

          Network.useNat = useNAT;

          // Creating server建立服務器

          Network.InitializeServer(32, listenPort); 

         // Notify our objects that the level and the network is ready

         //通知咱們場景裏物體,network(網絡)準備好了

         for (var go : GameObject in FindObjectsOfType(GameObject))

         {

             go.SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver);

          }

      }

      remoteIP = GUI.TextField(new Rect(120,10,100,20),remoteIP);

      remotePort = parseInt(GUI.TextField(new Rect(230,10,40,20),remotePort.ToString()));

   }

   else

   {

       // If connected若是鏈接了

       // Getting your ip address and port得到你的ip地址和端口

       ipaddress = Network.player.ipAddress;

       port = Network.player.port.ToString();

       GUI.Label(new Rect(140,20,250,40),"IP Adress: "+ipaddress+":"+port);

       if (GUI.Button (new Rect(10,10,100,50),"Disconnect"))

       {

           // Disconnect from the server從服務器斷開鏈接

           Network.Disconnect(200);

        }

    }

function OnConnectedToServer()

{

    // Notify our objects that the level and the network is ready 

    // 通知咱們的物體場景和network準備好了

    for (var go : GameObject in FindObjectsOfType(GameObject))

       go.SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver);

}  

function OnDisconnectedFromServer ()

{

     if (this.enabled != false)

         Application.LoadLevel(Application.loadedLevel);

     else

     {

         var _NetworkLevelLoad : NetworkLevelLoad = FindObjectOfType(NetworkLevelLoad);

         _NetworkLevelLoad.OnDisconnectedFromServer();

      }

 } 

如今能夠測試這種鏈接方式了。

[轉載]Unity3d多人在線教程按上面的要求設置你的Player Settings(若是你剛剛沒有改變他們)

[轉載]Unity3d多人在線教程 把工程編譯到iPhone

[轉載]Unity3d多人在線教程播放StarTrooper場景在編輯器。

[轉載]Unity3d多人在線教程在編輯器和在iPhone上點擊Direct Connection。

[轉載]Unity3d多人在線教程從編輯器點擊Start Server開啓服務器。

[轉載]Unity3d多人在線教程在iPhone上IP框輸入IP地址的。你能夠從Editor Player場景獲得IP地址。

[轉載]Unity3d多人在線教程你的場景應該看起來想這張圖片。

[轉載]Unity3d多人在線教程

[轉載]Unity3d多人在線教程

咱們已經完成咱們的客戶段和服務器通三種方式。。。。

 

4。3。3。最後潤色

 

咱們的工程如今已經基本完成。爲了使咱們的遊戲更具可玩性咱們須要去添加一些最終的潤色:

[轉載]Unity3d多人在線教程打開StarTrooper場景

[轉載]Unity3d多人在線教程選擇SpaceCraft預設而且設置Transform Scale參數成:1.8,1.8,1.8.

[轉載]Unity3d多人在線教程 選擇Main Camera在Hierarchy而後改變公共 變量在Play Controls腳本:Turn Speed: 3, Max Turn Lean: 70, Max Tilt: 50, Sensitivity: 0.5, Forward Force: 20.

[轉載]Unity3d多人在線教程在Main Camera 裏打開MissileLauncher.js腳本。在第16行,改變向量從Vector3(0,-0.2,1) 到Vector3(0,-0.3,0.5).

[轉載]Unity3d多人在線教程選擇missilePrefab預設而且設置Transform Scale參數成:8,8,8。

[轉載]Unity3d多人在線教程你最後的屏幕應該看起來像這張圖片。

[轉載]Unity3d多人在線教程

提示:這些最新的修改在個人嘗試中是基本的,因此能夠隨意的作出你的本身的修改和新的功能。

 

祝賀你!你已經完成了MultiPlayer MultiPlayer StarTrooper工程。。。。

你已經學習瞭如何去:

[轉載]Unity3d多人在線教程準備一個場景和物體爲network.

[轉載]Unity3d多人在線教程變換一個場景和物體在network.

[轉載]Unity3d多人在線教程一個單人遊戲轉換成多人

[轉載]Unity3d多人在線教程建立一個Master Server/Client.

[轉載]Unity3d多人在線教程建立一個Server/Client用直接鏈接。

[轉載]Unity3d多人在線教程建立一個Server/Client用UDP廣播鏈接。

[轉載]Unity3d多人在線教程用主要的Network組件。

[轉載]Unity3d多人在線教程用增長的Unity組件

相關文章
相關標籤/搜索