注:UNet 已经被废弃, 且未来会被Unity移除。在本文中,将会使用到 NetworkManager/High Level API,import方法:Window->Package Manager->Multiplayer HLAPI。

Networking

网络功能有两种类型的用户:

  • 制作多玩家的用户。这类用户应该使用 NetworkManager/High Level API。
  • 搭建网络基础设施或 advanced 多玩家游戏(Multiplayer game) 的用户。这类用户应该使用 NetworkTransport API。

High Level API

Unity网络有一个 “high-level”脚本API(HLAPI)。使用它可以满足你开发多人游戏的大部分需求,而不用去担心 “lower level”实现细节。HLAPI允许你:

  • 使用 “Network Manager”控制游戏的网络状态。
  • 操作 “client hosted”游戏,其中 host也是一个 player client。
  • 使用通用的序列化器(serializer)序列化数据。
  • 发送和接收网络信息。
  • 从 clients发送网络命令到 servers。
  • 从 servers到 clients进行远程过程调用(remote procedure calls,RPCs)。
  • 从 servers发送联网事件到 clients。

引擎和编辑器集成(Engine and Editor integration)

Unity网络被集成到引擎和编辑器中,从而能让你使用组件和可视化工具来构建多人游戏。它提供了:

  • 用于联网物体的 NetworkIdentity组件
  • 用于联网脚本的 NetworkBehaviour。
  • 物体 transforms的可配置自动同步。
  • 脚本变量的自动同步。
  • 在 Unity场景中支持放置联网物体。
  • Network组件。

网络传输实时传输层

Unity 实时传输层(Real-Time Transport Layer)提供了:

  • 基于UDP协议的优化。
  • 多通道设计以避免 队首阻塞(head-of-line blocking)问题。
  • 每个通道都支持各种级别的 Quality of Service (QoS)。

构建多玩家项目

接下来介绍构建多玩家项目的最基础且常见的事项。项目中需要:

  • Network Manager
  • 用户接口(玩家可以找到并加入游戏)
  • 联网玩家 Prefabs
  • 多玩家感知的 脚本和 GameObjects
    对于不同的游戏,这个列表会有一些变化。比如说,在多人象棋游戏,或实施策略游戏中,你不需要代表玩家的可视化 GameObject。然而,你可能始终需要一个不可见的空 GameObject来表示玩家,并将其与脚本关联。
    后面会简要介绍上面列出的每个条目。你需要理解以下两点重要概念并在构建游戏时做出适当的选择:
  • client、server和 host的关系。
  • GameObject和动作的 authority概念。(The idea of authority over GameObjects and actions)

Network Manager

Network Manager负责管理你的多玩家游戏的网络方面的东西。在你的 Scene中同时应当只有一个激活的 Network Manager。

unity网络游戏架构设计 unity网络游戏教程_unity网络游戏架构设计


Unity内置的 Network Manager组件集中了所有用于管理多玩家游戏的特性。如果你有特殊需求,可以自己写一个专属 Network Manager,否则还是老老实实用这个组件。

用户接口

几乎每款多玩家游戏都要提供用于玩家发现,创建和加入游戏 “instances”(或“matches”)的方法。游戏的这部分通常被称为 “大厅(lobby)”,且有时还能在里面交谈。

Unity有一个最为基础的内置接口:NetworkManagerHUD。他在你构建游戏的早期极为有用,它能让你简单地构建matches并测试游戏。然而,由于它功能性和可视化设计过于基础,你应该在完成project前替换它。

unity网络游戏架构设计 unity网络游戏教程_自定义_02

联机玩家 GameObjects

大多数多玩家游戏都有玩家可以操纵的对象,比如说角色,汽车等等。一些多人游戏没有可见的“玩家对象”,取而代之地,玩家能控制许多单位或物品,实时战略游戏就是这样。有些甚至就没有特定的对象,比如说画布绘画游戏。在这些场景中,你通常需要创建一个 GameObject来表示玩家。将此 GameObject设置为 Prefab,并关联上所有控制玩家能做的操作的脚本。

如果你使用的是 Network Manager组件,将此 Prefab分配给 Player Prefab域。

unity网络游戏架构设计 unity网络游戏教程_多人游戏_03

当游戏运行时,Network Manager为每个连接到此match的玩家创建一份你的玩家 Prefab拷贝(“instance)。
然而,多人游戏编程新手很容易陷入疑惑————你需要确认你的玩家 Prefab实例上的脚本 “意识到”,玩家是在使用 host(管理游戏的计算机)还是 client(与host不同的计算机)控制此实例。

多玩家意识脚本(Multiplayer-aware Scripts)

