Unity多人游戏和网络功能(二) 使用网络管理类

来源:互联网 发布:lolita洋装好的淘宝店 编辑:程序博客网 时间:2024/06/16 22:18

[本文翻译自Unity 5.2的官方文档]

NetworkManager是一个可以管理多玩家游戏的网络状态的组件。实际上,它是完全用HLAPI实现的,因此开发者可以使用其他的方式实现他的所有功能。然而,NetworkManager把很多有用的功能集成在了一起,并且使创建,运行和调试一个多玩家游戏尽可能的简单。

使用NetworkManager可以不写一行代码,它在编辑器上为所有功能都提供了可以配置的控制选项。NetworkManagerHUD提供了一个简单的,默认的运行时人机交互界面,允许网络游戏能被玩家所控制。对于高级的用户,开发者可以从NetworkManager派生一个新类,然后重写他的所有虚函数来定制他的行为。

NetworkManager提供的功能包括:

  • 游戏状态管理

  • 游戏物体派生(Spawning)管理

  • 场景管理

  • 调试信息

  • 比赛的组织(Matchmaking)

  • 个性化定制

开始使用NetworkManager

NetworkManager可以作为多玩家游戏的核心控制组件。首先在开始场景中创建一个空的物体,或者选择一个方便的管理物体。然后添加NetworkManager组件(Network/NetworkManager)。新增加的NetworkManager组件像下面这个样子:

编辑器中的这个视图允许你配置和控制很多网络相关的配置。

NetworkManagerHUD是另外一个和NetworkManager一起工作的组件。他在游戏运行时可以提供一个简单的用户界面用来控制网络的状态。这对于开始一个网络工程是有用的。但是不建议最为游戏最终的UI。NetworkManagerHUD如下图所示:

真正的游戏应该拥有一个更好的控制游戏状态的界面,可以让玩家选择玩哪种游戏。但是在开始的时候,我们可以用他方便的开始游戏的开发。

游戏状态管理

一个多玩家网络游戏可以有三种运行模式:作为客户端,作为专用的服务器,或者作为同时运行客户端和服务器的伺服器。网络功能被设计成在这三种模式下可以使用相同的代码和资源。开发单机版游戏和多人版游戏应该是相同的事情。

NetworkManager提供了所有三种模式下使用的方法。NetworkManager.StartClient(), NetworkManager.StartServer() 和NetworkManager.StartHost() 随时可以在脚本中调用,所以他们可以被键盘输入触发调用或从用户界面上触发。默认的运行时控制器也可以调用相同的函数。同时,NetworkManagerHUD界面在运行时也提供触发这些函数的开关。

不管用哪个方法来改变游戏状态,网络地址和端口都应该被正确的配置。当服务器或伺服器启动的时候,端口号将作为本地的监听端口。当客户端被启动的时候,网络地址将作为连接到的地址,网络端口是连接到的端口号。

派生物体(Spawning)管理

NetworkManager可以管理从预设体中派生出来的联网物体。大多数游戏都用一个预设体作为主要的玩家物体,所以NetworkManager里有一个槽位可以把这个玩家预设体拖放进去。当玩家预设体设置了之后,当有新玩家加入的时候,这个玩家物体将会被自动创建。在伺服器上,他将作为本地玩家,在远程客户端上将作为远程玩家。要注意的是,拖放进来的预设体必须要带有网络标识组件(NetworkIdentity)。

除了玩家物体,需要动态创建的其他物体必须首先在客户端场景中注册。这可以通过ClientScene.RegisterPrefab()函数完成,或者将预设体拖放到NetworkManager的派生列表中,这样NetworkManager就可以自动的创建他们。NetworkManager的派生配置视图如下:

当玩家预设体配置完之后,以伺服器模式运行,你就应该能看到玩家物体被派生出来了。停止游戏就可以让玩家物体被销毁掉。运行游戏的另外一份拷贝,并且以客户端的身份连接进来,应该就能看到另外一个玩家物体被创建了,停止掉客户端会使这个客户端物体被销毁掉。

玩家物体的创建是通过NetworkManager的默认实现(NetworkManager.OnServerAddPlayer)完成的。如果你希望定制玩家物体被创建的方式,可以重写这个虚函数。默认的实现如下所示:

public virtual void OnServerAddPlayer(NetworkConnection conn,
short playerControllerId)
{
var player = (GameObject)GameObject.Instantiate(playerPrefab,
playerSpawnPos, Quaternion.identity);
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
}
要注意的是,在创建新的玩家物体的时候,函数NetworkManager.AddPlayerForConnected()必须被调用,以让他能和特定的客户端连接关联起来。这将派生出这个物体,所以不一定非得为玩家物体调用函数NetworkServer.Spawn()。

开始位置

要控制玩家物体的派生位置,可以使用NetworkStartPosition组件。NetworkManager会在场景中寻找具有NetworkStartPosition的物体,如果找到了,就在其中的一个所标识的位置上派生玩家物体,并相应的调整物体的转向。用户可以通过NetworkManager.startPositions变量访问到开始位置的列表,或者也可以在处理函数OnServerAddPlayer()中使用帮助函数NetworkManager.GetStartPosition()确定合适的开始位置。

