本教程将详细展示如何把 Unity Online Services(UOS)Multiverse 与 Netcode for GameObjects 相结合,完成入门级操作。

通过本教程,你不仅能学会如何将其构建为专用服务器(Dedicated Server),并借助 Multiverse 进行托管,还能掌握运用 Matchmaking 为多人联机游戏打造可定制化的对局匹配。此外,教程还会演示并讲解将 Demo 工程部署至微信小游戏平台时所需的各项设置,带你一站式打通游戏开发与部署的关键流程!

大家可以通过 UOS 官网提供的多人联机服务选型参考,来了解 Dedicated Game Server 适用的游戏类型:

https://uos.unity.cn/product/multiplayer

教程中涉及 UOS 服务包括:

  • 服务器托管服务 Multiverse:用于部署多人联机服务端程序

服务器托管服务 Multiverse

Multiverse,由 Unity 资深团队匠心打造的专业服务器托管解决方案,让您的服务从上线到运营全程无忧。

它根植于 Agones 的强大基础,提供了更为可靠、丰富且高效的托管服务。借助 Multiverse,您的游戏能够迅速启动并运行于弹性缩扩容的系统中,无论是面对几百还是几百万的玩家,都能轻松应对,实现游戏服务器的无忧托管,让您全心投入到提升游戏的可玩性之中。

选择 Multiverse 的卓越优势:

  • 高效可靠的伸缩能力:基于 Agones 的坚实架构,Multiverse 确保了服务器资源能够根据游戏负载进行即时且高效的调度,同时提供可靠的伸缩机制,无论是面对突发的玩家涌入还是日常的流量波动,都能确保游戏运行的平稳与流畅。

  • 灵活的 Docker 容器部署:借助 Docker 容器技术的强大功能,Multiverse 允许开发者以更加灵活和模块化的方式组织服务,同时简化了系统依赖的安装与管理过程,使得服务的部署、升级与迁移变得更加便捷与高效。

  • 多地域智能缩扩容:为了满足全球玩家的需求,Multiverse 支持在全球多个地域部署服务器,并根据实时流量数据自动调整服务器资源,确保服务的经济性与高效性。这种智能化的缩扩容策略不仅降低了运营成本,还提升了玩家的游戏体验,让您的游戏在全球范围内都能保持出色的性能与稳定性。

教程视频

教程学习大纲

  1. Unity 项目工程的准备工作

  2. 创建 UOS App 并启用 Multiverse / Matchmaking 服务

  3. 使用 WebSocket 协议配置并启动项目

  4. 使用 Matchmaking 实现对局匹配

  5. 使用 KCP 协议配置并启动项目

  6. 构建 MiniGame 项目,设置 WXSDK 打包参数

  7. 在开发者工具上运行测试小游戏

  8. 更多功能介绍

教程案例工程源文件

教程内学习用到的项目工程文件可以通过以下方式进行下载:

教程示例 Demo 项目工程源文件下载链接:

https://unitychina.coding.net/public/uos/MultiverseNetcodeDemo/git/files

教程操作步骤

1. Unity 项目工程准备工作

温馨提醒:本教程的内容同时适用于 Global Unity Editor 、中国版 Unity Editor 和 团结引擎,当前先以在中国版 Unity 引擎中的使用为示例,进行讲解演示。

为大家提供两种准备初始项目的方式:

  • 方式一:直接下载我们提供链接里的 Demo 示例项目工程学习,按章节 1.1 的步骤操作,可跳过章节 1.2。

  • 方式二:从创建空项目工程开始,按章节 1.2 的教程步骤逐步学习。

  • 无论选择哪种方式,后续都从章节 2 继续学习

1.1 方式一:直接下载提供的 Demo 示例项目工程 1.1.1 打开项目工程

如果你想直接使用我们提供的示例 Demo 场景进行学习操作的话,请先通过上面提供的 git 链接,下载 Demo 项目工程。

在教程中,我们先使用 中国版 Unity 2022.3.53 f1c1 版本来打开项目工程,然后等待项目工程的加载。

1.1.2 安装 Netcode for GameObjects 资源包

当前项目将使用 Multiverse 结合 Netcode 来制作 Demo 的效果,所以项目中需要先安装 Netcode 资源包。

  • 在 Package Manager 窗口中,我们可以看到当前 Demo 已经安装好了 Netcode 资源包。无需再次安装。

  • 本教程 Demo 的功能是在 Netcode for GameObjects 提供的 Sample 示例的基础上稍作的调整,大家可以自行查看原始的 Sample 示例代码。

1.2 方式二:创建一个空的项目工程,从零开始操作 1.2.1 创建一个空的项目工程

打开 Unity Hub,选择创建新项目,教程这里使用的 Unity 编辑器版本是 2022.3.53f1c1 版本,大家可以自行选择电脑上已安装的版本。

项目模板可以选择3D(Built-in),自定义项目名称和位置。可以勾选选项启用游戏云服务,勾选后会自动为你的项目工程安装 UOS Launcher 的,然后可以直接通过 UOS Launcher 来启用想要使用的服务即可。

1.2.2 安装 Netcode for GameObjects 资源包

由于当前项目将使用 Multiverse 结合 Netcode 来制作 Demo 的效果,所以项目中需要先安装 Netcode 资源包。

可以打开WindowPackage Manager窗口,然后选择Unity Registry,搜索找到Netcode for GameObjects,然后点击Install即可。

教程中我们会在 Netcode 提供的示例的 Sample 基础上添加 Multiverse 和 Matchmaking 的功能。所以,我们先找到Samples,点击Import,导入 Netcode 的示例场景。

1.2.3 查看 Sample 场景

找到 Project 窗口中的 Bootstrap.unity 场景并打开,运行查看下当前示例场景的效果。

在弹出的下面窗口中,点击Yes,则会自动将当前场景添加到FileBuildSettings中。

运行后,Game 场景画面如下:

可以先在编辑器中点击Host按钮,会看到在场景中会生成一个 Sphere 游戏对象,点击Random Teleport按钮,就可以随机一个新的位置。

1.2.4 场景中创建对局匹配和随机位置的 UI 按钮

由于场景中的按钮是通过 OnGUI 函数绘制出来的,为了后面方便操作 UI 对象,我们对场景做一些调整,使用 UGUI 来创建 Button。在 Hierarchy 窗口中,点击+UIButton - TextMeshPro来创建一个按钮。

在弹出窗口中,点击Import TMP Essentials来导入相关资源:

然后设置 UI 自适应:找到 Canvas 对象上的 Canvas Scaler 组件,将UI Scale Mode设置为:Scale With Screen Size,分辨率暂时选择 1920 *1080。

