顯示具有 網路連線 標籤的文章。 顯示所有文章
顯示具有 網路連線 標籤的文章。 顯示所有文章

2010年8月8日 星期日

Unity3D的Socket連線實作範例


版權歸 UnityBuster.blogspot.com 所有。轉載請註明出處!

你可以使用標準的 .net sockets 來連接Unity和其他的socket-based應用軟體. 另外, 你也可以使用大多數的.net 2.0 API. 如果你有Unity Pro, 你還可以自己撰寫 C++ Dlls來使用, 需注意的是, 為了安全的理由, C++ Dlls不可以用在Web Player之中.

.NET Sockets 基本來說就是 TCP/IP Sockets. .NET 現有的network classe例如:TcpClient(client端)和 TcpListener(伺服器端), 它們包括了Socket及其他的支援功能, 這比直接使用Socket來得容易一些.

以下為一個簡單的試作.  若是想要實際在Unity中驗證,  可以開啟一個新的Project, 先create一個JavaScript並更名為GUI_Script後將以下'GUI_Scripts.js'的內容貼入. 完成後, 在Unity/Project子視窗中左鍵按住此一物件並移動到Hierarchy子視窗中的"Main Camera"物件上放開左鍵, 此一腳本即可和Camera連接上, 執行時就可以看到GUI在畫面上顯示.  接下來在Unity/Project視窗中create一個folder並更名為"Standard Assets", 然後在此一folder中create一個C Sharp Script並更名為s_TCP後將以下的's_TCP.cs'內容貼入.  將最上端的server程式編譯後執行, 然後執行Unity的client即可看到結果.

Client端的C# TCP腳本程式是附加在一個JavaScript GUI腳本上的.這個GUI腳本包含一個"Connect"按鈕, 一個"Level 1"按鈕和一個"Level 2"按鈕, 一個文字框和一個 "Disconnect"按鈕. 開始時, 畫面只會出現一個"Connect"按鈕, 按下按鈕後會把Unity的TcpClient連接到Server端建立Socket連線. 之後"Connect"按鈕會消失, 變而出現"Level 1", "Level 2"按鈕, 文字框, 和"Disconnect"按鈕. 當按下"Level 1"或"Level 2"按鈕, 文字框內利用GUI腳本的 WriteSocket()功能將預設的文字傳送給server, 而server則將收到的文字轉換成大寫傳回. 這個GUI腳本同時也包含了一個 ReadSocket()功能用來讀取server傳回的資訊並顯示在文字框中. 最後按"Disconnect"按鈕時則關閉連線回到"Connect"按鈕的初始畫面

Server端是取自MSDN的一個很簡單的程式碼, 一次只能處理一個Client的連結. 但足以用來驗證連線功能, 日後若想要強化, 則可依個人需求來修改了.

====================================================

以下為Server端 TcpListener 程式碼範例:

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;

class MyTcpListener
{
  public static void Main()
  { 
    TcpListener server=null;   
    try
    {
      // Set the TcpListener on port 13000.
      Int32 port = 13000;
      IPAddress localAddr = IPAddress.Parse("127.0.0.1");
      
      // TcpListener server = new TcpListener(port);
      server = new TcpListener(localAddr, port);

      // Start listening for client requests.
      server.Start();
         
      // Buffer for reading data
      Byte[] bytes = new Byte[256];
      String data = null;
      int counter = 0;


      // Enter the listening loop.
      while(true) 
      {
        Console.Write("Waiting for a connection... ");
        
        // Perform a blocking call to accept requests.
        // You could also user server.AcceptSocket() here.
        TcpClient client = server.AcceptTcpClient();
        counter++;
        Console.WriteLine("#"+counter+" Connected!");

        data = null;

        // Get a stream object for reading and writing
        NetworkStream stream = client.GetStream();

        int i;

        // Loop to receive all the data sent by the client.
        while((i = stream.Read(bytes, 0, bytes.Length))!=0) 
        {   
          // Translate data bytes to a ASCII string.
          data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
          Console.WriteLine("Received: {0}", data + counter);
       
          // Process the data sent by the client.
          data = data.ToUpper();

          byte[] msg = System.Text.Encoding.ASCII.GetBytes(data+"Client counter:"+counter);

          // Send back a response.
          stream.Write(msg, 0, msg.Length);
          Console.WriteLine("Sent: {0}", data + "Client counter:"+counter);            
        }
         
        // Shutdown and end connection
        client.Close();
      }
    }
    catch(SocketException e)
    {
      Console.WriteLine("SocketException: {0}", e);
    }
    finally
    {
       // Stop listening for new clients.
       server.Stop();
    }

      
    Console.WriteLine("\nHit enter to continue...");
    Console.Read();
  }   
}


====================================================

以下為一個C# TCP 程式碼 's_TCP.cs', 本程式取自Unity Forum中並加以簡單的修改:

using UnityEngine;
using System.Collections;
using System;
using System.IO;
using System.Net.Sockets;