场景管理

大多数游戏都拥有不止一个场景。通常最少有一个带标题和开始按钮的场景,加上实际玩游戏的场景。NetworkManager能自动管理多玩家游戏内的场景状态和场景切换。在NetworkManager的检视面板中有两个槽位,离线场景和上线场景。把场景物体拖放到相应的槽位上就能激活场景的管理功能。

当一个服务器或伺服器启动之后,上线场景将被加载进来,并成为当前的联网场景。所有连接到服务器的客户端也会被指引来加载这个场景。场景的名字被存储在networkSceneName属性中。

当网络断开的时候(服务器或伺服器关闭,或者客户端断开连接),离线场景将被加载。游戏可以在退出多人游戏状态的时候自动返回主菜单场景。

你也可以在游戏进行的时候调用NetworkManager.ServerChangeScene()函数来切换场景,这会使所有连接的客户端也切换场景,并修改networkSceneName属性。

当场景管理正在工作的时候,任何修改游戏状态的函数调用(如NetworkManager.StartHost()或StopClient())都会引起场景的切换。这会应用到运行时控制UI上。所以通过设计场景并调用这些函数的方式,可以很容易的控制多玩家游戏的流程。

要注意的是,场景切换会导致场景中的所有物体都被销毁,这也包括NetworkManager本身。所以如果你希望NetworkManager在场景切换的时候被保存下来,需要选中NetworkManager上的”Don’t Destroy On Load”选项。一般情况下,这是最合适的配置。但是,也有可能需要给每个场景带单独的NetworkManager,以派生不同的预设物体,或者进行不同的场景切换控制。

调试信息

NetworkManagerHUD检视面板可以在运行时显示额外的网络状态信息,包括:

  • 网络连接状态

  • 活动的服务器上带有网络标识的对象

  • 活动的客户端上带有网络标识的对象

  • 连接的客户端

同时,注册的客户端消息处理函数也可以在预览窗口中显示:

比赛安排

NetworkManager运行时UI和检视窗口上可以配置比赛安排服务器。可以使用函数NetworkManager.StartMatchmaker()开启比赛安排功能,然后将一个NetworkMatch物体赋值给NetworkManager.matchmaker属性。一旦激活,默认的UI将使用NetworkManager的回调函数进行简单的比赛安排。

在NetworkManager类里面有虚函数,可以用来在派生类中定制比赛安排的处理。

个性化定制

NetworkManager里面提供了很多虚函数,可以在派生类中重写来定制处理过程。当实现这些函数的时候,需要注意默认的处理函数的实现。如在OnServerAddPlayer()函数中,函数NetworkServer.AddPlayer()必须被调用,以激活连接上的玩家物体。

在服务器和伺服器上调用的函数有:

// 客户端连接时被调用
public virtual voidOnServerConnect(NetworkConnection conn);

// 客户端断开连接是被调用
public virtual void OnServerDisconnect(NetworkConnectionconn)
{
NetworkServer.DestroyPlayersForConnection(conn);
}

// 客户端准备好的时候调用
public virtual voidOnServerReady(NetworkConnection conn)
{
NetworkServer.SetClientReady(conn);
}

// 当有一个新的客户端加入的时候调用
public virtual voidOnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
var player =(GameObject)GameObject.Instantiate(playerPrefab, playerSpawnPos,Quaternion.identity);
NetworkServer.AddPlayerForConnection(conn,player, playerControllerId);
}

// 一个客户端的玩家物体被移除的时候调用
public virtual voidOnServerRemovePlayer(NetworkConnection conn, short playerControllerId)
{
PlayerController player;
if (conn.GetPlayer(playerControllerId, outplayer))
{
if (player.NetworkIdentity != null&& player.NetworkIdentity.gameObject != null)
NetworkServer.Destroy(player.NetworkIdentity.gameObject);
}
}

// 有网络错误发生的时候调用
public virtual void OnServerError(NetworkConnection conn, int errorCode);

在客户端上被调用函数有:

// 客户端连接到服务器的时候调用
public virtual voidOnClientConnect(NetworkConnection conn)
{
ClientScene.Ready(conn);
ClientScene.AddPlayer(0);
}

// 客户端从服务器断开连接的时候调用
public virtual voidOnClientDisconnect(NetworkConnection conn)
{
StopClient();
}

// 有网络错误发生的时候调用
public virtual voidOnClientError(NetworkConnection conn, int errorCode);

// 被服务器告知还没准备好的时候调用
public virtual voidOnClientNotReady(NetworkConnection conn);

在比赛安排中的函数有:

// 有比赛被创建的时候调用
public virtual voidOnMatchCreate(CreateMatchResponse matchInfo)

// 接收到比赛列表的时候调用
public virtual voidOnMatchList(ListMatchResponse matchList)

// 加入比赛的时候调用
public voidOnMatchJoined(JoinMatchResponse matchInfo)

转载自:

http://www.aichengxu.com/view/2405127


欢迎关注我的微信个人订阅号
这里写图片描述
每天多学一点0.0

0 0
原创粉丝点击