文章目录
- 官方文档
- 文章版本
- 关于Netcode for GameObject
- 发行说明
- API参考
- 开始使用(Get started)
- 网络组件(Networking Components)
- 网络管理器(NetworkManager)
- 网络变换(NetworkTransform)
- 每周更新
官方文档
首先亮出文档,可以直接去看官方文档: 官方文档
翻译如有错误,恳请指正。
命令行运行教程链接: 教程
目前正在翻译的部分:NetWorking Components > NetworkTransform
文章版本
本文章基于Netcode for GameObject 1.5.2、2.0.0exp、2.2.0版本进行翻译,以下是具体部分对应的版本:
- 关于Netcode for GameObject:1.5.2;
- 发行说明:1.5.2;
- API参考:1.5.2;
- 开始使用(Get started):2.2.0之前的版本;
- 网络组件(Networking Components)> 网络管理器(NetworkManager):2.2.0之前的版本;
- Networking components > NetworkTransform > Introduction :2.0.0exp
- Networking components > NetworkTransform > Adding the component:2.2.0
关于Netcode for GameObject
Netcode for GameObjects(NGO)是一个为Unity构建的高级网络库,用于抽象化网络逻辑。它使你能够将游戏对象和世界数据通过网络会话发送给多个玩家。通过使用NGO,你可以专注于构建游戏,而不必关注低级协议和网络框架。
要了解更多关于Netcode for GameObjects的功能和能力,请查看下面的内容:
开始入门
安装Unity Netcode
从UNet迁移到Netcode
升级到Unity Netcode Package
开始项目
教程和示例
Boss Room(首领房间)
Bite Size Samples(小示例)
Dilmer’s Tutorials(Dilmer的教程)
核心概念
调试
术语和常见问题解答
开始之前
Netcode支持以下版本:
- Unity 2021.3及更高版本
- Mono和IL2CPP脚本后端
Netcode支持以下平台:
- Windows、macOS和Linux
- iOS和Android
- 运行在Windows、Android和iOS操作系统上的XR平台
- 大多数封闭平台,如游戏主机。关于特定封闭平台的更多信息,请联系我们。这些内容通常受到保密协议的保护。
- 当在游戏主机(如PlayStation、Xbox或任天堂Switch)上运行时,你在测试和正式发布游戏前应了解特定的Netcode政策。请参考游戏主机的内部文档以获取更多信息。此类内容通常受到保密协议的保护。
最后更新日期:2023年8月2日
发行说明
Netcode for GameObjects
Netcode for GameObjects的更新日志
以下内容跟踪了下一个版本的Unity Netcode的功能、更新、错误修复和重构。因为Netcode for GameObjects是开源的,你可以在com.unity.netcode.gameobjects的GitHub存储库中访问完整的发行说明和变更日志。
发布 |日期 | 更新日志
1.5.2 2023-07-24 1.5.2
1.5.1 2023-06-09 1.5.1
1.4.0 2023-04-10 1.4.0
1.3.1 2023-03-27 1.3.1
1.2.0 2022-11-21 1.2.0
1.1.0 2022-10-18 1.1.0
1.0.2 2022-09-08 1.0.2
1.0.1 2022-08-23 1.0.1
1.0.0 2022-06-27 1.0.0
最后更新日期:2023年8月14日
Boss Room(首领房间)
Boss Room更新日志
以下内容跟踪了Boss Room示例项目的下一个版本的功能、更新、错误修复和重构。由于Boss Room是开源的,你可以在com.unity.multiplayer.samples.coop的GitHub存储库中访问完整的发行说明和变更日志。
发布 | 日期 | 更新日志
2.1.0 2023-04-27 2.1.0
2.0.4 2022-12-14 2.0.4
2.0.3 2022-12-09 2.0.3
全部内容在此,我就不一个一个复制了,太累了
最后更新日期:2023年6月13日
Bitesize
多人Bitesize示例
以下内容跟踪了多人Bitesize示例项目的下一个版本的功能、更新、错误修复和重构。由于多人Bitesize是开源的,你可以在com.unity.multiplayer.samples.bitesize的GitHub存储库中访问完整的发行说明和变更日志。
发布 | 日期 | 更新日志
1.1.0 2022-12-13 1.1.0
最后更新日期:2023年8月14日
API参考
开始使用(Get started)
已翻译,对应CSDN内部文章链接,可以直接点击:
开始使用(Get started)
网络组件(Networking Components)
网络管理器(NetworkManager)
NetworkManager
是一个必需的 Netcode for GameObjects(Netcode)组件,它包含了你项目中所有与网络代码相关的设置。将其视为你的网络代码启用项目的“中央网络代码中心”。
NetworkManager在Inspector面板的属性(NetworkManager Inspector Properties)
- LogLevel(日志级别):设置网络日志级别
- PlayerPrefab:当指定预制体时,该预制体将作为玩家对象实例化,并分配给新连接和授权的客户端。
- NetworkPrefabs:在这里注册你的网络预设。你还可以为每个已注册的网络预设创建一个单独的网络预设覆盖。
- Protocol Version(协议版本):设置该值以帮助区分构建版本,当前最新版本具有可能导致旧版本连接问题的新资源时,这里进行区分。
- Network Transport(网络传输):设置你的网络特定设置和传输类型的位置。该字段接受任何INetworkTransport的实现。不过,除非你有特殊的传输需求,否则UnityTransport是与Netcode for GameObjects一起使用的推荐传输方式。
- Tick Rate:此值控制网络tick更新速率。
- Ensure Network Variable Length Safety(确保网络变量长度安全):(增加CPU处理和带宽)当勾选此属性时,Netcode for GameObjects将防止用户代码写入超出NetworkVariable边界的部分。
- Connection Approval(连接批准):当勾选此项并分配
NetworkManager.ConnectionApprovalCallback
时,启用连接批准。 - Client Connection Buffer Timeout(客户端连接缓冲超时):该值设置连接客户端完成连接批准过程所需的时间。如果超过指定的时间,连接的客户端将被断开。
- Force Same Prefabs(强制相同预设):勾选后,将始终验证连接的客户端是否具有与服务器相同的已注册网络预设。如果未勾选,Netcode for GameObjects将忽略任何差异。
- Recycle Network Ids(回收网络Ids):勾选后,在指定的时间段后将重新使用先前分配的
NetworkObject.NetworkObjectIds
。 - Network Id Recycle Delay(网络Id回收延迟):之前分配但当前未分配的标识符(identifier)可供使用所需的时间。
- Enable Scene Management(启用场景管理):勾选后,Netcode for GameObjects将处理场景管理和客户端同步。如果未勾选,用户将需要创建自己的场景管理脚本并处理客户端同步。
- Load Scene Time Out(加载场景超时):当勾选了启用场景管理后,该选项指定
NetworkSceneManager
在加载场景异步进行时等待的时间段,超过这个时间段后NetworkSceneManager
将认为加载/卸载场景事件失败/超时。
网络管理器
子系统(NetworkManager
Sub-Systems)
NetworkManager
还包含其他与网络代码相关的管理系统的引用:
注意
所有NetworkManager
子系统在NetworkManager
启动后实例化(即,NetworkManager.IsListening == true
)。一个好的一般"经验法则"是在启动NetworkManager
之前不要尝试访问下面的子系统,否则它们尚未初始化。
NetworkManager.PrefabHandler: 提供了访问用于网络对象池和覆盖网络预设的NetworkPrefabHandler的功能。
NetworkManager.SceneManager: 当启用场景管理时,用于加载和卸载场景、注册场景事件和其他与场景管理相关的操作。
NetworkManager.SpawnManager: 处理与网络对象生成相关的功能。
NetworkManager.NetworkTimeSystem: 一个可以用来处理客户端和服务器之间延迟问题的同步时间。
NetworkManager.NetworkTickSystem: 使用此系统来调整更新NetworkVariables的频率。
NetworkManager.CustomMessagingManager: 使用此系统创建和发送自定义消息。
启动服务器、主机或客户端(Starting a Server, Host, or Client)
为了执行任何涉及发送消息的网络代码相关操作,首先你必须启动一个服务器并监听至少一个已连接的客户端(当作为主机运行时,服务器可以向自己发送RPCs)。为了实现这一目标,你首先要将NetworkManager
作为服务器、主机或客户端启动。你可以调用三个NetworkManager
的方法来实现:
NetworkManager.Singleton.StartServer(); // 将NetworkManager作为仅服务器启动(即无本地客户端)。
NetworkManager.Singleton.StartHost(); // 将NetworkManager作为既是服务器又是客户端启动(即具有本地客户端)。
NetworkManager.Singleton.StartClient(); // 将NetworkManager作为仅客户端启动。
危险
不要在NetworkBehaviour的Awake方法中启动NetworkManager,因为这可能会导致不良结果,取决于项目的设置!
注意
当作为服务器启动或加入已经启动的会话时,NetworkManager
可以生成一个属于客户端的"玩家对象(Player Object)"。
有关玩家预制件的更多信息,请参阅:
连接(Connecting)
当启动客户端时,NetworkManager
使用Transport
组件中提供的IP和端口进行连接。虽然你可以在编辑器中设置IP地址,但很多时候你可能希望能够在运行时设置IP地址和端口。
下面的示例使用Unity Transport展示了几种通过NetworkManager.Singleton
以编程方式配置项目网络设置来访问UnityTransport
组件的几种方法:
如果你只是设置IP地址和端口号,你可以使用UnityTransport.SetConnectionData
方法:
NetworkManager.Singleton.GetComponent<UnityTransport>().SetConnectionData(
"127.0.0.1", // IP地址是一个字符串
(ushort)12345 // 端口号是一个unsigned short类型
);
如果你在同一代码块中配置服务器和客户端,并且希望将服务器配置为监听分配给它的所有IP地址,那么你也可以向SetConnectionData方法传递一个“监听地址”的值为“0.0.0.0”,像这样:
NetworkManager.Singleton.GetComponent<UnityTransport>().SetConnectionData(
"127.0.0.1", // IP地址是一个字符串
(ushort)12345, // 端口号是一个unsigned short类型
"0.0.0.0" // 服务器监听地址是一个字符串。
);
注意
使用IP地址0.0.0.0作为服务器监听地址将使服务器或主机监听分配给本地系统的所有IP地址。如果你在同一系统上测试客户端实例以及一个或多个连接到本地局域网上的其他系统的客户端实例,这将特别有帮助。另一个场景是在开发和调试过程中,你可能有时会在同一系统上测试本地客户端实例,有时会测试在外部系统上运行的客户端实例。
在运行时,可以通过NetworkManager.Singleton.GetComponent<UnityTransport>().ConnectionData
访问当前连接数据。这将返回一个ConnectionAddressData
结构,保存着这些信息。强烈建议你使用SetConnectionData
方法来更新这些信息。
然而,如果你正在使用Unity Relay来处理连接,请不要使用SetConnectionData
。主机应调用SetHostRelayData
,而客户端应调用SetClientRelayData
。通过输入IP/端口号(通过SetConnectionData
)试图加入通过Relay托管的游戏将不起作用。
关于Netcode for GameObjects Transports的更多信息
断开连接和关闭(Disconnecting and Shutting Down)
断开连接相当简单,但是一旦NetworkManager
停止,你将无法使用/访问任何子系统(即NetworkSceneManager
),因为它们将不再可用。对于客户端、主机或服务器模式,你只需要调用NetworkManager.Shutdown
方法,它将在关闭时断开连接。
信息
当没有网络会话处于活动状态且NetworkManager
已关闭时,你将需要使用UnityEngine.SceneManagement
加载任何与网络会话无关的场景。
public void Disconnect()
{
NetworkManager.Singleton.Shutdown();
// 在这个阶段,我们必须使用UnityEngine的SceneManager切换回到主菜单
UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu");
}
断开客户端连接(仅服务器)(Disconnecting Clients (Server Only))
有时候,由于各种原因,你可能需要在不关闭服务器的情况下断开一个客户端的连接。为了做到这一点,你可以调用NetworkManager.DisconnectClient
方法,并将你希望断开连接的客户端的标识符作为唯一参数传递。客户端标识符可以在以下位置找到:
- 使用客户端标识符作为键,
NetworkClient
作为值的NetworkManager.ConnectedClients
字典。 - 通过
NetworkManager.ConnectedClientsList
作为只读的NetworkClients
列表。 - 可以通过
NetworkManager.ConnectedClientsIds
访问所有连接的客户端标识符的完整列表。 - 客户端标识符作为参数传递给
NetworkManager.OnClientConnected
事件的所有订阅者。 - 玩家的
NetworkObject
具有NetworkObject.OwnerClientId
属性。
提示
获取玩家的主NetworkObject
的一种方法是通过NetworkClient.PlayerObject
。
void DisconnectPlayer(NetworkObject player)
{
// 注意:如果客户端调用此方法,将会抛出一个异常。
NetworkManager.DisconnectClient(player.OwnerClientId);
}
客户端断开连接通知(Client Disconnection Notifications)
客户端和服务器都可以订阅NetworkManager.OnClientDisconnectCallback
事件,以便在客户端断开连接时收到通知。客户端断开连接的通知是“相对”的,取决于接收通知的是哪一方。
有两种常见的“断开连接”类型:
- 逻辑断开:自定义的服务器端代码(你可能为你的项目编写的代码)会调用
NetworkManager.DisconnectClient
。- 例如:主机玩家可能会踢出某个玩家,或者有玩家长时间处于“不活跃状态”而被断开连接。
- 网络中断:传输层检测到已不再存在有效的网络连接。
当断开连接通知触发时:
- 客户端会在被服务器断开连接时收到通知。
- 如果客户端断开连接(即玩家主动退出游戏会话),服务器会收到通知。
- 当服务器或客户端由于意外原因断开网络连接时(如网络中断),双方都会收到通知。
不会触发断开连接通知的场景:
- 当服务器“逻辑上”断开客户端时。
- 原因:此时服务器已经知道客户端已断开连接。
- 当客户端“逻辑上”自行断开连接时。
- 原因:此时客户端自身已经知道其已断开连接。
连接通知管理器示例(Connection Notification Manager Example)
以下是你可以向任何类型的NetworkBehaviour或MonoBehaviour派生组件提供客户端连接和断开通知的一个示例。
提示:
为了确保这个ConnectionNotificationManager
实例能够一直有效运行,你得把它挂载到和NetworkManager
相同的GameObject上,只要NetworkManager
的单例实例存在,它就能持续工作。
using System;
using UnityEngine;
using Unity.Netcode;
/// <summary>
/// 仅将此示例组件附加到NetworkManager GameObject上。
/// 这将为你提供一个集中注册处理客户端连接和断开连接事件的地方。
/// </summary>
public class ConnectionNotificationManager : MonoBehaviour
{
public static ConnectionNotificationManager Singleton { get; internal set; }
public enum ConnectionStatus
{
Connected,
Disconnected
}
/// <summary>
/// 当客户端连接或断开游戏时,此委托会被调用。
/// 第一个参数是客户端的ID(ulong类型)。
/// 第二个参数表示该客户端正在连接还是断开连接。
/// </summary>
public event Action<ulong, ConnectionStatus> OnClientConnectionNotification;
private void Awake()
{
if (Singleton != null)
{
// 只要不创建多个NetworkManager实例,就抛出异常。
//(***当前调用栈的位置将停在这里***)
throw new Exception($"检测到不止一个 {nameof(ConnectionNotificationManager)}实例! " +
$"是否在某个 {nameof(GameObject)}上附加了多个组件?");
}
Singleton = this;
}
private void Start()
{
if (Singleton != this){
return; // 如果这是重复实例,则防止问题进一步恶化 >:(
}
if (NetworkManager.Singleton == null)
{
// 不能监听不存在的对象 >:(
throw new Exception($"当前没有能让{nameof(ConnectionNotificationManager)}干活用的{nameof(NetworkManager)}!" +
$"请在场景中添加一个{nameof(NetworkManager)}");
}
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnectedCallback;
NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnectCallback;
}
private void OnDestroy()
{
// 由于NetworkManager可能在本组件之前被销毁,所以只有在其单例仍然存在的情况下才移除订阅。
if (NetworkManager.Singleton != null)
{
NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnectedCallback;
NetworkManager.Singleton.OnClientDisconnectCallback -= OnClientDisconnectCallback;
}
}
private void OnClientConnectedCallback(ulong clientId)
{
OnClientConnectionNotification?.Invoke(clientId, ConnectionStatus.Connected);
}
private void OnClientDisconnectCallback(ulong clientId)
{
OnClientConnectionNotification?.Invoke(clientId, ConnectionStatus.Disconnected);
}
}
网络变换(NetworkTransform)
简介(Introduction)
在如今的多人游戏中,对象transform(变换)的同步是最常见的网络编码任务之一。这个概念看似简单:
- 确定你希望同步的transform轴
- 序列化这些值
- 将序列化的值作为消息发送给所有其他已连接客户端
- 处理消息并反序列化这些值
- 将这些值应用到相应的轴上
乍一看,上述高级概述的任务似乎相对简单,但当你开始逐项实现时,几乎任何资深网络编码软件工程师都会认同:这一过程很快就会变得复杂起来。
例如,上述列举的任务并未考虑到以下问题:
- 谁来控制同步(也就是说,是每个客户端、服务器端,还是根据被同步对象的不同可能由两者共同控制)?
- 你应当多久同步一次这些值?又该使用什么样的逻辑来判断何时需要进行同步呢?
- 如果有复杂的父子层级结构(父对象带有一个或多个子变换(transforms)),应该同步世界空间坐标轴的值还是局部空间坐标轴的值?
- 怎样才能优化每次transform更新时所需的带宽成本?
幸运的是,NGO 提供了“NetworkTransform”组件实现,它能够处理transform同步中一些较复杂的问题,并且可以通过编辑器内的inspector视图访问和轻松配置其属性。
添加组件(Adding the component)
当向一个游戏对象添加 NetworkTransform 组件时,它需要在相同的游戏对象或父游戏对象上有一个 NetworkObject 组件才能正常工作。
在这张图片中,NetworkTransform 和 NetworkObject 组件都在同一个游戏对象上:
每周更新
很好,接下来你可以尝试看看官方文档了:
官方文档链接