修改匹配按钮的名字为:Button_StartMatch,大家可以自己调整想要的按钮的大小、位置以及按钮的颜色或者按钮的背景贴图等。

为了 UI 界面的美观,大家可以自行更换按钮上的贴图和字体。在教程中,我们创建了一个 Resources 文件夹,然后文件夹内放入了自己想要使用的 UI 贴图和字体了。UI 贴图的格式,也已经提前设置好 Sprite 格式了。

找到 Button 组件,将Transition类型改为Sprite Swap,在按钮的「Normal 」状态我们使用 Btn_MainButton_Blue 贴图,在按钮的「Disabled」禁用状态使用 Btn_MainButton_Gray 这张贴图。然后可以通过激活或者关闭 Interactable 属性,测试按钮的图片效果。

默认 TextMeshProUGUI 提供的 FontAsset 是不支持输入中文的开始匹配的,如果你想写中文文字的话,请自行创建中文字体集,这里暂时先不讲解 UGUI 的如何创建中文字体集的知识点了,就直接使用导入的创建好的字体集资源了。

选中 Button_StartMatch 按钮复制一份,重命名为:Button_RandomTeleport,作为后面随机小球位置的按钮。移动到左上角的位置,按钮的 Text 先写:RandomTeleport。

设置一下初始时场景中随机位置的按钮是隐藏的状态:

接下来,我们就用刚才的新创建的项目工程继续下面的步骤讲解了。如果你是用我们提供的示例 Demo 的话,后续教程步骤也是一样的。

1.2.5 设置 Network Prefabs Lists

找到场景中的 BootstrapManager 身上的 NetworkManager 组件,可以看到 Player Prefab 参数已经设为 BootstrapPlayer 预制物体对象了,表示在客户端连接上服务器时,会克隆出一个 BootstrapPlayer 对象。

NetworkPrefabsLists 参数用于指定在网络同步过程中会使用到的预制体(Prefab)列表。在网络多人游戏开发中,当客户端和服务器之间需要同步游戏对象时,Unity 需要知道哪些预制体可以被实例化并在网络上进行同步。如果不指定这些预制体,当服务器或客户端尝试实例化网络对象时,Unity 就无法识别这些对象,从而导致同步失败。

在这里,我们将 Assets 文件夹下的 DefaultNetworkPrefabs 添加到 NetworkPrefabsLists 中。

然后再手动添加一下场景中要网络同步的预制物体游戏对象 BootstrapPlayer。

2. 创建 UOS App 并启用服务

温馨提示:当前项目中已安装好 UOS Launcher,不需要再次安装了。大家可以参考之前的 的公众号文章教程,来为你当前的项目绑定你创建好的 UOS App 。

2.1 绑定 UOS App

点击 Launcher 面板的「LinkApp」按钮,在弹出窗口中选择「By Unity project」,在「Select organization」这里选择一个自己的项目组织,然后在「Select project 」选项这里,我们选择「Create a new project 」,自行设置修改项目名字「Project name」

教程中,我们就先选择绑定创建好的 NetcodeAndMultiverse_Demo 应用了。

2.2 开启 Multiverse 服务

在编辑器内 Unity Online Services 窗口的下拉服务列表中,找到「Multiverse」,点击「Enable」开启服务。

如果自己项目中没安装过的话,可以点击「Install」安装 SDK 。当前给大家提供的制作好的示例 Demo 项目已经安装过 Multiverse SDK 了,无需再次安装。

2.3 开启 Matchmaking 服务

接着继续在 UOS Launcher 的下拉服务窗口列表中,找到「Matchmaking Client」,点击「Enable」开启服务。

如果自己项目中没安装过的话,可以点击「Install」安装 SDK 。当前给大家提供的制作好的示例 Demo 项目已经安装过 Matchmaking Client SDK 了,无需再次安装。

2.4 安装 WebSocket 和 KCP 协议包

最终会将项目部署至微信小游戏平台,我们已经做好了相关的协议适配,大家可以在项目中使用提供的 WebSocket 协议和 KCP 协议。当前工程中,已经安装好了 WebSocket 协议和 KCP 协议。

如果是自己的项目工程的话,可以通过下面提供的 git 链接来安装对应的协议:在「Package Manager」窗口,点击左上角的「+」,选择「Add package from git URL」,输入提供的 git 链接,点击「Add」即可。

  • WebSocket Transport for Netcode for GameObjects 资源包的 git 安装链接:

https://e.coding.net/unitychina/uos/NetcodeTransport.git?path=websocket

  • Kcp Transport for Netcode for GameObjects 资源包的 git 安装链接:

https://e.coding.net/unitychina/uos/NetcodeTransport.git?path=kcp

2.5 安装 Linux Build 平台支持模块包

稍后当我们通过 Multiverse SDK,在 Editor 中自动构建并上传 Linux Dedicated Game Server 镜像时,会需要将平台切换到 Linux 平台。所以需要在当前使用的 Unity 编辑器版本中,安装 Linux 构建平台模块包

打开 Unity Hub ,找到左侧的「安装」,选择自己使用的 Unity 编辑器版本,比如 2022.3.53f1c1,点击「添加模块」按钮:

在弹出窗口中,同时勾选模块 Linux Build Support(IL2CPP)、 Linux Build Support(Mono)、Linux Dedicated Server Build Support ,然后点击「安装」

3. 使用 WebSocket 协议配置并启动项目 我们先来讲解使用 WebSocket Transport 协议来运行时的相关配置! 3.1 选择 WebSocket 协议

先找到场景中的对象 BootstrapManager,需要移除 Netcode 示例场景中默认为其添加好的 UnityTransport 组件。

然后在「Select transport...」这里选择「WebSocketTransport」,添加 WebSocket 协议对应的脚本组件,同时确保 NetworkManager 组件的 NetworkTransport 参数选择的协议为:WebSocketTransport。

3.2 MultiverseSDK 的初始化

我们先来创建 Multiverse 的服务端程序。找到 BootstrapManager 对象上的 BootstrapManager.cs 脚本,先注释掉或者删除该脚本中的 OnGUI 函数中的所有的代码,因为接下来我们会一步一步讲解要添加使用的代码。

在这里,需要注意的是,Netcode 的示例代码添加了自己的应用程序集文件 Bootstrap.asmdef,所以想要在 BootstrapManager.cs 脚本中引用 UOS 封装的相关 API 时,可做以下的两种处理:

(1)直接删除 Bootstrap/Scripts/Bootstrap.asmdef 文件即可。我们提供的示例 Demo 项目工程中,是已经删除了该文件,所以不需要 Bootstrap.asmdef 相关的配置。

