当NetworkIdentity
对象在客户端上产生时,它们将使用服务器上对象的当前状态创建。这适用于对象的变换,移动状态和同步变量。因此,客户端对象在创建时始终处于最新状态。这样可以避免出现问题,例如对象在错误的初始位置产生,然后在状态更新数据包到达时弹出到正确的位置。
这听起来不错,但有一些即时问题会引发。在客户端上创建的对象如何?而且,如果对象在产生时间和另一个客户端连接之间发生变化,该怎么办?那么为新客户端生成哪个版本的对象?
产生客户端上的对象的实例化来自传递给服务器上的NetworkServer.Spawn
的对象的预制件中的客户端对象。NetworkIdentity
检查器预览面板显示NetworkIdentity
的assetID
,正是此值标识预制,以便客户端可以创建对象。为了高效工作,客户必须执行注册步骤; 他们必须调用ClientScene.RegisterPrefab
来告诉系统有关将从中创建客户端对象的资产。
编辑器中的NetworkManager
可以很方便地完成spawn
预制件的注册。NetworkManager
的“spawn信息”部分允许您注册预制而无需编写任何代码。当创建NetworkClient
时,这也可以通过代码完成。要在代码中完成它:
在这个例子中,用户会将预制资产拖到MyNetworkManager
脚本的alienPrefab
插槽中。所以当在服务器上产生一个外来对象时,将在客户端上创建相同类型的对象。这种资产注册可确保资产与场景一起加载,从而在创建资产时不会出现摊档。对于更高级的用例,如对象池或动态创建的资产,有ClientScene.RegisterSpawnHandler
,它允许为客户端生成注册回调函数。
class Tree : NetworkBehaviour
{
[SyncVar]
public int numLeaves;
}
class MySpawner : NetworkBehaviour
{
public GameObject treePrefab;
{
GameObject tree = (GameObject)Instantiate(treePrefab, transform.position, transform.rotation);
tree.GetComponent<Tree>().numLeaves = Random.Range(10,200);
NetworkServer.Spawn(tree);
}
}
为了完成这个例子,该项目将为具有树脚本和NetworkIdentity
组件的树提供预制资源。然后在场景中的MySpawner实例上,treePrefab
插槽将由树预制资源填充。此外,树预制必须注册为一个可生成的对象 - 使用NetworkManager UI
或在代码中使用ClientScene.RegisterPrefab()
。
当此代码运行时,客户端上创建的树对象将具有来自服务器的numLeaves
的正确值。
约束
对象创建流程
创建的实际操作流程是:
• NetworkIdentity组件的预制注册为spawn
• GameObject是从服务器上的预制实例化的
• 游戏代码在实例上设置初始值(请注意,此处应用的3D物理力不会立即生效)
• NetworkServer.Spawn()与实例一起被调用
• 通过调用NetworkBehaviour组件上的OnSerialize()来收集服务器上实例上SyncVars的状态
• 将类型为MsgType.ObjectSpawn的网络消息发送到包含SyncVar数据的连接客户端
• 在服务器上的实例上调用OnStartServer(),并将isServer设置为true
• 客户端收到ObjectSpawn消息并从注册的预制件创建一个新实例
• 在每个客户端上的实例上调用OnStartClient(),并将isClient设置为true
• 随着游戏进行,对SyncVar值的更改会自动同步到客户端。这一直持续到游戏结束。
• NetworkServer.Destroy()在服务器上的实例上被调用
• OnNetworkDestroy()在客户端上的实例上调用,然后实例被销毁。
网络HLAPI中的玩家对象在某些方面是特殊的。使用NetworkManager生成玩家对象的流程是:
请注意,OnStartLocalPlayer()
在OnStartClient()
之后被调用,因为它只会在玩家对象产生后所有权消息从服务器到达时发生。所以isLocalPlayer
不会在OnStartClient()
中设置。
可以生成对象并将对象的权限分配给特定的客户端。这是通过NetworkServer.SpawnWithClientAuthority
完成的,它将客户端的NetworkConnection
作为参数进行授权。
对于这些对象,拥有权限的客户端的属性hasAuthority
将为true
,并且将在具有权限的客户端上调用OnStartAuthority()
。该客户端将能够为该对象发出命令。在其他客户端(和主机上),hasAuthority
将是false
。
使用客户端权限生成的对象必须在其NetworkIdentity
中设置LocalPlayerAuthority
。
例如,为了让玩家产生并控制一个物体:
[Command]
void CmdSpawn()
{
var go = (GameObject)Instantiate(
otherPrefab,
transform.position + new Vector3(0,1,0),
Quaternion.identity);
?