使用网络管理器

网络管理器是用于管理多玩家游戏的网络状态的组件。它实际上完全是使用高级API(HLAPI)实现的,所以它的所有功能也可以通过脚本提供给开发人员; 然而,网络管理器组件将许多有用的功能包括在一个地方,并且使得多人游戏的创建,运行和调试尽可能简单。

NetworkManager可以完全不使用脚本。它具有编辑器中的Inspector控件,允许配置其所有功能。NetworkManagerHUD在运行时提供一个简单的默认用户界面,允许用户控制网络游戏。对于高级用户,开发人员可以通过继承NetworkManager,覆盖提供的任何虚函数回调来定制其行为。

  1. 网络管理器功能包括:
  2. 游戏状态管理
  3. 生成管理
  4. 场景管理
  5. 调试信息
  6. MatchMaking
  7. 定制

网络管理器入门

网络管理器可以用作多人游戏的核心控制组件。要开始,请在开始的场景中创建一个空的GameObject(或者选择一个可以容纳Network Manager组件的方便的GameObject)。然后从Network / NetworkManager菜单项中添加NetworkManager组件。新添加的NetworkManager组件应该如下所示:

 6.23 使用网络管理器  - 图1

编辑器中的网络管理器检测器允许您配置和控制与网络相关的许多事情。

NetworkManagerHUD是与网络管理器配合使用的另一个组件。当游戏运行以控制网络状态时,它为您提供了一个简单的用户界面。这对于开始使用网络项目很有好处,但并不打算用作游戏的最终用户界面。NetworkManagerHUD看起来像这样:

 6.23 使用网络管理器  - 图2

 6.23 使用网络管理器  - 图3

完成的游戏仍然需要适当的用户界面来控制游戏状态并允许玩家选择要玩的游戏类型 - NetworkManagerHUD仅供开发使用。

游戏状态管理

网络多人游戏可以以三种模式运行 - 作为客户端,作为专用服务器,或作为同时是客户端和服务器的“主机”。网络旨在使所有这些情况下的相同游戏代码和资产都能正常工作。为单人游戏版本和多人游戏版本开发应该是同样的事情。

  1. NetworkManager具有用于输入以下各种模式的功能:
  2. NetworkManager.StartClient()
  3. NetworkManager.StartServer()
  4. NetworkManager.StartHost()

这些都可用于脚本代码,因此可以从键盘输入处理程序或自定义用户界面调用它们。可以选择显示的默认运行时控件也可以调用这些相同的功能。NetworkMangerHUD Inspector中还有一些按钮,可在编辑器的播放模式下使用,它们可以调用相同的功能:

 6.23 使用网络管理器  - 图4

当服务器或主机启动时,networkPort成为监听端口。当客户端启动时,networkAddress是要连接的地址,并且networkPort是要连接的端口。

生成管理

网络管理器可用于管理Prefabs中联网的GameObjects的生成。大多数游戏都有一个Prefab作为主要玩家GameObject,因此NetworkManager有一个插槽来拖放玩家Prefab。当玩家Prefab被设置时,游戏中的每个用户都会从该Prefab中自动产生玩家游戏对象。这适用于托管服务器上的本地玩家以及远程客户端上的远程玩家。请注意,玩家Prefab必须具有NetworkIdentity组件。

除了玩家Prefab之外,动态生成的其他GameObjects的预制必须在客户端场景中注册。这可以通过ClientScene.RegisterPrefab()功能完成,也可以由NetworkManager自动完成。将预制添加到生成清单会自动注册它们。网络管理器检查器的产生配置部分如下所示:

 6.23 使用网络管理器  - 图5

一旦玩家Prefab被设置,你应该能够以主机的身份开始游戏并看到玩家GameObject的产生。停止游戏应该会摧毁玩家GameObject。运行另一个游戏副本并作为客户端连接到localhost应该让另一个玩家GameObject出现,并停止该客户端应该使该客户端的玩家GameObject被销毁。

玩家GameObject由默认的实现产生NetworkManager.OnServerAddPlayer。如果您想自定义玩家GameObjects的创建方式,则可以覆盖该虚拟功能。此代码显示了默认实现的一个示例:

  1. public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
  2. {
  3. var player = (GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos, Quaternion.identity);
  4. NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
  5. }

请注意,NetworkServer.AddPlayerForConnection()必须为新创建的玩家GameObject调用该函数,以便生成该函数并与客户端的连接相关联。这产生了GameObject,所以NetworkServer.Spawn不需要为玩家GameObject调用。

NetworkStartPosition

要控制玩家产生的位置,可以使用NetworkStartPosition组件。NetworkManager在一个场景中查找附有NetworkStartPosition组件的GameObjects,如果它找到了它,则会在其中一个位置和方向上产生该玩家。使用自定义代码通过列表访问可用的NetworkStartPosition组件NetworkManager.startPositions,并使用网络管理器上的辅助功能GetStartPosition()来实现OnServerAddPlayer查找起始位置。

要使用开始位置,请将网络起始位置组件附加到场景中的GameObject。场景中可以有多个起始位置。然后网络管理器将GameObject的位置和方向注册为开始位置。当客户加入游戏并添加了玩家时,玩家GameObject将在其中一个起始位置创建,具有相同的位置和方向。

NetworkManager有一个属性PlayerSpawnMethod,允许配置如何选择startPositions

  1. 选择随机在随机选择的startPosition选项中产生玩家。
  2. 选择循环来循环startPosition选择集合列表中的选项。