(2)如果不想删除,想保留的话,需要在 Bootstrap.asmdef 文件中添加 UOS 相关的引用,最后记得点击右下角的「Apply」

然后在脚本的 Start 方法中,会根据宏定义来检测一下当前运行环境(服务器端还是客户端),来执行不同的初始化逻辑:

  • 如果是 Linux Dedicated Server 服务端,会先进行 Multiverse SDK 初始化,然后启动服务器,并标记服务器为 Ready 就绪状态。

  • 如果是客户端,则进行 MatchmakingSDK 的初始化,并执行玩家登录的操作。_userId 将用于客户端登录时作为用户的唯一标识。

  • 脚本中记得需要添加 UOS 相关的 namespace 的引用。


using System;
using Unity.UOS.Auth;
using Unity.UOS.Matchmaking;
using Unity.UOS.Multiverse;
using Unity.UOS.Multiverse.Exceptions;
using UnityEngine;
using Unity.Netcode;

public class BootstrapManager : MonoBehaviour
{
private readonly string _userId = Guid.NewGuid().ToString();

private async void Start()
{
#if !UNITY_EDITOR && UNITY_SERVER
// build 为 linux dedicated server 时,执行server端 multiverse sdk 初始化的代码逻辑
Debug.Log("Server is starting");
try
{
// MultiverseSDK 的初始化
await MultiverseSDK.Initialize();
}
catch (MultiverseSDKException ex)
{
Debug.LogErrorFormat("Failed to initialize sdk. {0}", ex);
throw;
}
// 启动 server
NetworkManager.Singleton.StartServer();

try
{
// 标记 server 为 ready 状态
await MultiverseSDK.Instance.ReadyAsync();
Debug.Log("server is ready");
}
catch (MultiverseSDKException ex)
{
Debug.LogErrorFormat("Failed to call mv sdk. {0}", ex);
throw;
}
#else
// build client端时,则初始化 matchmaking sdk 和执行玩家登陆操作
Debug.Log("match making sdk initialize");
MatchmakingSDK.Initialize();
Debug.Log("match making sdk initialized");
await AuthTokenManager.ExternalLogin(_userId);
#endif
}
}

由于在客户端使用 AuthTokenManager.ExternalLogin 来验证玩家的登录操作,所以场景中我们创建一个空对象,可命名为 AuthTokenManager,并挂载 AuthTokenManager.cs 脚本组件。


3.3 构建并上传 Multiverse 镜像

Multiverse 是基于 Docker 镜像来管理服务器程序的,系统需要将用户上传上来的服务器程序制作成 Multiverse 可用的镜像程序,并基于镜像来管理后续所有的配置。

UOS Launcher 提供了一键构建并上传 Multiverse 镜像的功能。当我们使用 Unity 构建 Dedicated Server - Linux 且托管到 Multiverse 时,推荐使用 Launcher 来简化镜像构建与上传的流程。

步骤如下:

  • 在 Multiverse 右侧列表中,点击「构建镜像」按钮,此时则可以通过 Multiverse SDK,在 Editor 中自动上传 Dedicated Game Server 镜像到 UOS Dev Portal。

  • 填写配置:在弹出窗口中填写配置:Target Directory 为镜像存放的本地目录,Image Tag 为镜像标签。

  • 建镜像并上传:点击 Build Image 按钮,等待镜像构建。构建完成后将自动上传到关联的 UOS APP 的 Multiverse 镜像中。

打开 UOS 网页端,在「启动配置」「镜像」这里,可以看到刚才构建的服务端程序,已经自动上传了。

在 Build Settings 窗口这里,可以看到在构建镜像时,Platform 已经自动被切换至 Linux 平台了。当然,大家也可以手动切换至 Linux 平台。

3.4 创建启动配置

我们以 Multiverse 的按需模式为例,需要在「Multiverse -> 启动配置」页面创建一个启动配置,启动配置是开启服务的配置,包含开启服务所需要 CPU、内存限制,启动参数,服务器端口,以及运行程序入口等。

「启动配置」页面,点击「立即创建」

填写配置名称,示例为 mvdemo-websocket ,大家也可自定义,点击「创建」

点击「添加已有镜像

在弹出窗口中,为当前的启动配置添加镜像时,首先选择需要使用的镜像,在这里我们选择 image1-websocket 。

然后设置镜像启动参数:

  • CPU核数:游戏服务器根据需要,可自行设置 CPU 核数。Unity 程序运行时我们推荐设置为 0.5 核以上

  • 启动超时时长:如果 Multiverse 在这个时长内未收到 GameServer 调用 MultiverseSdk.Ready() 的信号, 就会标记该 Allocation 为 failed 状态。

  • 入口程序启动命令:填 server.x86_64,该参数指的是服务器可执行文件在 zip 包中的相对路径。

  • 服务器端口:使用 WebSocket 时,选择 TCP 协议。游戏服务器端口默认将填写端口 9998,我们修改端口为 7777,端口号只要和 Unity 编辑器中自定义的端口号保持一致即可。

填写完后,点击「添加镜像配置」,将该镜像添加至启动配置上。

3.5 测试并应用镜像配置

镜像配置添加成功后,建议点击「立即测试配置」,以确保程序在刚刚的配置下可以正常运行。

测试成功后可选择「下一步」,并点击「应用镜像配置」,点击完成,进入 mvdemo-websocket 的详情页面。

在详情页面,可以进行添加镜像配置、更新启动参数、测试配置、删除配置等一系列操作。

注意:此处不建议应用测试失败的镜像配置,如镜像配置测试运行失败,请查看日志信息,并尝试修改启动参数来修复其中的错误。测试服务可手动关闭,若不关闭测试,系统将在一小时后清除运行的测试实例。

应用镜像配置会将当前镜像启动参数所使用的配置版本替换为该镜像配置。一个启动配置只会有唯一一个应用状态的镜像配置。

3.6 配置 Matchmaking

Matchmaking 是 UOS 提供的用于多人联机游戏的可定制配对服务。通过 Matchmaking,您可以创建自定义的匹配规则,来定义您的多人联机游戏中的游戏对局的玩家组成和阵营划分,以及在对局匹配的过程中应用灵活的调整策略来对匹配规则进行动态更新。

当前绑定的 UOS App 已经启用了「Matchmaking」功能了。需要注意的是,Matchmaking 作为 Multiverse 的支持“玩家匹配"的功能,依赖于 Multiverse 的「房间管理」功能。因此,对于没有启用「房间管理」功能的应用,在启用「Matchmaking」后,会自动启动「房间管理」功能

