跳转到内容

使用 XNA 创建游戏/网络/网络引擎

50% developed
来自维基教科书,开放世界的开放书籍

网络引擎

[编辑 | 编辑源代码]

其他看起来有用的引擎

  • WCF - Windows 通信基础
  • XNA 集成
  • RakNet

其他有趣的事实和示例可以在这里找到:http://create.msdn.com/en-US/education/catalog/?devarea=19,特别是名为网络预测的那个。

Lidgren 网络引擎

[编辑 | 编辑源代码]

Lidgren 网络引擎是一个由 Michael Lidgren 创建的基于 .NET 的库。它基本上可以与所有类型的 .NET 应用程序一起使用。它使用单个 UDP 套接字进行传输,并提供用于点对点和服务器-客户端连接的类。该引擎在 MIT 许可下运行,这意味着可以免费使用它。当前版本“gen3”需要 .NET 3.5 或更高版本。Lidgren 附带一个额外的库,其中包含一些类扩展方法,以便更好地支持 XNA。但是,您不能将 Lidgren 用于 Xbox 游戏。[1]

重要类

[编辑 | 编辑源代码]

NetPeer
NetPeer 代表本地连接点。它保存并创建到其他对等点的连接。重要的派生类是NetServerNetClient,它们包含针对服务器-客户端系统的适当修改。

NetOutgoingMessage
此类的对象是您信息的载体。要创建一个,您必须使用 NetPeer 对象的 CreateMessage() 方法。使用 Write(),您可以将所有数据放入消息中。Write() 接受所有基本类型和对象。

NetIncomingMessage
这用于保存有关接收消息的信息。除了内容,它还说明了 MessageType,它可能是与库相关的,也可能是您发送的数据。*MessageType 列表*

NetConnection
表示与远程主机的连接。

如何开始

  1. 项目的网站下载最新版本。
  2. 打开“Lidgren XNA Extensions/Lidgren XNA Extensions.sln”文件并编译解决方案。
  3. 将创建的 .dll 文件复制到您的项目文件夹中,并在您的项目中引用它们。
  4. 现在,您应该能够使用 Lidgren.Network 命名空间。

如何创建对等点

class Program
{
    //hold the NetPeer Object as a member
    //In this example I use a server, because it is more common to work with server and clients
    private NetServer server;

    public Program()
    {
        //When initialising, create a configuration object.
        NetPeerConfiguration config = new NetPeerConfiguration("Server");

        //Setting the port, where the NetPeer shall listen. 
        //This is optional, but for a server its good to know, where it is reachable
        config.Port = 50001;
        //Create the NetPeer object with the configurations.
        server = new NetServer(config);
        //Start
        server.Start();
    }
}


如何发送消息

//get a message from the servers message pool
NetOutgoingMessage msgOut = server.CreateMessage();
//write your data
msgOut.Write("Some Text");
msgOut.Write((short)54);
//send the message to a client
server.SendMessage(msgOut, client, NetDeliveryMethod.ReliableOrdered);

不同的 NetDeliveryMethods 在这里解释。

如何接收消息

//use local message variable
NetIncomingMessage msgIn;
//standard receive loop - loops through all received messages, until none is left
while ((msgIn = server.ReadMessage()) != null)
{
    //create message type handling with a switch
    switch (msgIn.MessageType)
    {
        case NetIncomingMessageType.Data:
            //This type handles all data that have been send by you.
            break;
        //All other types are for library related events (some examples)
        case NetIncomingMessageType.DiscoveryRequest:
            //...
            break;
        case NetIncomingMessageType.ConnectionApproval:
            //...
            break;
                    
    }
    //Recycle the message to create less garbage
    server.Recycle(msgIn);
}

可以在这里找到所有 MessageTypes 的描述。

如何连接到服务器
[2]第一步是启用三个特定的消息类型。

//for the server
serverConfig.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
serverConfig.EnableMessageType(NetIncomingMessageType.DiscoveryRequest);
//for the client
clientConfig.EnableMessageType(NetIncomingMessageType.DiscoveryResponse);

初始化客户端后,您可以搜索服务器。因此,您可以向 IP 地址发送请求,或搜索本地网络中的所有系统。

//search in local network at port 50001
client.DiscoverLocalPeers(50001);

服务器现在已收到 DiscoveryRequest,必须由“接收消息循环”处理。

case NetIncomingMessageType.DiscoveryRequest:
    NetOutgoingMessage msg = server.CreateMessage();
    //add a string as welcome text
    msg.Write("Hellooooo Client");
    //send a response
    server.SendDiscoveryResponse(msg, msgIn.SenderEndpoint);
    break;

客户端现在已收到服务器的 DiscoveryRequest。假设本地网络中只有一个服务器,您可以直接连接到它。

