2010年8月11日 星期三

Unity 3D Client/Server Socket Connection Sample Code


版權歸 UnityBuster.blogspot.com 所有。轉載請註明出處!
Welcome to link to this blog when referencing the article!

I'v been looking everywhere to find a socket connection sample code for Unity 3D. Although there are many sites/blogs pointed out some feature, but not a sample in whole can be found. Finally, I put some resources that I found and came out this sample. Hope those people who are looking for the answer can get one step further via this article.

You can use .net sockets to connect between Unity and socket-based applications. Furthermore, you can use most of the .net 2.0 API. If you happen to have a Unity Pro, you can write your own C++ Dlls, be noted, for the security reason, C++ Dlls can't be used with Web Player.

.NET Sockets is kind of TCP/IP Sockets. Existing network class of .NET, ex: TcpClient(client side) and TcpListener(server side), they include socket other feature support, and are easier then using Socket directly.

Below is a simple implementation. There are 2 parts: server side and client side. Server side is the Server side TcpListener code listed below. Just compile it and run it to wait for the connection. The Server was a sample code from MSDN, it can handle one Client connection at a time. As an example to make the socket connection work is enough. I'll keep on working on a simple server code that can handle multiple clients. Wish I can get it in the near future.

To do the client in the Unity, you can create a new Project, then create a JavaScript and rename to GUI_Script, copy and past the code in 'GUI_Scripts.js' listed below. When you finish this step, press left key to grab "CUI_Script" inside Unity/Project sub-window and drop on the "Main Camera" object inside Hierarchy sub-window, the script can then be attached to the Camera, you can then see the GUI when running the game. We then create a folder in the Unity/Project sub-window and rename to "Standard Assets", create a C# Script, rename it to "s_TCP", copy and past the code in the 's_TCP.cs' below. Now, run the unity game, you can try the result now.

Client side C# TCP script is attach to a GUI JavaScript. The GUI JavaScript contains a "Connect" button, a "Level 1" button, and a "Level 2" button; a text field and a "Disconnect" button. In the beginning of the game running, there is only one "Connect" button display on the screen; after the player press the button, the Unity game client will connect to the Server and establish a socket connection. The "Connect" button disappear, and the "Level 1", "Level 2" button, text filed, and "Disconnect" button show up. Whenever press the "Level 1" or "Level 2" button, the text field will use WriteSocket() function in the GUI JavaScript to send the preset string to the server, the server will then convert the lower case text to upper case text and send the result string to the client. The GUI JavaScript will then use the ReadSocket() function to read the return string and display in the text field. If you press the "Disconnect" button, the connection will be closed and the screen will change back to display "Connect" button only.



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

Code listed below is for Server side 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();
  }   
}


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

Code listed below is a C# TCP program 's_TCP.cs', which was graped from Unity Forum and made some modification:

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

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

This is a JavaScript '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 所有。轉載請註明出處!
Welcome to link to this blog when reference the article!

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年7月9日 星期五

Unity3D - 遊戲以外的事 (Unity3D: Beyond the Game)


本文轉載自www.everyday3d.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

我不是一個遊戲開發者。在過去的10年間,我一直是一個Flash的設計者和開發者。我曾經製作過許多項目包括廣告,如動畫(包括橫幅,視頻網站,豐富的媒體接口,網絡應用,三維仿真),以及簡單的遊戲。

然而相較於Flash,我相信Unity3D更像是一個遊戲開發平台,而前面提到所有這些類型的項目同樣都可以用Unity3D來解決。而在某些情況下,Unity3D得出的結果遠超出了我們目前用Flash和ActionScript可以得到的 - 這正是我期待的好機會。 (在某些情況下,最終可能變成災難,就好像明明用HTML就可以完成的網頁,結果卻用Flash來完成。我們將可預期同樣的事情會再度發生,只因為人都會犯錯)。

技術被接受採用的速度其時並沒有我預期的快。我敢肯定,Unity3D最終將成為3D Web(網頁)應用程式的標準,但是我們還沒有到達那裡。到目前為止,Unity 的iPhone遊戲已經非常成功的被開發出來,而它也逐漸成為開發線上遊戲的首選工具。廣告業也將會跟進採用Unity3D。我們可以預期尖端的互動機構和生產企業很快會開始釋放Unity3D製作的產品。我希望這會在這一兩年發生。這是很有機會的,因為許多這樣的專案已經在進行當中。UnityBuster整理翻譯

之所以會出現這種情況是因為Unity3D是多才多藝的。它是被當作一個 “遊戲開發工具” 來銷售,但它有許多功能都超過了這樣的定義。它允許多樣化的內容整合(二維,三維,視頻,聲音),具有強大的動畫工具和強大的腳本API可用來創建任何複雜的邏輯運算。

當我滿載著靈感從阿姆斯特丹FITC回來,我決定更深入地看看Unity3D腳本和至少多於基本功能和多於只建立一個“第三人稱射擊”的情況。作為一個長期的Flash開發人員,對於典型的Actionscript技術也有一些困擾和問題,我決定檢驗是否可以用 Unity3D來解決類似的問題。這裡是幾個首先出現在我心中的基本問題:

1. How to dynamically load an image into Unity3D and do something with it?
2. How to load a video?
3. How to draw lines, points and shapes at runtime?
4. How to generate content with code?

這些問題的順序是從那些最容易回答的問題開始。我有更多的問題排在後面,所以這個貼文可能會有後續的更新。無論如何,在未來的日子(或數週)我會發布它的解決方案。我做了一些嘗試,我有一些我在一路研究的心得代碼以及一些提示來分享。再見!

本文轉載自www.everyday3d.com,版權歸原作者所有,UnityBuster.blogspot.com整理翻譯。轉載請註明出處!

2010年7月2日 星期五

Unity小遊戲


非常不錯的小遊戲! 由SilverTree Media用Unity製作的一個Demo, 不錯玩!
http://www.cordythegame.com/