启用「Matchmaking」功能后,可以进入「Matchmaking」的页面,点击「立即创建」按钮就可以开始创建 Match 配置。

大家自行填写启动配置 mvdemo-websocket 对应的 Match 配置的名称,并且可以对「超时时长」配置项进行调整。这里我们先使用默认的超时时长 60 秒。

然后会进入模板选择页面,我们基于市面上常见的游戏玩法及其匹配机制为用户事先准备了一系列的 Match 配置的模板。

在本教程中,我们选择「自由休闲类」「快速启动」模板为例进行讲解。选择了模板后,点击「创建」

在 Match 配置的详情页中,大家可以对配置模板所提供的匹配信息进行调整,也可以更换新的模板,或者是对相关配置项进行调整。

teamDefinitions 声明了一局游戏的队伍规格和属性,示例模板中定义的该匹配规则的含义是:队伍名为 quick-game 的一局对局,最少玩家数为 1,最大玩家数为 4,如果达到了 minPlayers, 则可认为该队伍满足了匹配条件。

3.7 开启地域

到这里,大家已经通过教程创建了一个已应用镜像、并可以正常运行的启动配置了,接下来点击侧边栏的「房间/服务器」。可以看到,此时尚未启用任何地域,也未分配服务器,点击「启用」

并填写最大服务数,可直接点击「确认」,则会以默认值 10 为最大服务数完成开启。

在启用地域「上海」后,意味着您接下来的服务器可以创建在上海地区,不同地域可以满足不同的部署需求。

此时已经可以先在 Unity 编辑器中,点击运行进行测试。会看到客户端日志输出信息,说明客户端完成了初始化 matchmaking sdk 和执行了玩家登陆的操作。

4. 使用 Matchmaking 实现对局匹配

接下来看看使用 Matchmaking 是如何实现对局匹配功能的!

4.1 创建 Ticket 实现轮询匹配

继续在脚本 BootstrapManager.cs 中添加 OnStartMatchButton 方法,来实现当点击「开始匹配」的按钮时要响应的事件。

  • 定义变量 startButton,表示开始匹配的 UI 按钮。当玩家点击开始匹配的 UI 按钮时,代码会进行一系列操作,包括更新按钮文字和状态。UI 上文字将显示匹配中......,并且此时按钮变为不可点击的状态。

  • 当玩家想要开启一局匹配时,就需要在客户端发起一个 Ticket。在这里,客户端会根据 Matchmaking 的匹配配置 Id,调用 CreateTicketAsync 方法来创建一个 Ticket ,发起匹配请求。需要传入两个参数:Matchmaking 的匹配配置 Id,以及玩家列表 List。

  • 稍后会给大家详细解释开启协程去轮询 GetTicket 等待匹配结果的方法 WaitForMatchResult,我们同时会使用 try...catch... 来处理捕获到的异常情况。


//需要新引入的 namespace--------------------------------------
using UnityEngine.UI;
using TMPro;
using Unity.UOS.Matchmaking.Model;
using System.Collections.Generic;
using Unity.UOS.Matchmaking.Exception;
//需要新引入的 namespace--------------------------------------

namespace Unity.UOS.Multiverse.Samples.NetCode
{
public class BootstrapManager : MonoBehaviour
{
// 填写Matchmaking的配置列表中的配置ID
public string matchmakingConfigId;
// 填写Matchmaking配置中的玩家匹配请求超时时长
public int matchmakingTimeoutSeconds = 120;
private readonly string _userId = Guid.NewGuid().ToString();
public Button startButton; //开始匹配的UI按钮
private Coroutine matchCoroutine;

// 点击开始匹配按钮的响应事件
public async void OnStartMatchButton()
{
// Change text to "匹配中......"
startButton.transform.GetChild(0).GetComponent ().text = "匹配中......";
// Change button to non-clickable state
startButton.interactable = false;

var player = new Player()
{
id = _userId
};

try
{
//创建一个 Ticket 开始匹配,传入参数:Matchmaking匹配配置Id,玩家列表
var ticketId =
await MatchmakingSDK.Instance.CreateTicketAsync(matchmakingConfigId, new List { player });
// 开启一个 coroutine 去轮询 GetTicket 等待匹配结果
matchCoroutine ??= StartCoroutine(WaitForMatchResult(ticketId));
}
catch (MatchmakingClientException ex)
{
Debug.LogErrorFormat("Failed to create ticket, clientEx: {0}", ex);
throw;
}
catch (MatchmakingServerException ex)
{
Debug.LogErrorFormat("Failed to create ticket, serverEx: {0}", ex);
throw;
}
}
}
}

此时也是需要引入系统自带的 TextMeshPro Package 资源包的应用程序集,添加引用后,点击「Apply


接着,我们要开启一个 coroutine 去轮询 GetTicket 等待匹配结果了,封装协程方法 WaitForMatchResult 来实现该功能。

  • 将根据配置的玩家匹配请求超时时长,也就是参数 matchmakingTimeoutSeconds 设置的时长,每间隔 1 秒调用一次自定义封装的 GetTicketAsync 方法,来轮询 GetTicket 等待匹配结果。

  • 添加异步方法 GetTicketAsync ,在方法内实现查询指定 tickerId 的 Ticket 信息。

  • 每次查询 Ticket 信息时,要等待任务完成,如果检查到任务出错,就抛出异常并跳出循环。

  • 然后获取任务的结果,为了方便调试,我们可以打印一下当前 Ticket 的状态。如果检查到 Ticket 的状态为匹配完成或者错误,则跳出循环、退出轮询。


//需要新引入的 namespace--------------------------------------
using System.Collections;
using System.Threading.Tasks;
//-----------------------------------------------------------

namespace Unity.UOS.Multiverse.Samples.NetCode
{
private IEnumerator WaitForMatchResult(string ticketId)
{
// 轮询 GetTicket 等待匹配结果
Ticket ticket = null;
for (var i = 0; i < matchmakingTimeoutSeconds; i++)
{
var task = GetTicketAsync(ticketId);//查询指定 ticket id 的详细信息
yield return new WaitUntil(() => task.IsCompleted);

if (task.IsFaulted)
{
if (task.Exception != null) throw task.Exception;
break;
}

ticket = task.Result;
Debug.Log($"Current ticket status: {ticket.status}");

if (ticket.status is MatchmakingSDK.TicketStatusMatched or MatchmakingSDK.TicketStatusError)
{
break;
}

// 延时1秒
yield return new WaitForSeconds(1);
}
}
// 查询指定 ticket id 的详细信息
private async Task GetTicketAsync( string ticketId)
{
try
{
return await MatchmakingSDK.Instance.GetTicketAsync(ticketId);
}
catch (MatchmakingClientException ex)
{
Debug.LogErrorFormat("Failed to get ticket, clientEx: {0}", ex);
throw;
}
catch (MatchmakingServerException ex)
{
Debug.LogErrorFormat("Failed to get ticket, serverEx: {0}", ex);
throw;
}
}
 }

