首先亮出文档,可以直接去看官方文档。
官方文档
翻译水平有限,如有错误,欢迎在评论区指正。
部分教程链接如下:
教程
本文章基于Netcode for GameObject 1.5.2进行翻译。
Netcode for GameObjects(NGO)是一个为Unity构建的高级网络库,用于抽象化网络逻辑。它使你能够将游戏对象和世界数据通过网络会话发送给多个玩家。通过使用NGO,你可以专注于构建游戏,而不必关注低级协议和网络框架。
要了解更多关于Netcode for GameObjects的功能和能力,请查看下面的内容:
安装Unity Netcode
从UNet迁移到Netcode
升级到Unity Netcode Package
开始使用Netcode
Boss Room(首领房间)
Bite Size Samples(小示例)
Dilmer’s Tutorials(Dilmer的教程)
网络
组件
对象
消息系统
序列化
场景
日志记录
故障排除
错误消息
高级术语
多人游戏架构
常见问题解答
别忘了查看发行说明和API文档!
Netcode支持以下版本:
Netcode支持以下平台:
最后更新日期:2023年8月2日
以下内容跟踪了下一个版本的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是开源的,你可以在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是开源的,你可以在com.unity.multiplayer.samples.bitesize的GitHub存储库中访问完整的发行说明和变更日志。
发布 | 日期 | 更新日志
1.1.0 2022-12-13 1.1.0
最后更新日期:2023年8月14日
API参考
你可以使用本指南来帮助你在Unity项目中设置Netcode for GameObjects (NGO)。
在开始安装Netcode之前,请确保你具备以下条件:
注意
当运行在游戏主机等封闭平台(PlayStation、Xbox、Nintendo Switch)上时,可能会存在特定的政策和注意事项。请参考你所用游戏主机的文档以获取更多信息。
在安装了Netcode for GameObjects (NGO)之后,请参阅以下内容以继续你的旅程:
最后更新时间:2023年8月14日
——————————————————————————————————
使用本指南学习如何创建你的第一个NGO项目。它将指导你创建一个简单的Hello World项目,实现Netcode for GameObjects (NGO)的基本功能。
参考"Testing the command line helper",学习如何使用命令行辅助工具测试你的构建结果。
在开始之前,请确保你具备以下条件:
在继续之前,请使用 Unity 编辑器版本 2021.3 或更高版本创建一个新项目。
小贴士
- 如果你还没有一个 Assets/Scripts/ 文件夹,现在创建一个:
- 在项目选项卡中,右键单击Assets文件夹,然后选择Create> Folder。 将新文件夹命名为Scripts。
这将是你保存所有脚本的位置。
参考安装Netcode for GameObjects的说明。
本节将指导你添加网络游戏的基本组件:
本节将指导你创建一个NetworkManager组件。
首先,创建NetworkManager组件:
信息
当你将预制体放入PlayerPrefab槽时,你是在告诉库当客户端连接到游戏时,自动将此预制体生成为连接客户端的角色。如果你没有将任何预制体设置为PlayerPrefab,NGO将不会生成玩家对象。参考Player Objects。
这部分将指导你创建一个为每个连接的玩家生成对象的过程。
7. 通过在Scene选项卡中选择Player胶囊体,然后按下删除键(或macOS按下Cmd + Delete)来删除场景中的Player。
提示
你可以从场景中移除Player GameObject,因为你将这个网络预制体分配给NetworkManager组件中的Player prefab属性。该库不支持将玩家对象定义为场景中放置的NetworkObject。
注意
添加平面是为了提供一个可视化参考点来显示Player预制体的位置,但这并不是必需的。
12. 按下Ctrl/Cmd + S(选择File > Save)保存场景。
这部分将指导你将场景添加到build中。
网络管理器(NetworkManager)的启用场景管理(Enable Scene Management)设置允许服务器控制客户端加载的场景。但是,你必须将当前场景添加到构建中才能进入游戏模式。
注意
网络管理器(NetworkManager)的启用场景管理选项默认已启用。
Scenes/SampleScene 在Scenes In Build下列出。你可以关闭Build Settings窗口。
这部分将指导你向项目添加基本的RPCs。
提示
如果你还没有Assets/Scripts/文件夹,现在创建一个:
- 在项目选项卡中,右键单击Assets文件夹,然后选择Create > Folder新建文件夹。
- 将新文件夹命名为Scripts。
这将是你保存所有脚本的位置。
创建一个名为RpcTest.cs的脚本:
将RpcTest.cs脚本添加到Player预制体上:
编辑RpcTest.cs脚本:
using Unity.Netcode;
using UnityEngine;
public class RpcTest : NetworkBehaviour
{
public override void OnNetworkSpawn()
{
if (!IsServer && IsOwner) //Only send an RPC to the server on the client that owns the NetworkObject that owns this NetworkBehaviour instance
{
TestServerRpc(0, NetworkObjectId);
}
}
[ClientRpc]
void TestClientRpc(int value, ulong sourceNetworkObjectId)
{
Debug.Log($"Client Received the RPC #{value} on NetworkObject #{sourceNetworkObjectId}");
if (IsOwner) //Only send an RPC to the server on the client that owns the NetworkObject that owns this NetworkBehaviour instance
{
TestServerRpc(value + 1, sourceNetworkObjectId);
}
}
[ServerRpc]
void TestServerRpc(int value, ulong sourceNetworkObjectId)
{
Debug.Log($"Server Received the RPC #{value} on NetworkObject #{sourceNetworkObjectId}");
TestClientRpc(value, sourceNetworkObjectId);
}
}
这部分将引导你测试之前添加的RPCs。
提示
除了使用命令行助手脚本外,你还可以使用多人游戏模式(MPPM)包,它允许你运行多个Unity编辑器实例来测试多人游戏功能。有关更多信息,请参阅Multiplayer Play Mode。
注意:MPPM仅在Unity编辑器2023.1版本及更高版本中受支持。
在客户端和服务器生成之后,日志将显示在客户端和服务器的控制台中,显示它们相互发送RPC消息的情况。
客户端在其OnNetworkSpawn调用中首次启动交换,计数器的值为0。然后,它使用下一个值调用服务器的RPC。服务器接收到这个消息后会调用客户端。在控制台中分别显示服务器和客户端的以下内容。
Server Received the RPC #0 on NetworkObject #1
Server Received the RPC #1 on NetworkObject #1
Server Received the RPC #2 on NetworkObject #1
Server Received the RPC #3 on NetworkObject #1
...
Client Received the RPC #0 on NetworkObject #1
Client Received the RPC #1 on NetworkObject #1
Client Received the RPC #2 on NetworkObject #1
Client Received the RPC #3 on NetworkObject #1
...
只有在服务器上拥有RpcTest脚本的NetworkObject的客户端才会发送RPC,但它们都将从服务器接收RPC。这意味着,如果你使用多个客户端进行测试,在服务器和所有客户端上,控制台将在每个迭代中记录每个NetworkObject接收到的RPC一次。如果使用主机和客户端进行测试,你将在主机的控制台中看到以下内容。这是因为作为服务器,它将接收到其他客户端的服务器RPC,并且作为客户端,它也将接收到自己的客户端RPC。
Server Received the RPC #0 on NetworkObject #2
Client Received the RPC #0 on NetworkObject #2
Server Received the RPC #1 on NetworkObject #2
Client Received the RPC #1 on NetworkObject #2
Server Received the RPC #2 on NetworkObject #2
Client Received the RPC #2 on NetworkObject #2
Server Received the RPC #3 on NetworkObject #2
Client Received the RPC #3 on NetworkObject #2
...
注意
这里的NetworkObjectId是2,因为主机也具有一个拥有RpcTest脚本生成的NetworkObject,但它不会发送启动链的初始RPC,因为它是服务器。
本节展示如何使用两个脚本扩展Hello World项目的功能:HelloWorldPlayer.cs和HelloWorldManager.cs。
using Unity.Netcode;
using UnityEngine;
namespace HelloWorld
{
public class HelloWorldManager : MonoBehaviour
{
void OnGUI()
{
GUILayout.BeginArea(new Rect(10, 10, 300, 300));
if (!NetworkManager.Singleton.IsClient && !NetworkManager.Singleton.IsServer)
{
StartButtons();
}
else
{
StatusLabels();
SubmitNewPosition();
}
GUILayout.EndArea();
}
static void StartButtons()
{
if (GUILayout.Button("Host")) NetworkManager.Singleton.StartHost();
if (GUILayout.Button("Client")) NetworkManager.Singleton.StartClient();
if (GUILayout.Button("Server")) NetworkManager.Singleton.StartServer();
}
static void StatusLabels()
{
var mode = NetworkManager.Singleton.IsHost ?
"Host" : NetworkManager.Singleton.IsServer ? "Server" : "Client";
GUILayout.Label("Transport: " +
NetworkManager.Singleton.NetworkConfig.NetworkTransport.GetType().Name);
GUILayout.Label("Mode: " + mode);
}
static void SubmitNewPosition()
{
if (GUILayout.Button(NetworkManager.Singleton.IsServer ? "Move" : "Request Position Change"))
{
if (NetworkManager.Singleton.IsServer && !NetworkManager.Singleton.IsClient )
{
foreach (ulong uid in NetworkManager.Singleton.ConnectedClientsIds)
NetworkManager.Singleton.SpawnManager.GetPlayerNetworkObject(uid).GetComponent<HelloWorldPlayer>().Move();
}
else
{
var playerObject = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject();
var player = playerObject.GetComponent<HelloWorldPlayer>();
player.Move();
}
}
}
}
}