U3D对的网络功能是尽可能可靠,灵活为设计原则。两种成熟的网络方案是 授权服务器和非授权服务器。


1.授权服务器其实也叫状态同步 ,由服务器处理所有的游戏状态,客户端只是处理输入请求和表现,不维护具体的游戏状态逻辑。主角的移动,技能的释放需要服务器作出反应,这些状态才能真正有效。可以避免外挂,但是问题是操作有网络延迟,需要做前摇处理。


2.非授权服务器也叫帧同步 ,由客户端进行游戏的交互和本地进行游戏逻辑的处理,只需要通知结果或操作命令给服务器,服务器对结果或操作命令同步给其它玩家。优势是自己操作交互迅速,可以把本地战斗表现做得更好,劣势是要处理外挂和处理不同步问题。


网络通信有两种方式:


1) 远程过程调用RPC,本地客户端调用了某个事件函数,发送给服务器,服务器调用所有副本中的其它客户端的该事件函数。


2)状态同步,状态同步用于在不同客户端之间同步改变的数据,例如一个玩家的跑动,跳跃和释放技能,那么需要将这些必要的状态同步给其它客户端,需要消耗较多带宽,要不断进行网络优化。


3. Network view组件 ,可以进行远程过程调用和状态同步两种方式的通信,也可以设置进行状态同步时候什么数据进行共享和那些对象会被同步。


State Synchironization是状态同步方式,如果是off那么是使用RPC调用,不使用状态同步。如果是可靠的那么只有状态改变才同步,不改变不会同步,且同步失败会重传。使用不可靠则没有改变也会同步且不会重传。


Observed:是该游戏对象的数据会进行网络传递。


View ID中的scene id是游戏场景中唯一的id,会根据该id进行生成数据和转发数据。


网络游戏对象管理+状态同步+RPC组成了Unity的网络协议,所有需要实现的多人游戏的网络功能都是构建在这套Unity网络协议的基础之上的。


实例:


服务端:


服务器socket侦听建立:


NetworkConnectionError error=Network.InitializeServer(connectCount,remotePort,useNAT); 

 

  获取当前连接ip和端口: 

 

  int connectLength=Network.connections.Length; 

 

  //遍历所有客户端并获取IP与端口号 

 

  for(int i=0;i<connectLength;i++){ 

 

  GUILayout.Label(" 连接的IP:"+Network.connections[i].ipAddress); 

 

  GUILayout.Label(" 连接的端口:"+Network.connections[i].port); 

 

  } 

 
连接建立的回调调用RPC:
 

  void OnPlayerConnected(NetworkPlayer player) 

 

  { 

 

  networkView.RPC("OnNetworkLoaded",RPCMode.Others,player); 

 

  } 

 

  void OnPlayerDisconnected(NetworkPlayer player) { 

 

  Debug.Log("清除对象: " + player); 

 

  Network.RemoveRPCs(player); 

 

  Network.DestroyPlayerObjects(player); 

 

  }



客户端:


连接到服务器:

Network.Connect(remoteIP,listenPort,"UnityNetwork");
 

  连接后回调函数,是同步的: 

 

  void OnConnectedToServer(){ 

 

  foreach(GameObject go in FindObjectsOfType(typeof(GameObject))) 

 

  { 

 

  go.SendMessage("OnNetworkLoaded",SendMessageOptions.DontRequireReceiver); 

 

  } 

 

  } 

 

  // 连接后的回调: 

 

  public void OnNetworkLoaded(){ 

 

  Debug.Log ("OnNetworkLoaded!!"); 

 

  //int playerID=int.Parse(player.ToString()); 

 

  Network.Instantiate(control,transform.position,transform.rotation,0); 

 

  } 

 
断开回调函数,是同步的:
 

  void OnDisconnectedFromServer(NetworkDisconnection info){ 

 

  } 

 
 
 
 
通过RPC调用同步角色的动画:
 

  animation.Play("walk"); 

 

  networkView.RPC("PlayState",RPCMode.OthersBuffered,"walk"); 

 

  [RPC] 

 

  void PlayState(string state){ 

 

  animation.Play(state); 

 

  }

总结:


Network view组件的networkView成员,调用RPC函数来驱动其它客户端的同步。


通过Network类来建立服务器,建立和断开连接。


RPC函数的调用方便直接,但是需要仔细的规划函数接口,否则导致大型项目混乱。而且不方便将角色数据放置到数据库中,不方便部署到linux服务器环境下,还是用传统的服务器网络设计方式适合大型项目。



unity5 后引入的UNET,带来了很多好处,可以便捷开发,但是也带来了一些坏处。


1.带来的坏处,安全性上堪忧,客户端和服务器逻辑都在一起,一旦客户端被反编译了,那么是不是服务器逻辑都泄漏了。


2.网络性能不好,同步太多数据不好控制,且在linux上部署一个unity的服务端,很难支撑更多的人数。


2.Unity Cloud在国内半残,国内访问unity网站网络性能不好,而且还被unity的收费限制。