生成区域的代码如下所示:

  1. if (m_PlayerSpawnMethod == PlayerSpawnMethod.Random && s_StartPositions.Count > 0)
  2. {
  3. // try to spawn at a random start location
  4. int index = Random.Range(0, s_StartPositions.Count);
  5. return s_StartPositions[index];
  6. }
  7. if (m_PlayerSpawnMethod == PlayerSpawnMethod.RoundRobin && s_StartPositions.Count > 0)
  8. {
  9. if (s_StartPositionIndex >= s_StartPositions.Count)
  10. {
  11. s_StartPositionIndex = 0;
  12. }
  13. Transform startPos = s_StartPositions[s_StartPositionIndex];
  14. s_StartPositionIndex += 1;
  15. return startPos;
  16. }

场景管理

大多数游戏都有不止一个场景。除了实际玩游戏的场景之外,通常还有标题屏幕或开始菜单场景。网络管理器设置为以适用于多人游戏的方式自动管理场景状态和场景转换。NetworkManager检查器上有两个插槽:offlineSceneonlineScene。将场景GameObjects拖入这些插槽可激活联网场景管理。

当服务器或主机启动时,联机场景被加载。这然后变成当前的网络场景。指示连接到该服务器的任何客户端也会加载该场景。此场景的名称存储在networkSceneName属性中。

当网络停止时,通过停止服务器或主机或客户端断开连接,加载离线场景。这允许游戏在与多人游戏断开连接时自动返回到菜单场景。

您也可以在游戏处于活动状态时通过调用更改场景NetworkManager.ServerChangeScene()。这使得所有当前连接的客户端也更改场景,并进行更新,networkSceneName以便新客户端也加载新场景。

虽然网络现场管理是有效的,任何调用游戏状态管理功能,NetworkManager.StartHost()NetworkManager.StopClient()可能导致场景变化。这适用于运行时控制UI。通过设置场景并调用这些功能,很容易控制多人游戏的流程。

请注意,场景变化会导致前一场景中的所有GameObjects被销毁。网络管理器通常需要在场景之间保留(否则网络连接会在场景更改时断开),因此请确保在检查器中选中了“不装载时销毁”框。也可以在每个场景中使用不同设置的网络管理器,如果您希望控制增量预制加载或不同场景转换,这可能会有所帮助。

调试信息

NetworkManagerHUD检查器窗口显示有关运行时网络状态的附加信息。这包括:

  1. 网络连接
  2. 活动NetworkIdentity服务器对象
  3. 活动NetworkIdentity客户端对象
  4. 客户同行

注册的客户端消息处理程序显示在“预览”窗口中。

 6.23 使用网络管理器  - 图6

MatchMaking

Network Manager Runtime UINetwork Manager Inspector UI允许与匹配器服务进行交互。该函数NetworkManager.StartMatchmaker()启用匹配,并NetworkManager.matchmakerNetworkMatch对象填充属性。一旦这是活动的,默认UI使用它和回调函数NetworkManager来让你执行简单的匹配。

NetworkManager派生类可以使用定制响应Matchmaker回调的行为的虚函数。

 6.23 使用网络管理器  - 图7

定制

NetworkManager派生类可以使用自定义行为的虚函数。在实现这些功能时,请务必注意默认实现提供的功能。例如,在OnServerAddPlayer()NetworkServer.AddPlayer中必须调用该函数来激活连接的玩家GameObject。

在服务器/主机上调用的函数:

  1. // called when a client connects
  2. public virtual void OnServerConnect(NetworkConnection conn);
  3. // called when a client disconnects
  4. public virtual void OnServerDisconnect(NetworkConnection conn)
  5. {
  6. NetworkServer.DestroyPlayersForConnection(conn);
  7. }
  8. // called when a client is ready
  9. public virtual void OnServerReady(NetworkConnection conn)
  10. {
  11. NetworkServer.SetClientReady(conn);
  12. }
  13. // called when a new player is added for a client
  14. public virtual void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
  15. {
  16. var player = (GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos, Quaternion.identity);
  17. NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
  18. }
  19. // called when a player is removed for a client
  20. public virtual void OnServerRemovePlayer(NetworkConnection conn, short playerControllerId)
  21. {
  22. PlayerController player;
  23. if (conn.GetPlayer(playerControllerId, out player))
  24. {
  25. if (player.NetworkIdentity != null && player.NetworkIdentity.gameObject != null)
  26. NetworkServer.Destroy(player.NetworkIdentity.gameObject);
  27. }
  28. }
  29. // called when a network error occurs
  30. public virtual void OnServerError(NetworkConnection conn, int errorCode);

在客户端上调用的函数:

  1. // called when connected to a server
  2. public virtual void OnClientConnect(NetworkConnection conn)
  3. {
  4. ClientScene.Ready(conn);
  5. ClientScene.AddPlayer(0);
  6. }
  7. // called when disconnected from a server
  8. public virtual void OnClientDisconnect(NetworkConnection conn)
  9. {
  10. StopClient();
  11. }
  12. // called when a network error occurs
  13. public virtual void OnClientError(NetworkConnection conn, int errorCode);
  14. // called when told to be not-ready by a server
  15. public virtual void OnClientNotReady(NetworkConnection conn);

Matchmaker调用的函数:

  1. // called when a match is created
  2. public virtual void OnMatchCreate(CreateMatchResponse matchInfo)
  3. // called when a list of matches is received
  4. public virtual void OnMatchList(ListMatchResponse matchList)
  5. // called when a match is joined
  6. public void OnMatchJoined(JoinMatchResponse matchInfo)

?