本文为B站系列教学视频 《UE5_C++多人TPS完整教程》 —— 《P10 创建会话(Creating A Session)》 的学习笔记,该系列教学视频为 Udemy 课程 《Unreal Engine 5 C++ Multiplayer Shooter》 的中文字幕翻译版,UP主(也是译者)为 游戏引擎能吃么。
文章目录
- P10 创建会话
- 10.1 委托
- 10.2 创建委托以及回调函数
- 10.3 Summary
P10 创建会话
本节课将学习委托(Delegates)的基本概念、工作原理以及它对于管理多人游戏的关键(Crucial)作用,然后我们将在上节课《P9 访问 Steam(Acessing Steam)》 代码的基础上,尝试创建一个游戏会话,并通过在屏幕上打印文本来验证游戏会话是否创建成功。
10.1 委托
-
委托可以被认为是一个持有对函数的引用(Reference)的对象。虚幻引擎的委托可以与函数 绑定(Having functions bound to them),可以 广播到 所有与它绑定的函数接收并执行以进行 响应 的信号。我们通常会编写 回调函数(Make functions referred to as callback functions)然后将它们绑定到委托上。于是,当游戏中的某个确定事件(Certain event)发生时,委托被触发或者广播,任何绑定在该委托的 回调函数 都将进行响应。
-
虚幻引擎的在线会话需要利用委托,这是因为创建和加入游戏会话都需要在互联网上发送信息。如果我们调用 会话接口(Session interface)函数 “
CreateSession()
” 就会发送信息到服务平台(本课程为Steam
),此时游戏会话就能被创建,然后服务平台将(反馈)信息发送到我们的设备上,让我们知道会话创建已经完成。
会话接口(Session interface)定义了一组委托类型,拥有一个可以在适当的时间内通过事件触发进行遍历的 委托列表(Delegate list),我们将以其中一个委托类型创建一个新对象,为它绑定一个回调函数,并添加到会话接口的委托列表中。
-
本节课的思路就是首先利用函数 “
FOnCreateSessionCompleteDelegate
” 在第三人称游戏项目MenuSystem
的character
类中创建委托(变量),同时也创建一个绑定到该委托的回调函数 “OnCreateSessionComplete()
”,接着访问会话接口并添加委托到委托列表中;然后调用会话接口函数 “CreateSession()
” 连接到Steam
以创建游戏会话,游戏会话创建完成后Steam
向会话接口发送一个信号,会话接口将遍历委托列表,从而触发我们添加到此列表的委托并导致回调函数 “OnCreateSessionComplete()
” 被调用并接收游戏会话创建完成的信息;通过打印信息到屏幕上,就可以验证会话是否真的创建成功。
关于委托的更多知识可以参阅官方文档《委托》。
10.2 创建委托以及回调函数
-
添加代码到 “
MenuSystemcharacter.h
” 的类 “AMenuSystemCharacter
” 中,定义委托CreateSessionCompleteDelegate
、创建游戏会话函数CreateGameSession()
以及委托的回调函数OnCreateSessionComplete()
:...#include "Interfaces/OnlineSessionInterface.h"...UCLASS(config=Game) class AMenuSystemCharacter : public ACharacter {.../* P10 创建会话(Creating A Session)*/ public:// 会话接口智能指针// IOnlineSessionPtr OnlineSessionInterface; // 添加头文件 "Interfaces/OnlineSessionInterface.h" 后使用,更具可读性TSharedPtr<class IOnlineSession, ESPMode::ThreadSafe> OnlineSessionInterface; // 使用 TSharedPtr 智能指针包装器进行声明protected:UFUNCTION(BlueprintCallable)void CreateGameSession(); // 创建游戏会话void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful); // 委托 CreateSessionCompleteDelegate 的回调函数private:// 类 FOnCreateSessionCompleteDelegate 在 UE 5.0 和 5.1 版本的头文件 "Interfaces/OnlineSessionInterface.h" 中声明// 而 5.2 和 5.3 版本的头文件 "Interfaces/OnlineSessionDelegates.h" 中声明FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate; // 会话创建完成委托/* P10 创建会话(Creating A Session)*/ };
-
在 “
MenuSystemcharacter.cpp
” 构造函数 “AMenuSystemCharacter::AMenuSystemCharacter()
” 中为委托 “CreateSessionCompleteDelegate
” 绑定回调函数 “OnCreateSessionComplete()
” 并完成创建游戏会话函数CreateGameSession()
的定义。/* MenuSystemcharacter.h */ ... /* P10 创建会话(Creating A Session)*/ #include "OnlineSessionSettings.h" /* P10 创建会话(Creating A Session)*/ .../* MenuSystemcharacter.cpp */ .../* P10 创建会话(Creating A Session)*/ AMenuSystemCharacter::AMenuSystemCharacter(): // 为委托绑定回调函数 CreateSessionCompleteDelegate(FOnCreateSessionCompleteDelegate::CreateUObject(this, &ThisClass::OnCreateSessionComplete)) /* P10 创建会话(Creating A Session)*/ {...}/* P10 创建会话(Creating A Session)*/ void AMenuSystemCharacter::CreateGameSession() // 当按下数字键 1 时调用 {// 检查会话接口是否有效if (!OnlineSessionInterface.IsValid()) {return;}// 检查是否先前存在会话auto ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession);if (ExistingSession != nullptr) { // 如果先前存在会话OnlineSessionInterface->DestroySession(NAME_GameSession); // 销毁会话}OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate); // 添加委托到会话接口的委托列表TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings()); // 创建会话设置,利用函数 MakeShareable 初始化// FOnlineSessionSettings 在头文件 "OnlineSessionSettings.h" 中// 会话设置成员变量参阅及含义:https://docs.unrealengine.com/5.3/en-US/API/Plugins/OnlineSubsystem/FOnlineSessionSettings/SessionSettings->bIsLANMatch = false; // 会话设置:不创建 LAN 连接SessionSettings->NumPublicConnections = 4; // 会话设置:设置最大公共连接数为 4SessionSettings->bAllowJoinInProgress = true; // 会话设置:在会话运行时允许其他玩家加入SessionSettings->bAllowJoinViaPresence = true; // 会话设置:Steam 使用 Presence 搜索会话所在地区,确保连接正常工作SessionSettings->bShouldAdvertise = true; // 会话设置:允许 Steam 发布会话SessionSettings->bUsesPresence = true; // 会话设置:允许显示用户 Presence 信息SessionSettings->bUseLobbiesIfAvailable = true; // (视频中未提及)会话设置:优先选择 Lobby API(Steam 支持 Lobby API)const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController(); // 获取本地玩家指针OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), // 第一个参数类型为 strut FUniqueNetIdRepl,公共继承了 struct FUniqueNetIdWrapper// 这个包装器重载了引用运算符 *,它表示 * 返回一个引用 *UniquenetIdNAME_GameSession, // 第二个参数类型为 FName SessionName,游戏会话名称*SessionSettings); // 第三个参数类型为 const FOnlineSessionSettings &NewSessionSettings } /* P10 创建会话(Creating A Session)*/...
会话设置代码
SessionSettings->bUseLobbiesIfAvailable = true
在视频中是没有提及的,如果在后面的测试出现无法创建会话,则需要添加(作者在下一集教学视频 《P11 设置加入会话(Setup for Joining Sessions)》 中会提到这点)。
-
继续在 “
MenuSystemcharacter.cpp
” 构造函数 “AMenuSystemCharacter::AMenuSystemCharacter()
” 中完成回调函数OnCreateSessionComplete()
的定义。.../* P10 创建会话(Creating A Session)*/ void AMenuSystemCharacter::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful) {if (bWasSuccessful) { // 如果游戏会话创建成功if (GEngine) {GEngine->AddOnScreenDebugMessage( // 添加调试信息到屏幕上-1, // 使用 -1 不会覆盖前面的调试信息15.f, // 调试信息的显示时间FColor::Red, // 字体颜色FString::Printf(TEXT("Create session: %s!"), *SessionName.ToString()) // 打印游戏会话的名称);}}else { // 如果游戏会话创建失败if (GEngine) { GEngine->AddOnScreenDebugMessage( // 添加调试信息到屏幕上-1, // 使用 -1 不会覆盖前面的调试信息15.f, // 调试信息的显示时间FColor::Red, // 字体颜色FString::Printf(TEXT("Failed to create session!")) // 打印失败消息);}} } /* P10 创建会话(Creating A Session)*/...
-
进行实时编译,编译成功后打开 “
BP_ThirdPersonCharacter
” 蓝图编辑器,绘制如下蓝图,编译、保存。
-
将项目打包之后再运行游戏(保证
Steam
已经运行),按下数字键 “1”,屏幕左上角红色字体显示会话的名称 “Game Session
” ,说明创建会话成功。
10.3 Summary
本节课学习委托(Delegates)的基本概念、工作原理以及它对于管理多人游戏的关键(crucial)作用,在创建会话的 C++ 编程中,首先利用函数 “FOnCreateSessionCompleteDelegate
” 创建委托,接着创建一个绑定到该委托的回调函数 “OnCreateSessionComplete()
”,访问会话接口并添加该委托到委托列表中;然后调用会话接口函数 “CreateSession()
” 连接到 Steam
以创建游戏会话,游戏会话创建完成后 Steam
向会话接口发送一个信号,会话接口遍历委托列表,触发我们添加到此列表的委托并导致回调函数 “OnCreateSessionComplete()
” 被调用,接收游戏会话创建完成的信息,我们将其打印在屏幕上。
在 10.1 委托 中,有关委托的进一步学习可以参阅官方文档《委托》。
在 10.2 创建委托以及回调函数 的 步骤 2 中,会话设置代码 SessionSettings->bUseLobbiesIfAvailable = true
在视频中是没有提及的,如果在后面的测试出现无法创建会话,则需要添加。