如果轮询 Ticket 的过程中,捕获到异常,需要做一些清除资源的操作。所以,封装一个方法 Cleanup,来处理遇到异常时停止协同程序的执行。在代码中添加调用 Cleanup 方法的地方:

private void Cleanup()
{
if (matchCoroutine == null) return;
StopCoroutine(matchCoroutine);
matchCoroutine = null;
}

代码中添加调用 Cleanup 方法的地方:

  • 在 OnStartMatchButton 方法的 Client /Server 异常时,添加调用 Cleanup 方法;

  • 在 GetTicketAsync 方法的 Client/Server 异常时,也添加调用 Cleanup 方法;

  • 在 WaitForMatchResult 方法的轮询匹配时,如果异步任务出错(task.IsFaulted),则调用 Cleanup 方法停止协程函数的调用。


// 点击开始匹配按钮的响应事件
public async void OnStartMatchButton()
{
//此处省略其它代码行......
try
{
//此处省略其它代码行......
}
catch (MatchmakingClientException ex)
{
Debug.LogErrorFormat("Failed to create ticket, clientEx: {0}", ex);
Cleanup();
throw;
}
catch (MatchmakingServerException ex)
{
Debug.LogErrorFormat("Failed to create ticket, serverEx: {0}", ex);
Cleanup();
throw;
      }
}

// 查询指定 ticket id 的详细信息
private async Task GetTicketAsync( string ticketId)
{
try
{
return await MatchmakingSDK.Instance.GetTicketAsync(ticketId);
}
catch (MatchmakingClientException ex)
{
Debug.LogErrorFormat("Failed to get ticket, clientEx: {0}", ex);
Cleanup();
throw;
}
catch (MatchmakingServerException ex)
{
Debug.LogErrorFormat("Failed to get ticket, serverEx: {0}", ex);
Cleanup();
throw;
      }
}

private IEnumerator WaitForMatchResult(string ticketId)
{
// 轮询 GetTicket 等待匹配结果
Ticket ticket = null;
      for (var i = 0; i < matchmakingTimeoutSeconds; i++)
{
var task = GetTicketAsync(ticketId);//查询指定 ticket id 的详细信息
yield return new WaitUntil(() => task.IsCompleted);

if (task.IsFaulted)
{
Cleanup();
if (task.Exception != null) throw task.Exception;
break;
}

          //此处省略其它代码行......
      }
}

添加完代码,接着找到场景中的开始匹配的 UI 按钮对象 Button_StartMatch,要确保此按钮已经在 Inspector 面板上注册绑定了:BootstrapManager 对象上的脚本 BootstrapManager.cs 中的 OnStartMatchButton 方法。


回到 UOS 网页端,找到「Matchmaking」「配置列表」,复制 mvdemo-websocket 下方的 Matchmaking 配置 ID 号。


回到 Unity 编辑器,在 Inspector 面板上的 BootBootstrapManager 组件这里,有几个参数需要我们设置:

  • 将刚才 UOS 网页端复制的 Matchmaking 配置 ID ,粘贴到 matchmakingConfigId 参数这里。

  • matchmakingTimeoutSeconds 参数,在这里也是需要和 UOS 网页端配置的玩家匹配请求超时时长(60 秒)保持一致。如果在 60 秒结束之后 Ticket 仍未匹配成功,将被标记为匹配失败。

  • StartButton:指定为场景中的按钮 Button_StartMatch。

继续点击运行项目后,查看控制台输出的日志信息,可以看到当前 Tickcet 状态的变化:由 created → awaitingAssignment → matched

Ticket 共有以下状态:

  • 匹配已创建 (created):Ticket 已成功创建,并处于正在匹配玩家的状态。

  • 匹配成功,正在创建房间 (awaitingAssignment): Ticket 已匹配成功,系统正在为该局游戏创建房间。

  • 匹配成功,且创建房间完成 (matched): 匹配成功并已能够拿到 IP 和 PORT 等对局信息,可连接到战斗服开始游戏。

  • 匹配失败 (error): 匹配超时(匹配时长超出玩家匹配请求超时时长)或是 Ticket 不符合规则被标记非法 Ticket。

Ticket 状态转换关系如下图:

4.2 匹配成功后,获取匹配到的服务器的 IP 地址和端口号

接下来处理匹配成功后的逻辑!

在这里我们先使用 WebSocket 协议进行测试,代码中如果缺少引用会报错的,我们先提前引入 WebSocket Transport for Netcode 资源包的应用程序集」。添加引用后,点击「Apply」按钮。

在脚本中定义方法 HandleMatchedTicket 来处理匹配到的 Ticket

  • 当 Ticket 的状态为匹配成功时,会先解析匹配到的房间端口信息(ticket.assignment.gamePorts),得到当前匹配到的服务器的端口号 port。

  • 然后根据所使用的网络传输协议 NetworkTransport 类型(如 UOS 提供的 KCP 或 WebSocket 协议)进行相应配置,以便客户端能连接到匹配的服务器。

  • 当使用 WebSocket 协议时,先获取到 WebSocketTransport 组件,然后再将匹配到的服务器的 IP 地址和端口,填充到 WebSocketTransport 组件上的参数 ConnectAddress 和 Port 。

//需要新引入的 namespace-----------------------------------
using Netcode.Transports.WebSocket;
//--------------------------------------------------------

private void HandleMatchedTicket(Ticket ticket)
{
//ticket匹配到的房间端口,形如 port-name / port
//比如当Multiverse启动配置只填了一个端口时:websocket / 7654; 配置了多个端口时:websocket / 7654,kcp / 7655
//这里的代码示例是以只填了一个端口为例
var ports = ticket.assignment.gamePorts.Split(",");
if (ports.Length != 1)
{
throw new Exception("Unexpected number of ports");
}

var portInfo = ports[0].Split("/");
if (portInfo.Length != 2)
{
throw new Exception("Unexpected number of port info");
}

var port = ushort.Parse(portInfo[1]);

switch (NetworkManager.Singleton.NetworkConfig.NetworkTransport)
{
case WebSocketTransport:
{
//如果使用 websocket 协议,获取 WebSocketTransport 组件
var wt = NetworkManager.Singleton.GetComponent ();
if (wt == null)
{
throw new Exception("Unexpected null WebSocketTransport");
}

//填充匹配到的服务器的ip地址和端口到 WebSocketTransport 组件
Debug.Log("Using WebSocket transport");
wt.ConnectAddress = ticket.assignment.ip;
wt.Port = port;

break;
}
default:
throw new Exception("No suitable transport found");
}
}