public class s_TCP : 
MonoBehaviour {
    bool socketReady = false;

    TcpClient mySocket;
    NetworkStream theStream;
    StreamWriter theWriter;
    StreamReader theReader;
    String Host = "localhost";
    Int32 Port = 13000; 

    // Use this for initialization
    void Start() {

    }

    // Update is called once per frame
    void Update() {

    }

    public void setupSocket() {
        try {
            mySocket = new TcpClient(Host, Port);
            theStream = mySocket.GetStream();
            theWriter = new StreamWriter(theStream);
            theReader = new StreamReader(theStream);
            socketReady = true;
        }
        catch (Exception e) {
            Debug.Log("Socket error:" + e);
        }
    }

    public void writeSocket(string theLine) {
        if (!socketReady)
            return;
  String tmpString = theLine + "\r\n";
        theWriter.Write(tmpString);
        theWriter.Flush();
    }

    public String readSocket() {
        if (!socketReady)
            return "";
        if (theStream.DataAvailable)
            return theReader.ReadLine();
        return "";
    }

    public void closeSocket() {
        if (!socketReady)
            return;
        theWriter.Close();
        theReader.Close();
        mySocket.Close();
        socketReady = false;
    }
 
    public void maintainConnection(){
 if(!theStream.CanRead) {
  setupSocket();
 }
    }
} // end class s_TCP

====================================================

以下為一個JavaScript的GUI腳本 'GUI_Scripts.js':

private var textFieldString = "Socket Testing String";
private var myTCP; 

function Awake() {
 myTCP = gameObject.AddComponent(s_TCP);
}

function OnGUI () {
 if(myTCP.socketReady==false) {
  if (GUI.Button (Rect (20,10,80,20),"Connect")) {
   myTCP.setupSocket();
  }
 }
 else {
  myTCP.maintainConnection();

  if (GUI.Button (Rect (20,40,80,20), "Level 1")) {
   myTCP.writeSocket(" The is from Level 1 Button");
   textFieldString=myTCP.readSocket();
  }
  if (GUI.Button (Rect (20,70,80,20), "Level 2")) {
   myTCP.writeSocket(" The is from Level 2 Button");
   textFieldString=myTCP.readSocket();
  }
  
  textFieldString = GUI.TextField (Rect (25, 100, 300, 30), textFieldString);
  
  if (GUI.Button (Rect (20,140,80,20),"Disconnect")) {
   myTCP.closeSocket();
   textFieldString = "Socket Disconnected...";
  }
 }
}
版權歸 UnityBuster.blogspot.com 所有。轉載請註明出處!

2010年7月11日 星期日

Unity 3D 多人線上遊戲要如何開始


Unity3D在多人線上遊戲的架構中主要是扮演了前台Client端的角色, 而它的網路功能則提供了開發者的一個簡單選項. 然而, 它對連線數的支持到底是如何呢? 以下提供了一些基本資訊與教程:
Unity's networking functions.
http://unity3d.com/support/documentation/ScriptReference/Network.html
Unity提供多人線上遊戲的開發者兩種選擇:
一. 使用Unity3D內建的網路功能, 你可以從以下兩個主要的範例開始 :
1. Unity的官方網路範例:
http://unity3d.com/support/resources/example-projects/networking-example
2. Leepo的教程: 此教程主要是使用Unity本身為Server, 連線數約為100人.
http://forum.unity3d.com/viewtopic.php?t=30788

二. 使用HTTP/sockets來和市面上第三者開發的後台伺服器軟體(如:SmartFox, NetDog, Photon 等..., 此項之具體作法可在各相關伺服器之網站找到, 不過大多交代不清, 或隱藏在範例中不易發覺, 相信也是眾多開發者頭痛的地方), 或者自行開發後台. MMO是指 "大量多人線上", 上面的選項可以作到多人, 但是無法做到大量如千人以上. HTTP/socket的方式則可以達成這一步.

2010年6月28日 星期一

想用Unity3D來開發MMO嗎?


Unity3D 可以用來開發MMO嗎? 當然是可以的! MMO - 顧名思義就是大量多人連線, 早已跳脫了單機遊戲之外, Unity提供了開發者一個大展身手的舞台,也提供了基本連線功能, 可是, 要如何把成百上千個玩家串在一起, 讓你中有我, 我中有你呢? 對那些已經在這行的老手, 這自不在話下.可是, 對那些非程式設計師或新手而言,要如何開始呢?
既然談到了MMO, 就免不了提到 Client/ Server的架構. Unity提供了client端的絕妙選擇, 但是, server端呢?
除了自己寫server之外又有哪些選擇呢? 幸好, 坊間還是有一些選擇可供新手來過過癮的, 有些是免費, 有些是以連線數來訂價, 有些則另行報價, 茲列於下:

SmartFoxServer
http://www.smartfoxserver.com/

Photon
http://photon.exitgames.com/

NetDog
http://www.pxinteractive.com/

Project Darkstar
http://www.projectdarkstar.com/

RakNet
http://www.jenkinssoftware.com/

Quazal
http://www.quazal.com/

Hero Engine
http://www.heroengine.com/

Icarus Studios
http://www.icarusstudios.com/

Monumental Games
http://www.monumentalgames.com/

MultiVerse
http://multiverse.net/index.html

BigWorld Technology
http://www.bigworldtech.com/index/index.php

Open Simulator
http://opensimulator.org

Badumna Network Suite - 一個P2P MMO多人線上伺服器
http://www.badumna.com/

Lidgren Network
http://code.google.com/p/lidgren-network/

All middeware can be used with Unity as long as it plays well with the Mono interface.