为多玩家游戏写脚本与单玩家游戏是不同的。这是因为你需要考虑脚本运行的不同上下文。比如说,你添加在你的玩家 Prefab上的脚本应该允许该玩家实例的“owner”来操控它,而不是其他玩家。你需要考虑是否server或client有控制该脚本的权力(authority)。有时,你想让脚本同时运行在 server和 clients上,有时,你又只想让脚本运行在 server上,并且只希望 clients复制 GameObjects的移动方式。(比如说,在一个游戏中,玩家拾起可收集的 GameObject,脚本应该只在 server上运行,这样 server就能成为已收集 GameObjects数量的官方权威。
取决于你脚本的作用,你应该决定你脚本的哪些部分在哪些情形是可用的。
对于玩家 GameObject,每个人通常都有控制它们玩家实例的权限。这意味着每个 client都自己的 local authority,且 server接收 client告诉它的信息,比如说玩家正在做什么。
对于非玩家 GameObjects,server通常都有 authority,来知晓它们发送了什么(物品是否已经被收集),所有 clients接收 server发布的,关于此 GameObject的信息。

使用 Network Manager

Network Manager有以下特性:

  • 游戏状态管理(Game state management)
  • 产生管理(Spawn management)
  • 场景管理(Scene management)
  • Debug信息(Debugging information)
  • Matchmaking
  • 定制化(Customization)

开始使用 Network Manager

Network Manager是多人游戏地核心控制组件。首先先创建一个 empty GameObject,然后添加 NetworkManager组件:

unity网络游戏架构设计 unity网络游戏教程_unity网络游戏架构设计

注:你应该只有一个激活的 Network Manager。不要把 Network Manager组件放到一个联网的 GameObject(有 Network Identity组件),因为 Unity会在场景加载时 disable它们。

因为 Network Manager是基于 High-level API (HLAPI)实现的,所以它能做的你也可以使用脚本来实现。对于高级开发者,如果需要扩展 Network Manager组件的特性,可以在脚本中继承 NetworkManager类,并通过重载虚函数来自定义它的行为。

游戏状态管理

网络多人游戏有三种模式:client,专用server,或“Host”,“Host”即是client又是server。如果你正在使用 Network Manager HUD,它会自动告诉 Network Manager要以哪种模式开始,基于玩家选择的选项。如果你用的是自己的UI,那么你需要在你的代码中调用这些:

  • NetworkManager.StartClient
  • NetworkManager.StartServer
  • NetworkManager.StartHost

    网络地址和端口设置
    无论游戏以哪种模式(client,server,host)开始,网络地址和端口属性都会被使用。在client模式,游戏会试图连接特定的地址和端口号。在server或host模式,游戏会监听特定端口号的输入连接。
    在游戏开发过程中,设置一个固定的地址和端口号是很有用的。然而,你最后可能想要你的玩家能够选择他们想要连接的host。当你到达那个阶段后,Network Discovery组件能被用于广播并寻找局域网上的地址和端口号,且 Matchmaker服务能被用于为玩家寻找网络上可以连接的matches。

产生管理

使用 Network Manager来管理联网 GameObject的产生(联网实例化)。

unity网络游戏架构设计 unity网络游戏教程_Network_05

大多数游戏都有代表玩家的 Prefab,因此 Network Manager有一个 Player Prefab槽。你应该将你的玩家 Prefab分配到此槽中。当你有了一个玩家Prefab设置,玩家 GameObject能为每个玩家使用该Prefab自动自动产生。你必须为 Player Prefab关联一个 Network Identity组件。
一旦你分配了一个玩家 Prefab,你可以以host身份开始游戏并看到玩家 GameObject产生。停止游戏会摧毁玩家 GameObject。如果你以client的身份运行游戏的另一份副本,并连接到localhost,Network Manager会产生另一个玩家 GameObect。
除了玩家 Prefab,你必须在 Network Manager为你想要动态产生的物体注册 Prefabs。你可以添加 Prefabs到Inspector中的 Registered Spawnable Prefabs标签中的列表。你也可以使用代码来注册,通过ClientScene.RegisterPrefab()方法。如果每个场景中都有单独的 Network Manager,你只需要注册Prefabs到与该场景相关的Network Manager中。

自定义玩家实例

Network Manager使用 NetworkManager.OnServerAddPlayer()的实现来产生玩家 GameObject。如果你想要自定义玩家 GameObject产生的方式,你可以重载此虚函数。它的默认实现如下:

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

注:如果你要实现自定义版本的 OnServerAddPlayer,NetworkServer.AddPlayerForConnection()方法必须呗新产生的玩家 GameObject调用,这样它就能被产生,并与client连接相关联。AddPlayerForConnection产生 GameObject,所以你不需要使用 NetworkServer.Spawn()。

起始位置

要控制玩家产生的位置,你可以使用 Network Start Position组件。要使用它,先关联 Network Start Position组件到场景中的一个 GameObect,并把此 GameObject放置到你希望玩家开始的地方。你可以在场景中添加许多起始点。Network Manager会检测场景中的起始位置,并在每个玩家实例产生时,它会使用其中一个位置和方向。
Network Manager有一个 Player Spawn Method属性:

  • Random:随机产生
  • Round Robin:循环产生
    如果 Random和 Round Robin模式无法满足你,你也通过代码可以自定义起始位置是如何被选取的。你可以通过 NetworkManager.startPositions访问可用的 Network Start Position组件,并在 OnserverAddPlayer的实现中使用 GetStartPosition()方法,来找到一个起始位置。

场景管理

大多数游戏都不止一个场景。至少,除了游戏场景外,每个游戏都有标题场景和起始菜单场景。Network Manager被设计于可以自动管理游戏场景状态和场景切换。
NetworkManager Inspector中有两个槽:Offline Scene和 Online Scene。拖动场景assets到这些槽里来激活联网场景管理。
当server或host启动后,Online Scene会被加载。这会成为当前的网络场景,任何连接到该server的clients都会加载此场景。场景名字存储在 networkSceneName属性中。当网络中断后(停止server/host或client断开连接),Offline Scene会被加载。这能当多人游戏断开连接后,游戏能自动返回菜单场景。
你也可以在游戏运行时调用 NetworkManager.ServerChangeScene()来切换场景。这也可以令所有连接的clients切换场景,并更新 networkSceneName。当联网场景管理处于激活状态时,任何调用游戏状态管理函数,如NetworkManager.StartHost(), NetworkManager.StopClient()都会导致场景变化。通过设置场景并调用这些方法,你可以控制多人游戏的flow。
注意场景切换会导致前一个场景中的所有 GameObjects被摧毁。

你应该确保 NetworkManager在场景中始终存在,否则网络连接会在场景变化时断开。要做到这个,确保 Dont't Destroy On Load应该被选中。

定制化

NetworkManager类有许多虚函数,你可以在你的继承自 NetworkManager的类中自定义行为。在实现这些函数时,确保注意这些默认实现提供的功能性。比如说,在OnServerAddPlayer()中,NetworkServer.AddPlayer函数必须被调用,以激活连接中的玩家 GameObject。

使用 Network Manager HUD

你应该能够理解基础的网络概念,如host,server和client之间的关系。见 Network System Concepts

unity网络游戏架构设计 unity网络游戏教程_多人游戏_06

Network Manager HUD组件如下所示:

unity网络游戏架构设计 unity网络游戏教程_自定义_07

属性

功能

Show Runtime GUI

点击此 checkbox来在运行时显示 Network Manager HUD GUI。这能让你在快速debug时显示或隐藏它。

GUI Horizontal Offset

设置HUD的水平像素偏移,从屏幕左边缘开始测量。

GUI Vertical Offset

设置HUD的垂直像素偏移,从屏幕顶部开始测量。

Network Manager HUD提供了基础功能,让玩你游戏的人能够掌管一个联网游戏,或找到并加入到已存在的联网游戏中。

unity网络游戏架构设计 unity网络游戏教程_unity网络游戏架构设计_08

使用 HUD

Network Manager HUD有两个基础模式:LAN(局域网)和 Matchmaker模式。LAN模式用于创建并加入局域网托管的游戏。Matchmaker模式用于通过互联网创建并寻找加入到游戏中。
Network Manager HUD开始于 LAN模式。要切换到 Matchmaker模式,点击 Enable Match Maker (M)按钮。

LAN HOST

点击 LAN Host按钮来以host身份在局域网上开始游戏。这个 client既是host又是游戏内的一个玩家。它使用来自 Network Info的信息来掌管游戏。

当你点击此按钮后, HUD切换到一个简单的网络细节展示。Stop(X)按钮能让你停止掌管游戏并返回到主 LAN菜单。当你以 host身份开始游戏时,其他玩家才能连接到此游戏。点击 Stop(X)后,连接到host的所有玩家都会断开连接。

unity网络游戏架构设计 unity网络游戏教程_Network_09

LAN Client

要连接到局域网上的host,使用文本域来指定host地址。默认host地址为 “localhost”,这意味着 client会查看本机上的游戏。点击 LAN Client (C)来连接到你指定的host地址。

当你想要在处于同一个网络的多台机器上测试你的游戏时,你需要将host机器的地址填入文本框中。扮演host的机器需要告诉所有人他的IP地址。输入IP地址后点击 LAN Client来连接到host。当client连接时,HUD会展示一个 Cancel Connection Attempt按钮,你可以点击它来停止尝试连接。

unity网络游戏架构设计 unity网络游戏教程_unity网络游戏架构设计_10

如果连接成功,HUD会显示 Stop(X)按钮。点击它可以停止游戏并断开与host的连接:

unity网络游戏架构设计 unity网络游戏教程_unity网络游戏架构设计_11

LAN Server Only

点击 LAN Server Only来以 server身份开始游戏,但是不具有client身份。这类游戏称为 “专用服务器(dedicated server)”。用户不能在这个特殊实例上玩游戏。所有玩家必须以client身份连接。
局域网的专用服务器对于所有连接玩家来说会有更好的性能,因为服务器除了担任服务器之外,不需要处理本地玩家的 gameplay。
如果你想要 host一个能在互联网上玩的游戏,但是希望自己维护对服务器的控制,你可能会选择此选项。比如说,防止client作弊,因为只有 server有游戏的权限。

Enable Match Maker

点击 Enable Match Maker (M)来切换 HUD到 Matchmaker模式。如果你想要创建或连接互联网游戏上,你需要使用 Matchmaker模式。(这个模式具体参数以后再来填坑)

注:记住 Network Manager HUD 特性是开发时的临时帮助。它能让你快速运行多人游戏,但是在你准备好后,你应该把它替换成自己的UI控件。