然后我们找到之前封装过的 WaitForMatchResult 方法,添加判断:如果匹配成功时,调用处理匹配结果的方法 HandleMatchedTicket。如果捕获到异常时,就清除相关的资源。

private IEnumerator WaitForMatchResult(string ticketId)
{
// 轮询 GetTicket 等待匹配结果
Ticket ticket = null;
for (var i = 0; i < matchmakingTimeoutSeconds; i++)
{
        //此处省略其它代码行......
}

if (ticket is { status: MatchmakingSDK.TicketStatusMatched })
{
Debug.Log("匹配成功");
try
{
// 处理匹配结果
HandleMatchedTicket(ticket);
}
catch (Exception)
{
Cleanup();
throw;
}
}
//此处省略其它代码行......
}

再次运行游戏后进行测试,查看日志信息会输出:"Using WebSocket transport",说明使用了 WebSocket 协议。同时可以查看下 WebSocketTransport 组件的 Connect Address 和 Port 参数,已经发生了变化。


刷新 UOS 网页端的服务器列表,可以看到自动创建的服务器信息。点击服务器 UUID 值查看服务器详情,可以获取到服务器的 IP 与端口(使用 Multiverse 映射后的端口)。

  • 配置中的服务器端口为内部监听端口,连接时会使用 Multiverse 映射后的端口

  • 如下图,配置时填的服务器监听端口为 7777,但是连接时将使用映射后的端口 7005 进行连接。

4.3 匹配成功后,客户端连接服务器

继续在 HandleMatchedTicket 方法中添加代码:

  • 处理下当匹配成功后,开启客户端连接到 Multiverse 服务端,并将开始匹配的 UI 按钮隐藏,在场景中会出现一个 Sphere 小球对象和一个可以控制随机小球位置的按钮。

  • 在这里,我们定义一个变量 randomTeleport 表示随机小球位置的 UI 按钮。


public Button randomTeleport;//随机位置的UI按钮

private void HandleMatchedTicket(Ticket ticket)
{
//此处省略其它代码行......
switch (NetworkManager.Singleton.NetworkConfig.NetworkTransport)
{
//此处省略其它代码行......
}

// 开启客户端,连接到server
NetworkManager.Singleton.StartClient();

//隐藏匹配的按钮
startButton.gameObject.SetActive(false);
//激活随机位置的按钮
if (NetworkManager.Singleton.IsClient && NetworkManager.Singleton.LocalClient != null)
{
randomTeleport.gameObject.SetActive(true);
}
}

BootstrapManager.cs 组件上的参数 Random Teleport 选择提前创建好的按钮对象:Button_RandomTeleport。


此时再次运行游戏后,看到在 Game 窗口中出现了一个 Sphere 对象,说明客户端连接上了服务器。


4.4 匹配失败后,则重新匹配

如果匹配失败,则重新开始刚才的匹配过程。在 WaitForMatchResult 方法中,添加重新开始匹配的代码,同时会调用 Cleanup 方法来停止当前的匹配操作。

private IEnumerator WaitForMatchResult(string ticketId)
{
Ticket ticket = null;
for (var i = 0; i < matchmakingTimeoutSeconds; i++)
{
//此处省略其它代码行......
}
if (ticket is { status: MatchmakingSDK.TicketStatusMatched })
{
//此处省略其它代码行......
}
else
{
if (ticket != null) Debug.Log($"匹配失败: {ticket.assignment.msg}");
// Restore button to matchable state
startButton.transform.GetChild(0).GetComponent ().text = "开始匹配";
startButton.interactable = true;
// Match failed, throw an exception
Cleanup();
throw new Exception("Match failed");
}
}

4.5 匹配成功后,在客户端随机小球对象的位置

继续打开脚本 BootstrapManager.cs,添加新的方法 OnRandomTeleportButton,判断下如果本地客户端的玩家对象包含 BootstrapPlayer 组件,则会从客户端向服务器端发送一个远程过程调用(Server RPC),目的是将玩家传送到服务器端的一个随机位置。

//当点击随机位置的按钮响应的事件
public void OnRandomTeleportButton()
{
if (NetworkManager.Singleton.LocalClient.PlayerObject.TryGetComponent(out BootstrapPlayer bootstrapPlayer))
{
// Invoke a `ServerRpc` from client-side to teleport player to a random position on the server-side
bootstrapPlayer.RandomTeleportServerRpc();
}
}

有需要的话,可自行查看下 Netcode 示例 Demo 提供的随机位置的脚本 BootstrapPlayer.cs。这段代码定义了一个服务器远程过程调用(Server RPC)方法 RandomTeleportServerRpc,用于将调用该方法的游戏对象、传送到 XY 平面上的一个随机位置。

public class BootstrapPlayer : NetworkBehaviour
{
[ServerRpc]
public void RandomTeleportServerRpc()
{
var oldPosition = transform.position;
transform.position = GetRandomPositionOnXYPlane();
var newPosition = transform.position;
print($"{nameof(RandomTeleportServerRpc)}() -> {nameof(OwnerClientId)}: {OwnerClientId} --- {nameof(oldPosition)}: {oldPosition} --- {nameof(newPosition)}: {newPosition}");
}

private static Vector3 GetRandomPositionOnXYPlane()
{
return new Vector3(Random.Range(-3f, 3f), Random.Range(-3f, 3f), 0f);
}
}

查看场景中随机位置的 UI 按钮 Button_RandomTeleport,确保它已经提前注册绑定了方法 OnRandomTeleportButton。


然后大家可以再次点击运行测试,匹配成功以后,就可以随机小球的位置了。

4.6 启用 Websocket Proxy

如果想要在微信小游戏中使用 WebSocket 协议进行通信,需要「联系我们」,为你的项目开通「启用 Websocket Proxy」功能。

在 HandleMatchedTicket 方法中添加判断的代码,若开启了 WebSocket 代理选项,系统会自动在 WebSocketTransport 组件的 “Proxy” 这一相关配置字段中填入 WebSocket 代理服务器的地址。这一过程无需开发人员手动输入,系统将自动完成配置。

如此一来,在进行 WebSocket 通信时,便能正确连接到指定的代理服务器,进而实现预期的网络通信和功能逻辑。

