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