【转】Unity网络机制的相关实现流程

连接 和断开连接

这个示例是一个简单的测试客户端与服务器连接、断开连接的功能。发布出的程序,既可以作为客户端,也可以作为服务器。所以在测试时候,需要运行两个程序实例。其初始界面如下:

上面两条是填写相应的IP地址和端口号,如果以服务器运行,就点Start Server,程序就会开始监听指定端口。

如果以客户端来运行,就点Connect as client。一般用Build后的程序来运行客户端,用编辑器来运行服务器,当有客户端成功连接到服务器,会在编辑器的Console窗口中出现类似如下信息:

Player connected from: 127.0.0.1:1350

实现过程中,需要在编辑器建立一个空的GameObject,这里起名叫Scripts。然后为其附加连接的脚本Connect.js。其中两个可设置的属性connectToIP、connectPort是脚本的两个公共变量,在脚本中声明如下:

var connectToIP : String = "127.0.0.1";

var connectPort : int = 25001;

然后在GUI的处理函数OnGUI中,先根据当前的网络状态决定不同的UI显示布局,网络状态可以用Network.peerType来获得,可以有4种状态Disconnected、Connecting、Client、Server,分别表示断开连接的状态、尝试连接服务器的状态、作为客户端运行的状态、和作为服务器运行的状态。这里在Disconnected状态下显示初始界面,这里比较重要的逻辑是Start Server按钮和connect as client按钮的处理。

如果点击了Start Server按钮,就开启服务器:

Network.useNat = false;

Network.InitializeServer(32, connectPort);

Network是Unity一个内置类,其中useNat表示是否启用NAT机制。之后在启动服务器的函数InitializeServer中传入两个参数,第一个表示允许最大的连接数量,第二个就代表端口号。

这样就可以开始监听指定端口了。

如果点击connect as client,就进行如下操作:

Network.useNat = false;

Network.Connect(connectToIP, connectPort);

这里的操作也很简单,只需要调用Network的Connect函数指定连接到的IP和端口号就可以连接到服务器端。

当服务器端程序接到来自一个客户端连接后,会触发unction OnPlayerConnected(player: NetworkPlayer)事件函数,所以为脚本添加这个函数,在这个函数处理中,就在编辑器的Console中显示之前看到的连接信息。

function OnPlayerConnected(player: NetworkPlayer) {

Debug.Log("Player connected from: " + player.ipAddress +":" + player.port);

}

其中的NetworkPlayer类的对象,就包含了这个连接到服务器上的客户端的信息,包括他的IP、端口、GUID、外部IP端口等。

状态同步:

这个示例实现了基本的状态同步的方法,客户端和服务器仍然用的相同的程序。

通过Start Server启动服务器的实例,然后可以用方向键或者wsad控制方块的移动,然后启动另一实例作为客户端,点击Connect as client连接到服务器。这时候通过服务器和客户端之间对筛子的状态同步,当服务器移动方块时候,可以看到客户端程序中的筛子在同步的移动。

实现中仍然先按照连接示例中的方法添加一个物体和附加连接Connect脚本:

然后在Unity创建方块的模型,给模型的对象添加Network View的组件:

为了使用状态同步机制,需要设置State Synchoronization,这里有三个选项一个Off,Reliable Delta Compressed和Unreliable。Off代表不想使用状态同步,后两种是状态同步的两种不同的传输模式,一个是基于差异的压缩,另一个是非可靠的机制。两种都可以实现所需功能,只是根据对带宽、延迟等要求不同决定具体用哪种。

下面是设置Observed,这个属性代表想要同步这个物体的哪一部分数据,其他部分并不会通过网络同步。这里为了保持方块的位置、朝向等信息一致,所以只需要将Transform的组件拖拽到Observed上就可以了。

然后需要实现Server对物体控制移动的逻辑,所以给方块的物体再增加一个脚本

在每帧都会调用的Update()函数中判断如果当前实例是Server,那么就处理移动的输入,更新物体的位移。这样只有Server会控制物体,客户端只根据Server物体的状态同步数据。

if(Network.isServer){

var moveDirection : Vector3 = new Vector3(-1*Input.GetAxis("Vertical"), 0,Input.GetAxis("Horizontal"));

var speed : float = 5;

transform.Translate(speed * moveDirection * Time.deltaTime); }

这样就完成了示例所演示的功能,实现了基本的状态同步的功能。

补充说明:

除此之外,也可以同步Animation、Rigidbody、脚本几种组件类型。

Animation组件同步时会同步动画的播放时间、权重、播放速度,以及是否启用等信息。

Rigidbody组件会同步位置、旋转、速度和角速度信息。

脚本同步中会调用OnSerializeNetworkView()函数,在这里实现自定义数据的收发。

底下的ViewID是只读的,代表这个NetworkView在网络中的唯一ID。每个到达客户端的封包需要应用与一个Network View. Network View ID唯一的区分这个封包属于哪个Network View,Unity会解压封包内容,将其应用到对应的Network View上.

Type显示这个Network View是存到场景中的,还是动态分配的。

RPC通信:

这一实例实现了和状态同步实例同样功能,但是用的机制是RPC通信。

开始的步骤仍然和以前一样,先增加连接的GameObject和附加脚本

然后同样对方块的模型附加Network View组件:

但是这次因为不用状态同步,所以在State Synchoronization和Observed分别设为Off和None。

然后同样对方块附加控制脚本

这次为了实现RPC,在这个脚本里除了要处理操作方块移动的逻辑,还要提供所被调用的RPC函数,以及处理调用的时机。

首先是声明一个RPC函数:

这里需要在函数上方增加@RPC标示,让编辑器认出这是RPC函数。参数的类型和数量是可以自定义的,这里只需要传输位置信息,所以只有一个Vector3的参数。接收到的客户端,会用新的Pos,来更新此物体transform组件的position信息。

在调用的情况下,因为这里只需要Server调用Client,所以在Update()函数中,先判断是不是Server如果是的话,处理完移动的逻辑后,然后才调用RPC

调用的方法是:networkView.RPC("SetPosition", RPCMode.Others, transform.position);

networkView就是给方块物体附加的NetworkView组件,其下的RPC函数就是调用远程方法用的。

第一个参数是调用的方法名称,第二个参数代表调用的对象,有几个枚举值,分别是:Server,Others,OthersBuffered,All,AllBuffered。

之后的参数就是需要传入调用RPC的参数。

这样就完成了RPC调用的实现,将位置信息实时传送到客户端。

补充说明:

RPC调用对象的枚举RPCMode

Server:只调用Server的RPC

Others:会调用除发送者外的其他所有人

OthersBuffered:会调用除发送者外其他所有人,并且添加到缓冲区。

ALL:代表所有人,包括Server和Client

AllBuffered:的除了调用其他所有人外,同时添加到缓冲区。

缓冲RPC的作用是对于后来新来的连接,同样会接收到被缓冲的RPC调用。比如一个常见的情况是,一个Client加入到一个Server里,需要加载一个指定关卡,这样就发送RPC给Client和Server,同时添加到缓冲区。当有新的Client也加入进来时候,就会自动接收到刚才的RPC,加载同样的关卡。

欢迎到论坛参与提问与讨论!~~~~

原帖地址:http://bbs.9ria.com/thread-124775-1-1.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值