《UE5_C++多人TPS完整教程》学习笔记9 ——《P10 创建会话(Creating A Session)》


本文为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)》 代码的基础上,尝试创建一个游戏会话,并通过在屏幕上打印文本来验证游戏会话是否创建成功。
《UE5_C++多人TPS完整教程》学习笔记9 ——《P10 创建会话(Creating A Session)》_第1张图片


10.1 委托

  1. 委托可以被认为是一个持有对函数的引用(Reference)的对象。虚幻引擎的委托可以与函数 绑定(Having functions bound to them),可以 广播到 所有与它绑定的函数接收并执行以进行 响应 的信号。我们通常会编写 回调函数(Make functions referred to as callback functions)然后将它们绑定到委托上。于是,当游戏中的某个确定事件(Certain event)发生时,委托被触发或者广播,任何绑定在该委托的 回调函数 都将进行响应。
    《UE5_C++多人TPS完整教程》学习笔记9 ——《P10 创建会话(Creating A Session)》_第2张图片

  2. 虚幻引擎的在线会话需要利用委托,这是因为创建和加入游戏会话都需要在互联网上发送信息。如果我们调用 会话接口Session interface)函数 “CreateSession()” 就会发送信息到服务平台(本课程为 Steam),此时游戏会话就能被创建,然后服务平台将(反馈)信息发送到我们的设备上,让我们知道会话创建已经完成。
    会话接口Session interface)定义了一组委托类型,拥有一个可以在适当的时间内通过事件触发进行遍历的 委托列表Delegate list),我们将以其中一个委托类型创建一个新对象,为它绑定一个回调函数,并添加到会话接口的委托列表中。
    《UE5_C++多人TPS完整教程》学习笔记9 ——《P10 创建会话(Creating A Session)》_第3张图片

  3. 本节课的思路就是首先利用函数 “FOnCreateSessionCompleteDelegate” 在第三人称游戏项目 MenuSystemcharacter 类中创建委托(变量),同时也创建一个绑定到该委托的回调函数 “OnCreateSessionComplete()”,接着访问会话接口并添加委托到委托列表中;然后调用会话接口函数 “CreateSession()” 连接到 Steam 以创建游戏会话,游戏会话创建完成后 Steam 向会话接口发送一个信号,会话接口将遍历委托列表,从而触发我们添加到此列表的委托并导致回调函数 “OnCreateSessionComplete()” 被调用并接收游戏会话创建完成的信息;通过打印信息到屏幕上,就可以验证会话是否真的创建成功。
    《UE5_C++多人TPS完整教程》学习笔记9 ——《P10 创建会话(Creating A Session)》_第4张图片

    关于委托的更多知识可以参阅官方文档《委托》。


10.2 创建委托以及回调函数

  1. 添加代码到 “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)*/	
    
    };
    
  2. 在 “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;		// 会话设置:设置最大公共连接数为 4
    	SessionSettings->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
    																					// 这个包装器重载了引用运算符 *,它表示 * 返回一个引用 *UniquenetId
    										  NAME_GameSession,							// 第二个参数类型为 FName SessionName,游戏会话名称
    										  *SessionSettings);						// 第三个参数类型为 const FOnlineSessionSettings &NewSessionSettings										 	
    }
    /* P10 创建会话(Creating A Session)*/
    
    ...
    

    会话设置代码 SessionSettings->bUseLobbiesIfAvailable = true 在视频中是没有提及的,如果在后面的测试出现无法创建会话,则需要添加(作者在下一集教学视频 《P11 设置加入会话(Setup for Joining Sessions)》 中会提到这点)。

  3. 继续在 “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)*/
    
    ...
    
  4. 进行实时编译,编译成功后打开 “BP_ThirdPersonCharacter” 蓝图编辑器,绘制如下蓝图,编译、保存。
    《UE5_C++多人TPS完整教程》学习笔记9 ——《P10 创建会话(Creating A Session)》_第5张图片

  5. 将项目打包之后再运行游戏(保证 Steam 已经运行),按下数字键 “1”,屏幕左上角红色字体显示会话的名称 “Game Session” ,说明创建会话成功。


10.3 Summary

本节课学习委托(Delegates)的基本概念、工作原理以及它对于管理多人游戏的关键(crucial)作用,在创建会话的 C++ 编程中,首先利用函数 “FOnCreateSessionCompleteDelegate” 创建委托,接着创建一个绑定到该委托的回调函数 “OnCreateSessionComplete()”,访问会话接口并添加该委托到委托列表中;然后调用会话接口函数 “CreateSession()” 连接到 Steam 以创建游戏会话,游戏会话创建完成后 Steam 向会话接口发送一个信号,会话接口遍历委托列表,触发我们添加到此列表的委托并导致回调函数 “OnCreateSessionComplete()” 被调用,接收游戏会话创建完成的信息,我们将其打印在屏幕上。
《UE5_C++多人TPS完整教程》学习笔记9 ——《P10 创建会话(Creating A Session)》_第6张图片

10.1 委托 中,有关委托的进一步学习可以参阅官方文档《委托》。

10.2 创建委托以及回调函数步骤 2 中,会话设置代码 SessionSettings->bUseLobbiesIfAvailable = true 在视频中是没有提及的,如果在后面的测试出现无法创建会话,则需要添加。


你可能感兴趣的:(#,ue5,c++,游戏)