private void HandleMatchedTicket(Ticket ticket)
{
    //此处省略其它代码行......

switch (NetworkManager.Singleton.NetworkConfig.NetworkTransport)
{
case WebSocketTransport:
{
//如果使用 websocket 协议,获取 WebSocketTransport 组件
var wt = NetworkManager.Singleton.GetComponent ();
if (wt == null)
{
throw new Exception("Unexpected null WebSocketTransport");
}

//填充匹配到的服务器的ip地址和端口到 WebSocketTransport 组件
Debug.Log("Using WebSocket transport");
wt.ConnectAddress = ticket.assignment.ip;
wt.Port = port;

if (!string.IsNullOrEmpty(ticket.assignment.wsProxy))
{
// 如果联系我们配置了开启websocket代理, 则填充代理地址到 WebSocketTransport 组件
Debug.Log("Using WebSocket proxy");
wt.Proxy = ticket.assignment.wsProxy;
wt.SecureConnection = true;
}
break;
}
}
}

找到场景中的 BootstrapManager 对象上的 WebSocket Transport 组件,勾选「Secure Connection」选项

如果你的项目已经开启 Websocket 代理, 运行项目后,会看到 WebSocketTransport 组件的 Proxy 参数上,已经自动填充了代理地址

4.7 增加关闭的按钮

可以在场景中增加一个 Close 的关闭,随时来关闭场景重新运行匹配功能。大家自行根据自己的需求,选择是否添加这个按钮。

创建一个新的按钮,重命名为 Button_Close,可自行设置按钮上的贴图和颜色。

将按钮上的 Text 文字设置为 X。

脚本中添加 OnClickCloseButton 方法,主要功能是点击关闭按钮时,进行资源清理、关闭网络管理器并销毁其对应的游戏对象,最后异步加载索引为 0 的场景,以实现场景的切换和资源的释放。

//需要新引入的 namespace------------------------------------
using UnityEngine.SceneManagement;
//---------------------------------------------------------

public void OnClickCloseButton()
{
Cleanup();
if (NetworkManager.Singleton)
{
NetworkManager.Singleton.Shutdown();
Destroy(NetworkManager.Singleton.gameObject);
}
SceneManager.LoadSceneAsync(0, LoadSceneMode.Single);
}

找到场景中的关闭的 UI 按钮对象 Button_Close,要确保此按钮已经在 Inspector 面板上注册绑定了:BootstrapManager 对象上的脚本 BootstrapManager.cs 中的 OnStartMatchButton 方法。


可以运行场景,再次进行测试效果。

5. 使用 KCP 协议配置并启动项目

为助力开发者在微信小游戏平台实现更优网络通信体验,我们特别提供 KCP 协议。针对微信独特的 UDP 通信环境,我们进行了深度适配工作,成功让 KCP 协议无缝融入其中,保障其在微信小游戏平台稳定且高效地运行。

5.1 选择 KCP 协议

我们再来测试下使用 KCP 协议来运行时所需要的相关配置!

再次找到场景中的对象 BootstrapManager,给其添加 Kcp 2k Transport 协议脚本组件 ,同时将 NetworkManager 组件上的 NetworkTransport 参数选择的协议修改为:Kcp 2k Transport 协议


5.2 构建并上传 Multiverse 镜像

更换协议之后,我们按照之前的步骤,重新构建新的服务器镜像来测试。

镜像标签 Image Tag 设置为:image2-kcp,然后点击「Build Image」按钮。


在 UOS 网页端的「启动配置」「镜像」这里,可以看到刚才构建的服务端程序 image2-kcp,已经自动上传了。


5.3 创建启动配置

多套启动配置可以方便管理同一服务器程序对于不同服务所需的启动参数,CPU 消耗等不同配置的需求。

同理参考使用 WebSocket Transport 协议时的操作步骤,再创建一个使用 KCP 协议的启动配置。在「启动配置」页面,点击「创建启动配置


填写配置名称,示例为 mvdemo2-kcp,然后点击「创建」


点击「添加已有镜像


接着为启动配置 mvdemo2-kcp 添加镜像配置:

  • 选择镜像:image2-kcp;

  • CPU核数:Unity 程序运行时我们还是推荐设置为 0.5 核以上;

  • 入口程序启动命令:填 server.x86_64;

  • 服务器端口:使用 KCP 协议时,服务器协议选择 UDP 协议。游戏服务器端口我们还是和 Unity 编辑器中自定义的端口号保持一致(7777)即可。

填写完后,点击「添加镜像配置」,将该镜像添加至启动配置上。

5.4 测试并应用镜像配置

接着点击「立即测试配置」,然后点击「下一步」「立即应用配置」即可。

5.5 配置 Matchmaking

进入「Matchmaking」「配置列表」页面,点击「创建 Match」按钮。

这里「Match 配置名称」就先填写 :mvdemo2-kcp 了,「玩家匹配请求超时时长」也设置为默认 60 秒。

Match 模板还是选择「自由休闲类」「快速启动」模板为例进行讲解。选择了模板后,点击「创建」

在 Match 配置的详情页中,这里的匹配信息和之前一样,不再重复解释了。

5.6 获取匹配到的服务器的 IP 地址和端口

此时也是需要先设置下,引入 Kcp Transport for Netcode 资源包的应用程序集。当添加引用后,点击「Apply」

找到脚本中的 HandleMatchedTicket 方法,继续判断:如果使用的是 KCP 协议的话,同理也是通过 Ticket 拿到匹配到的服务器的 IP 地址和端口号,然后填充到 Kcp Transport 组件上的参数 Host 和 Port。

//需要新引入的 namespace------------------------------------
using Netcode.Transports.KCP;
//--------------------------------------------------------

private void HandleMatchedTicket(Ticket ticket)
{
    //此处省略其它代码行......

switch (NetworkManager.Singleton.NetworkConfig.NetworkTransport)
{
case Kcp2kTransport:
{
//如果使用 kcp 协议,获取 Kcp2kTransport 组件
var kt = NetworkManager.Singleton.GetComponent ();
if (kt == null)
{
throw new Exception("Unexpected null Kcp2kTransport");
}

Debug.Log("Using KCP transport");

//填充匹配到的服务器的ip地址和端口到 Kcp2kTransport 组件
kt.Port = port;
kt.Host = ticket.assignment.ip;
break;
}
case WebSocketTransport:
{
//此处省略其它代码行......
break;
}
default:
throw new Exception("No suitable transport found");
}
//此处省略其它代码行......
}