case NetIncomingMessageType.DiscoveryResponse:
    Console.WriteLine("Server answered with: {0}", msgIn.ReadString());
    client.Connect(msgIn.SenderEndpoint);
    break;

最后一步是在服务器端接收 ConnectionApproval 消息并批准连接。

case NetIncomingMessageType.ConnectionApproval:
    msgIn.SenderConnection.Approve();
    break;

RakNet 是一个包含多个类以执行网络解决方案的库,由 Jenkins Software LL 开发。它是一个跨平台库,适用于 C++ 和 C#。因此,它可以在所有主要平台上使用,包括 Android 和 iOS。主要功能包括对象复制、大厅系统、安全连接、语音通信和自动修补程序。[3]

Swig 可用于为本机 DLL 生成包装代码,从而允许在 C# 中使用 RakNet。[4] Swing 生成 CXX 和 .h 文件,这些文件表示接口,以及 C# 项目连接到 DLL 所需的包含文件。有关如何使用 Swig,请参阅详细说明

重要类

[编辑 | 编辑源代码]
RakPeerInterface
[编辑 | 编辑源代码]

尽管 RakPeerInterface 不是一个实际的类,但它是网络通信的主要接口,负责启动。通过调用.GetInstance() 方法返回对等点实例。[5]

SocketDescriptor
[编辑 | 编辑源代码]

一个实例描述了本地套接字,可用于启动。[5]可以使用参数定义端口,或使用 0 自动选择一个空闲端口。此外,如果需要,可以创建套接字描述符数组。[6]

它代表来自另一个系统/计算机的消息,并包含有关消息的信息,例如长度、比特大小或发送者的 ID。

===== 作为客户端的连接 ===== [7]

using UnityEngine;
using System;
using System.Collections;
using RakNet;

public class ConnectClient {
      public static string remoteIP = 127.0.0.1;
      RakPeerInterface myClient;
      SocketDescriptor scktDist;
      //…
      void Awake() {
            myClient = RakPeerInterface.GetInstance();
            scktDist = new SocketDescriptor();
            //  Prameters: 1) max. number of connection 2) SocketDescriptor to specifie ports/addresses
            myClient.Startup(1,scktDist,1);
      }
      void OnGUI(){
      //…
      // if not yet connected
      myClient.Connect(remoteIP, 25000, “”,0);
      //…
      }
}

===== 作为服务器的连接 ===== [8]启动服务器与上述说明非常类似。

public class ConnectServer  {
      public static string remoteIP = 127.0.0.1;

      public static int maxConnectionsAllowed = 4:
      public static int maxPlayersPerServer = 10;

      RakPeerInterface server;
      SocketDescriptor scktDist;
      //…
      void Awake() {
            server = RakPeerInterface.GetInstance();
            scktDist = new SocketDescriptor();
            server.Startup(maxConnectionsAllowed, 30, scktDist, 1);
            server.SetMaximumIncomingConnections(maxPlayersPerServer);
      }

}

===== 数据包的读取 ===== [8]说明,如果数据包为 0,则没有要读取的内容。

public class PackageReading  {

      RakPeerInterface server;
      Packet p;
      //…
      void Reading() {

            while (true) {
                  if (p = server.Receive()) {
                             // do something terribly interesting with p...
                  }
            }

      }

}

===== 数据包的发送 ===== [9]说明,它使用 BitStreams 创建“数据包”。

public class PackageReading  {

      RakPeerInterface peer;
      Packet p;
      //…
      void Sending() {
            MessageID useTimeStamp; // Assign this to ID_TIMESTAMP
            Time timeStamp; // Put the system time in here returned by GetTime()
            MessageID typeId; // This will be assigned to a type I've added after            ID_USER_PACKET_ENUM, lets say ID_SET_TIMED_MINE
            useTimeStamp = ID_TIMESTAMP;
            timeStamp = GetTime();
            typeId=ID_SET_TIMED_MINE;

            BitStream message = new BitStream();
            message.Write(useTimeStamp);
            message.Write(timeStamp);
            message.Write(typeId);

            message.Write("Hallo",5);

            peer = Send(BitStream * bitStream,HIGH_PRIORITY,RELIABLE,0,UNASSIGNED_SYSTEM_ADDRESS,true);
      }

}

Windows 通信基础

[编辑 | 编辑源代码]

微软的 Windows Communication Foundation (WCF) 是一个平台或应用程序编程接口,它捆绑了多种技术,用于构建连接的服务或程序。微软将其功能定义为:面向对象、互操作性、多种消息模式、服务元数据、安全性和 AJAZ 和 REST 支持。 [10] 它支持通过 HTTP、TCP、消息队列等传输 SOAP。 WCF 需要 Windows XP SP2 或更高版本。 [11]

参考文献

[编辑 | 编辑源代码]

mglaeser 和 juliusse

华夏公益教科书