Object visibility

Unity Networking supports the idea that not all objects on the server should be visible to all players in the game. This is sometimes called “Area of Interest”, as players are only given visibility to objects that the game determines are relevant or interesting to them. Some game features that use this concept are Fog Of War, Stealth and proximity based visibility. This is especially important when the game world is very large on the server or contains many networked objects. Reducing the set of objects visible to player reduces login times, and ongoing bandwidth - as updates are only sent to players for objects that are visible to them. Unity的网络系统可以做到:服务器上的所有object并不是游戏中的所有player都能看到。一般的,这种情况被叫做“Area of Interset”(AOI),因而玩家可以仅仅看到他所感兴趣的那些object。一些游戏可以使用这种概念,比如战争迷雾(Fog of War)。同时,对于超大型的游戏世界,服务端上有很多网络化object的场合下,这种技术也是很重要。减少player的可见object将能大幅度地降低登录时间,降低带宽占用——因为只需发送player可见的object即可。
The simplest way to restrict object visibility for players is use the built-in NetworkProximityChecker component. This works in conjunction with the Unity 3D physics or 2D physics systems to only allow players to see objects that are close to them. To use this component, add it to the prefab of the networked object that you want to have restricted visibility. The NetworkProximityChecker has some configurable parameters. Objects further away than “Vis Range” will not be visible to a player, and each player’s set of visible objects will be recalculated every “Vis Update Interval” seconds. 最简单的方法去减少player的可见object,是使用内建的NetworkProximityChecker组件。这个组件是需要和Unity的3D或者2D物理系统去实现需求的。为了使用这个组件,你需要把这个组件挂接到你想加入这种可见性判断的networked game object上。NetworkProximityChecker组件有若干的可配置参数。例如一个object如果距离player的长度,大于“Vis Range”属性所指定的长度的话,该object将不被player所视。每一个player的“可见object集合”的重新计算和更新,将每隔由“Vis Update Interval”属性指定的秒数去不断进行。
The object must have a physics collider to work with the NetworkProximityChecker. 挂接了NetworkProximityChecker组件的object,同时也需要挂接接一个collider组件
Visibility on Remote Clients
When a player on a remote client joins a network game, only objects that are visible to the player will be spawned on that client. So even if the player enters a large world with many networked objects, the time for world entry can be kept reasonable. This applies to networked objects in the scene, but does not affect the loading of assets - the assets for registered prefabs and scene objects are still loaded. 当一个远程客户端的player加入到游戏时,只有对该player可见的object将会在该远程客户端中被spawn出来。所以尽管玩家可能登录上一个有很多networked object的场景。也不会影响资源的载入——当然,注册到NetworkManager的预设和场景对象依然被加载。
As a player moves within the world, the set of visible objects will change. As this happens, the client is told about these changes. There is an ObjectHide message that is sent to clients when an object is no longer visible. The default behaviour for handling this message is to destroy the object. When an object becomes visible, the client receives an ObjectSpawn message - just as if the object were created for the first time. So by default the object is instantiated like any other spawned object. 当一个player移出游戏之后。可见objects的集合将会发生改变。当改变发生之后,客户端将得到这个发生改变的通知。当一个object不再可视的时候。每一个客户端将会收到一个名为ObjectHide消息。处理这个消息的默认操作便是摧毁这个object。当一个object可视的时候,客户端将会收到一个ObjectSpawn消息。该object也将会被实例化出来。
Visibility on the Host
As the host shares the same scene as the server, it cannot destroy objects that are not visible to the local player. Instead, there is a virtual function on NetworkBehaviour that is invoked: 因为一个HOST和服务端是共享了相同场景。对于该HOST上的player而言,不可视的object是不能被删除的。NetworkBehaviour组件上有一个虚函数可供在可视性发生变化时进行重载处理。

public virtual void OnSetLocalVisibility(bool vis)

This function is invoked on all networked scripts on objects that change visibility state on the host. This allow each script to customize how it should respond, such as by disabling HUD elements or renderers. The default implementation in NetworkProximityChecker disables or enables all Renderer components on the object. 这个函数将会在HOST上所有的可见性状态发生改变的object上被调用。这也允许每一个脚本去重载此函数,自定义如何去响应这个状态的变化。
Custom Visibility
The NetworkProximityChecker is implemented using the public visibility interface of Unity Networking. Using this interface developers should be able to implement any kind of visibility rules they desire. Each NetworkIdentity keeps track of the set of players that it is visible to. These are called the “observers” of the object. NetworkProximityChecker类是通过使用Unity网络库的公有的可见性接口(public visibility interface)实现的。使用此接口的开发人员必须实现他们所有的他们想要的可见性规则。每一个NetworkIdentity对象将会负责跟踪能见到本object的各个player。这些player被称为这些object的“观察者”。
There is one function on NetworkIdentity: NetworkIdentity类中有一个函数对应处理这些东西,如下:

// call this to rebuild the set of players observing this object
public void RebuildObservers(bool initialize);

The NetworkProximityChecker calls this function at a fixed interval, so the set of visible objects for each player is updated as they move around. NetworkProximityChecker类将会在固定的时间间隔内定期调用上述的函数。所以当一个player在世界中漫游的时候,它的可见object列表将会得到更新。
On the NetworkBehaviour, there are some virtual functions for determining visibility: 在NetworkBehaviour类里面,有一些虚函数用来操作可见性。如下:
// called when a new player enters the game
public override bool OnCheckObserver(NetworkConnection newObserver);

// called when RebuildObservers is invoked 
public override bool OnRebuildObservers(HashSet<NetworkConnection> observers, bool initial);
The OnCheckObservers function is called on the server on each networked object when a new player enters the game. If it returns true, then that player is added to the object’s observers. The NetworkProximityCheck does a simple distance check in its implementation of this function. 当一个新的player进入到游戏的时候,服务器上的每一个networked object的OnCheckObservers函数将会被调用到。如果该函数返回true,这个player将被添加到networked object的观察者列表中去。在实现中,NetworkProximityCheck执行一个简单的判断以决定是否可视。
The OnRebuildObservers function is called on the server when RebuildObservers is invoked. This function expects the set of observers to be populated with the players that can see the object. The NetworkServer then handles sending ObjectHide and ObjectSpawn messages based on the differences between the old and new visibility sets. The NetworkProximityChecker uses Physics.OverlapSphere() to find the players that are within the visibility distance for this object. 当RebuildObservers被调用后,OnRebuildObservers函数也会在服务端被调用。该函数期许观察者集合中的观察者,能够被分散(be populated)在能看到object的player。NetworkServer则根据新旧两个可视object集合中的内容,对应发送ObjectHide和ObjectSpawn消息。NetworkProximityChecker类使用Physics.OverlapSphere()方法去找出能看到本object的那些player
Note that to tell is an object is a player, check if it has a valid “connectionToClient” on its NetworkIdentity. For example: 如果要判断那个可视的object是不是一个player,检查它的NetworkIdentity组件的connectionToClient是否为null即可。不为null的话,表示这个object是一个player
var hits = Physics.OverlapSphere(transform.position, visRange);
foreach (var hit in hits)
    // (if an object has a connectionToClient, it is a player)
    var uv = hit.GetComponent<NetworkIdentity>();
    if (uv != null && uv.connectionToClient != null)