进入 UOS 网页端的「Matchmaking」「配置列表」页面,找到新创建的 Matchmaking 配置:mvdemo2-kcp,复制 mvdemo2-kcp 下方的 Matchmaking 配置 ID 号。


将刚才 UOS 网页端复制的 Matchmaking 配置 ID ,粘贴到 matchmakingConfigId 参数这里。

matchmakingTimeoutSeconds 参数:还是和 Matchmaking 配置中的玩家匹配请求超时时长保持一致写 60 秒。


再次运行游戏后进行测试,查看日志信息会输出:"Using KCP transport",说明使用了 KCP 协议。

同时看到 Kcp 2k Transport 组件的 Host 和 Port 参数,也已经自动填充了匹配到的服务器的 IP 地址和 Multiverse映射后的端口号


再次刷新 UOS 网页端的服务器列表,点击服务器 UUID 值查看服务器详情,可以看到 Unity 编辑器 Inspector 面板上的服务器的 IP 与端口,和网页端的是一致的。


此时,Game 窗口的画面如下,可以正常随机位置。


6. 构建 MiniGame 项目,设置 WXSDK 打包参数

接下来我们将该 Demo 发布成微信小游戏,接着刚才的 KCP 协议继续操作。使用 Unity 引擎发布成微信小游戏的话,需要安装 WebGL 平台支持模块包和 WXSDK,然后再构建小游戏项目工程。

6.1 安装 WebGL 平台支持模块包,将项目切换至 WebGL 平台

再次打开 Unity Hub ,找到左侧的「安装」,选择自己使用的 Unity 编辑器版本,比如 2022.3.53f1c1,点击「添加模块」按钮:


在弹出窗口中「勾选 WebGL Build Support 模块,然后点击「安装」


在 UOS Launcher 面板中勾选 Weixin Minigame 选项,点击弹窗中的按钮「Switch to WebGL」


然后打开「File」「Build Settings」窗口,可以看到勾选 Weixin Minigame 选项后,Platform 已经自动帮你切换至「WebGL」平台了。

切换平台后,需要重新检查下你的 UOS Launcher 面板,查看 UOS App 是否绑定。贴图的压缩模式 Texture Compression:选择「ASTC


6.2 安装 WXSDK

在 Unity Editor 菜单栏,点击「Window」「Package Manager」,点击左上角的「+」,选择「Add package from git URL...」,输入下方的 WXSDK 的仓库 Git 资源地址,点击「Add」即可。

WXSDK 的仓库 Git 地址:

https://gitee.com/wechat-minigame/minigame-tuanjie-transform-sdk.git


等待 WXSDK 安装好以后,可以在Package Manager窗口中看到。


6.3 设置 WXSDK 的参数,构建小游戏项目工程

安装好 WXSDK 后,点击菜单栏的按钮「微信小游戏」「转换小游戏」按钮。


然后设置微信小游戏转换工具面板的参数,如下面的截图所示:


游戏AppID:可以直接从微信小游戏开发工具里点击 register 去申请正式 AppID。注册过账号以后,可以在「开发管理」「开发设置」这里看到自己的 AppID 账号,复制一下 AppID 号填入 WXSDK 的参数中。

注册链接https://mp.weixin.qq.com/wxopen/waregister?action=step1

第一次注册好的 AppID 账号,需要进行设置下是用于「小程序开发」还是「小游戏开发」

设置修改:登录小程序页面后,选择「首页」「小程序发布流程」「小程序类目」,然后点击填写添加服务类目,选择「游戏」类目,自行选择一种游戏类型即可,在这里我设置的是「休闲游戏」类型。



  • 小游戏项目名:自定义填写导出的微信小游戏项目名称,这里先写 MultiverseAndNetcode_MiniGame。

  • 游戏方向:选择根据游戏画面选择竖屏还是横屏,这里选择横屏 Landsape

  • 导出路径:这里大家自行来设置生成微信小游戏工程的位置,后续步骤会需要打开这里的小游戏目录。

  • 首包资源加载方式:由于当前项目只用到了 Multiverse 和 Matchmaking 服务,没有使用到 CDN 服务,所以先将首包的资源加载方式设置为「小游戏包内」加载。

  • 压缩首包资源:由于场景中 UI 用到了背景图资源,却未使用 CDN 上传资源,直接打包的话会提示首包资源太大。所以我们这里可以勾选下「压缩首包资源」选项。

  • WebGL2.0(beta):这里参数打勾。

  • 显示优化建议弹窗:这里先不打勾,后面在微信开发者工具中运行测试项目时,就暂时不让它自动弹出优化提示的窗口。如果需要时,可以再勾选。

  • 最后,点击「生成并转换」的按钮,开始打包项目,等到转换成功后,会看到小游戏导出路径下的文件如图所示:

7. 在微信开发者工具运行测试

7.1 下载微信开发者工具

如果你还没有下载过微信开发者工具的话,可以前往微信官方网站进行下载微信开发者工具, 并安装到本地电脑上。

https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

7.2 在微信开发者工具中导入小游戏项目

打开安装好的微信开发者工具,选择「小游戏」类型,导入你的项目。「目录」这里选择之前在 WXSDK 的参数面板中设置的导出路径:

MultiverseAndNetcode_minigame/minigame 路径文件夹。

注意不要选错了目录哦!路径一定要选择到 minigame 路径文件夹!!!

当选择完目录以后,会自动加载填入你在 Unity 编辑器内设置的导出的小游戏项目名称的,不需要自己填写。然后选择你的 AppID,最后点击「确定」按钮即可。

接着在 Unity 编辑器里和微信开发者工具中,我们都点击「开始匹配」按钮,匹配成功后,会看到都出现了 Sphere 游戏对象,点击随机位置,可以看到这两个对象在场景中的 Transform 组件的数据信息都是同步的。

7.3 设置域名

如果此时,想要在手机上扫描二维码进行真机预览小游戏效果的话,还需要进行相关域名的设置。如果大家想知道自己缺少的域名,可以在微信开发者工具里强制开启白名单调试:

  • 打开「设置->项目设置」面板,选择「本地设置」取消勾选”不校验合法域名、网络视图(业务域名)、TLS 版本以及 HTTPS 证书“(默认是勾选状态,表示默认不进行校验域名)。

可以进入 UOS 官网,在网页上的 QA 的「4 .小程序/小游戏需要用到的域名白名单」这里,找到项目中使用到的 服务对应的域名,然后复制域名。 https://uos.unity.cn/doc/others/qa#4

  • Matchmaking 服务对应的域名——https://m.unity.cn

  • Passp...

ad1 webp
ad2 webp
ad1 webp
ad2 webp