| 
 | 
 
 
 楼主 |
发表于 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楼继续.................... 
 |   
- 
 
 
 
 
 
 
 
 |