|  | 
 
 
 楼主|
发表于 2014-2-16 23:42:49
|
显示全部楼层 
| 本帖最后由 夜行的猫仔 于 2014-2-18 14:29 编辑 
 4.使用RPC传送网络信息
 RPC估计是目前使用最广的网络信息发送方式,至少我看到的例题大多都是RPC方式。
 首次接触RPC,我们还是实现以下上面的功能吧。
 修改服务器代码:将GameObject的NetworkView参数synchronization设为off,observed设为null。
 [mw_shl_code=csharp,true]using UnityEngine;
 using System.Collections;
 
 public class move : MonoBehaviour {
 private Vector3 lastPosition;
 
 // Update is called once per frame
 void Update () {
 if(Network.isServer){
 Vector3 moveDirection  = new Vector3(-1*Input.GetAxis("Vertical"), 0,Input.GetAxis("Horizontal"));
 float speed = 5;
 transform.Translate(speed * moveDirection * Time.deltaTime);
 
 //Save some network bandwidth; only send an rpc when the position has moved more than X
 if(Vector3.Distance(transform.position, lastPosition)>=0.05){
 lastPosition=transform.position;
 
 //Send the position Vector3 over to the others; in this case all clients
 networkView.RPC("SetPosition", RPCMode.Others, transform.position);
 }
 }
 }
 
 [RPC]
 void SetPosition(Vector3 newPos)
 {
 // This RPC is in this case always called by the server,
 // but executed on all clients
 
 transform.position=newPos;
 }
 }
 [/mw_shl_code]在这个代码中,增加了一个新的函数SetPosition,这个例题和之前两个实现了一样的功能。不过Networkview不再监视任何物体,同步选项也已经被关闭。秘密就在这个脚本里,特别是这一行networkView.RPC("SetPosition", RPCMode.Others, transform.position);   RPC是调用远程的函数,因此客户端的代码里也必须有这个函数。
 
 服务器调用了RPC,这个RPC会求客户端调用“SetPosition”函数,同时这个RPC还包含这一个新的位置信息“transform.position”,然后所有的客户端都调用”SetPosition”这个函数。下面是整个移动的过程:
 
 1.服务器端玩家按下按键,他控制的物体移动。
 2.服务器用移动的数值和上次更新的数值比较,如果差距大于设置的最小值,就发送一个RPC给出了自己的所有人,这个RPC种包含了新的物体位置。(代码20-25行)
 3.所有的客户端接收到RPC的设置物体位置命令,并且得到其中包括的新位置参数,然后再它们本地执行位置移动的代码。
 4.现在无论服务器还是客户端,大家的物体都处在相同的位置了~!
 
 如果我们想要使用RPC函数,需要在脚本中这个函数的上面加上“@RPC”(C#里面是”[RPC]”).当发送一个RPC的时候,我们可以指定下列的接收器:
 
 
 RPCMode.Server               :只发送给服务器RPCMode.Others           :发送给除了调用者之外的所有人RPCMode.OthersBuffered     :发送给除了调用者之外的所有人,暂存的内容RPCMode.All             :发送给包括调用者在内的所有人RPCMode.AllBuffered         :发送给包括调用者在内的所有人,暂存的内容
 暂存的内容,指的是无论何时新玩家连接到服务器,都将会接收到这个信息。一个包含暂存内容的RPC可以用于比如说生成玩家的时候。这个暂存的内容会被服务器记住,然后每个玩家连接到服务器的时候,都会先收到一个生成玩家的RPC,这个RPC会在这个刚连接的新玩家的客户端中,生成其他所有在他之前加入服务器的玩家。
 
 5.创建服务器&客户端互动
 以前这几个例子都是服务器端控制,客户端只能看到服务器端运行的结果而无法控制,这个例题客户端将会与服务器互动。首先,前面几个例子都是创建好物体,通过NetworkView将服务器的数据同步到客户端。实际的游戏中,客户端不登陆服务器,是互相看不到游戏中的角色的,也就是说游戏中的角色是实时创建出来的。
 这个例子中,分别在客户端和服务器端都将原来的模型删掉。因为这次我们的资源要等到服务器创建的时候再加载,客户端创建客户端的,服务器创建服务器的,而且双方还要互相能看到对方动。
   在服务器和客户端都创建一个胶囊和一个球,分别染上红色和绿色。绑定好Move脚本和NetworkView ,以及刚体。然后将这两个物体都生成预制体备用。
 修改Move脚本,这样修改的目的是每个端智能控制自己(客户端只能控制球,而服务器端智能控制胶囊)。
 [mw_shl_code=csharp,true]using UnityEngine;using System.Collections;
 
 public class move : MonoBehaviour {
 private Vector3 lastPosition;
 void Update () {
 if(networkView.isMine){
 Vector3 moveDirection  = new Vector3(-1*Input.GetAxis("Vertical"), 0,Input.GetAxis("Horizontal"));
 float speed = 5;
 transform.Translate(speed * moveDirection * Time.deltaTime);
 
 //移动的距离超出一定的值以后才会发送移动消息
 if(Vector3.Distance(transform.position, lastPosition)>=0.05){
 lastPosition=transform.position;
 networkView.RPC("SetPosition", RPCMode.Others, transform.position);
 }
 }
 }
 
 [RPC]
 void SetPosition(Vector3 newPos)
 {
 transform.position=newPos;
 }
 }
 [/mw_shl_code]
 将预制体绿色的球拖到变量ClientPlayer 上。链接服务器的NetClient 脚本增加一句话, 当登录服务器成功以后,增加客户端角色。
 [mw_shl_code=csharp,true]using UnityEngine;
 using System.Collections;
 
 public class NetClient : MonoBehaviour {
 public Transform ClientPlayer;          //客户端的预制体(绿色的球体)
 // Use this for initialization
 void OnGUI()
 {
 if (GUILayout.Button("链接服务器"))
 Network.Connect("192.168.0.2", 6000);
 }
 
 //当登录服务器成功以后,增加客户端角色。
 void OnConnectedToServer() {
 Network.Instantiate(ClientPlayer,transform.position,transform.rotation,0);
 }
 }
 [/mw_shl_code]
 服务器端也有相似的代码,等服务器创建成功以后,将红色的胶囊预制体拖到playerPrefab上,Move脚本和客户端的一样。[mw_shl_code=csharp,true]using UnityEngine;
 using System.Collections;
 
 public class NetServer : MonoBehaviour
 {
 public Transform playerPrefab;
 
 string connectToIP  = "127.0.0.1";
 int connectPort= 6000;
 
 void OnGUI()
 {
 switch(Network.peerType)
 {
 case NetworkPeerType.Disconnected:
 //服务器没有开启
 StartServer();
 break;
 case NetworkPeerType.Server:
 OnServer();
 break;
 }
 
 }
 
 void StartServer()
 {
 if(GUILayout.Button("创建服务器"))
 {
 Network.InitializeServer(32, connectPort);
 }
 }
 
 void OnServer()
 {
 GUILayout.Label("服务器创建成功,等待接入.............");
 }
 
 //Server functions called by Unity
 void OnPlayerConnected(NetworkPlayer player) {
 Debug.Log("有人连接到服务器");
 }
 
 void OnServerInitialized()
 {
 //当服务器建立的时候,创建角色预制体
 Network.Instantiate(playerPrefab, transform.position, transform.rotation, 0);
 }
 }
 [/mw_shl_code]
 这样运行以后,服务器端会生成红色的胶囊,当客户端登陆以后,场景里就会多一个绿色的球,客户端移动小球服务器端也可以看到绿色小球的移动。
 到此为止客户端和服务器端相互通信就解决了。但是这样的工作只是完成了第一步,接下来游戏开发资源会越来越多,客户端和服务器端分开开发就显得很麻烦,接下来将会整合这两套代码并完善其中的资源管理等。
 
 下来的内容在4楼继续....................
 
 | 
 
  |