NetworkIdentity对象在客户端上产生时,它们将使用服务器上对象的当前状态创建。这适用于对象的变换,移动状态和同步变量。因此,客户端对象在创建时始终处于最新状态。这样可以避免出现问题,例如对象在错误的初始位置产生,然后在状态更新数据包到达时弹出到正确的位置。

这听起来不错,但有一些即时问题会引发。在客户端上创建的对象如何?而且,如果对象在产生时间和另一个客户端连接之间发生变化,该怎么办?那么为新客户端生成哪个版本的对象?

产生客户端上的对象的实例化来自传递给服务器上的NetworkServer.Spawn的对象的预制件中的客户端对象。NetworkIdentity检查器预览面板显示NetworkIdentityassetID,正是此值标识预制,以便客户端可以创建对象。为了高效工作,客户必须执行注册步骤; 他们必须调用ClientScene.RegisterPrefab来告诉系统有关将从中创建客户端对象的资产。

编辑器中的NetworkManager可以很方便地完成spawn预制件的注册。NetworkManager的“spawn信息”部分允许您注册预制而无需编写任何代码。当创建NetworkClient时,这也可以通过代码完成。要在代码中完成它:

在这个例子中,用户会将预制资产拖到MyNetworkManager脚本的alienPrefab插槽中。所以当在服务器上产生一个外来对象时,将在客户端上创建相同类型的对象。这种资产注册可确保资产与场景一起加载,从而在创建资产时不会出现摊档。对于更高级的用例,如对象池或动态创建的资产,有ClientScene.RegisterSpawnHandler,它允许为客户端生成注册回调函数。

  1. class Tree : NetworkBehaviour
  2. {
  3. [SyncVar]
  4. public int numLeaves;
  5. }
  6. class MySpawner : NetworkBehaviour
  7. {
  8. public GameObject treePrefab;
  9. {
  10. GameObject tree = (GameObject)Instantiate(treePrefab, transform.position, transform.rotation);
  11. tree.GetComponent<Tree>().numLeaves = Random.Range(10,200);
  12. NetworkServer.Spawn(tree);
  13. }
  14. }

为了完成这个例子,该项目将为具有树脚本和NetworkIdentity组件的树提供预制资源。然后在场景中的MySpawner实例上,treePrefab插槽将由树预制资源填充。此外,树预制必须注册为一个可生成的对象 - 使用NetworkManager UI或在代码中使用ClientScene.RegisterPrefab()

当此代码运行时,客户端上创建的树对象将具有来自服务器的numLeaves的正确值。

约束

对象创建流程

创建的实际操作流程是:

  1. NetworkIdentity组件的预制注册为spawn
  2. GameObject是从服务器上的预制实例化的
  3. 游戏代码在实例上设置初始值(请注意,此处应用的3D物理力不会立即生效)
  4. NetworkServer.Spawn()与实例一起被调用
  5. 通过调用NetworkBehaviour组件上的OnSerialize()来收集服务器上实例上SyncVars的状态
  6. 将类型为MsgType.ObjectSpawn的网络消息发送到包含SyncVar数据的连接客户端
  7. 在服务器上的实例上调用OnStartServer(),并将isServer设置为true
  8. 客户端收到ObjectSpawn消息并从注册的预制件创建一个新实例
  9. 在每个客户端上的实例上调用OnStartClient(),并将isClient设置为true
  10. 随着游戏进行,对SyncVar值的更改会自动同步到客户端。这一直持续到游戏结束。
  11. NetworkServer.Destroy()在服务器上的实例上被调用
  12. OnNetworkDestroy()在客户端上的实例上调用,然后实例被销毁。

网络HLAPI中的玩家对象在某些方面是特殊的。使用NetworkManager生成玩家对象的流程是:

请注意,OnStartLocalPlayer()OnStartClient()之后被调用,因为它只会在玩家对象产生后所有权消息从服务器到达时发生。所以isLocalPlayer不会在OnStartClient()中设置。

可以生成对象并将对象的权限分配给特定的客户端。这是通过NetworkServer.SpawnWithClientAuthority完成的,它将客户端的NetworkConnection作为参数进行授权。

对于这些对象,拥有权限的客户端的属性hasAuthority将为true,并且将在具有权限的客户端上调用OnStartAuthority()。该客户端将能够为该对象发出命令。在其他客户端(和主机上),hasAuthority将是false

使用客户端权限生成的对象必须在其NetworkIdentity中设置LocalPlayerAuthority

例如,为了让玩家产生并控制一个物体:

  1. [Command]
  2. void CmdSpawn()
  3. {
  4. var go = (GameObject)Instantiate(
  5. otherPrefab,
  6. transform.position + new Vector3(0,1,0),
  7. Quaternion.identity);

?