创建会话
基于上篇配置steam在线子系统之后,在Character.h中声明一个会话创建完成时的委托以及回调函数。
#include "Interfaces/OnlineSessionInterface.h"public://指向在线会话界面的指针,将会话接口存储在里面TSharedPtr<class IOnlineSession, ESPMode::ThreadSafe> OnlineSessionInterface;protected://创建游戏会话UFUNCTION(BlueprintCallable)void CreateGameSession();//回调函数,用于处理会话创建完成时的逻辑void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful);private://声明会话创建完成时的委托FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate;
在Character.cpp的构造函数中绑定委托
//绑定会话创建完成委托CreateSessionCompleteDelegate.BindUObject(this, &ThisClass::OnCreateSessionComplete);
添加创建会话逻辑,将结果打印到屏幕
OnlineSessionInterface->GetNamedSession(NAME_GameSession):获取会话
OnlineSessionInterface->DestroySession(NAME_GameSession):销毁会话
OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate):添加会话到列表
TSharedPtr<FOnlineSessionSettings> SessionSettings 游戏会话设置
GetWorld()->GetFirstLocalPlayerFromController():获取本地玩家
OnlineSessionInterface->CreateSession:创建会话,参数:网络id,会话名,会话设置
World->ServerTravel():进行服务器旅行
#include "OnlineSessionSettings.h"void AMenuSystemCharacter::CreateGameSession() {if (!OnlineSessionInterface.IsValid()){return;}//通过NAME_GameSession创建一个临时会话FNamedOnlineSession* ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession);if (ExistingSession != nullptr){//销毁之前的会话OnlineSessionInterface->DestroySession(NAME_GameSession);}//将委托添加到句柄中OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate);//修改游戏会话设置TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings());SessionSettings->bIsLANMatch = false;SessionSettings->NumPublicConnections = 4;SessionSettings->bAllowJoinInProgress = true;SessionSettings->bAllowJoinViaPresence = true;SessionSettings->bShouldAdvertise = true;SessionSettings->bUsesPresence = true;//获取本地玩家const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();//将本地玩家的id作为会话房主OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *SessionSettings);}void AMenuSystemCharacter::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful) {if (bWasSuccessful){if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Blue,FString::Printf(TEXT("Created Session: %s"), *SessionName.ToString()));}//打开一个空白地图作为服务器大厅UWorld* World = GetWorld();if (World){World->ServerTravel(FString("/Game/ThirdPerson/Maps/Lobby?listen"));}}else{if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Red,FString(TEXT("Fail to create session")));}} }
查找会话
在Character.h中添加查找结束委托以及回调函数
//加入游戏会话UFUNCTION(BlueprintCallable)void JoinGameSession();void OnFindSessionsComplete(bool bWasSuccessful);//声明查找会话完成时的委托FOnFindSessionsCompleteDelegate FindSessionCompleteDelegate;//会话搜索结果TSharedPtr<FOnlineSessionSearch> SessionSearch;
在Character.cpp中,构造函数中绑定委托
FindSessionCompleteDelegate.BindUObject(this, &ThisClass::OnFindSessionsComplete);
OnlineSessionInterface->FindSessions:查找会话
void AMenuSystemCharacter::JoinGameSession() {if (!OnlineSessionInterface.IsValid()){return;}OnlineSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegate);SessionSearch = MakeShareable(new FOnlineSessionSearch());SessionSearch->MaxSearchResults = 10000;SessionSearch->bIsLanQuery = false;SessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();OnlineSessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), SessionSearch.ToSharedRef());}void AMenuSystemCharacter::OnFindSessionsComplete(bool bWasSuccessful) {if (!OnlineSessionInterface.IsValid()){return;}for (FOnlineSessionSearchResult Result : SessionSearch->SearchResults){FString Id = Result.GetSessionIdStr();FString User = Result.Session.OwningUserName;if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Cyan,FString::Printf(TEXT("Id: %s ,User: %s"),*Id, *User));}} }
加入会话
在Character.h中添加 加入会话结束时的委托和回调
//加入会话结束时的委托FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate;void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result);
在构造函数中绑定委托
JoinSessionCompleteDelegate.BindUObject(this, &ThisClass::OnJoinSessionComplete);
在查找会话阶段的OnFindSessionComplete回调函数中,判断找到的会话类型是否和创建的会话类型一样,如果一样的话就加入会话
Result.Session.SessionSettings.Get(FName("MatchType"), MatchType):获取会话类型
OnlineSessionInterface->JoinSession:加入会话
void AMenuSystemCharacter::OnFindSessionsComplete(bool bWasSuccessful) {if (!OnlineSessionInterface.IsValid()){return;}for (FOnlineSessionSearchResult Result : SessionSearch->SearchResults){FString Id = Result.GetSessionIdStr();FString User = Result.Session.OwningUserName;if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Cyan,FString::Printf(TEXT("Id: %s ,User: %s"),*Id, *User));}//----------判断会话类型FString MatchType;Result.Session.SessionSettings.Get(FName("MatchType"), MatchType);if (MatchType == FString("FreeForAll")){if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Cyan,FString::Printf(TEXT("Joining Match Type: %s"), *MatchType));}//加入会话OnlineSessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegate);const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();OnlineSessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, Result);}} }
在加入会话结束的回调函数中
GetGameInstance()->GetFirstLocalPlayerController():获取本地玩家控制器
PlayerController->ClientTravel:作为客户端旅行
void AMenuSystemCharacter::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result) {if (!OnlineSessionInterface.IsValid()){return;}FString Address;if (OnlineSessionInterface->GetResolvedConnectString(NAME_GameSession,Address)){if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Yellow,FString::Printf(TEXT("Connect String : %s"), *Address));}APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController();if (PlayerController){PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute);}} }
结果:
玩家1通过按“1”将自己的id作为会话房主,创建一个会话,打开一个空白地图作为服务大厅,玩家2通过按“2”找到类型匹配的会话并以客户端旅行加入会话,
玩家1在蓝图中通过按键“1”进行调试,调用CreateGameSession函数。
玩家2在蓝图中通过按键“2”进行调试,调用JoinGameSession函数
(1)如果是打包出来给两台电脑测试的话,首先需要保证Steam在后台运行,两个不同的steam账号下载地址最好改成一样的。然后一台电脑按1创建房间,另外一台电脑按2加入房间。
(2)如果只有一台电脑测试的话,要将steam退出后台,然后在编辑器中选择“独立进程游戏”,玩家数量改为2。使用局域网来完成,一个玩家按1创建房间,另外一个玩家按2加入房间
如果一直显示无法创建成功的话,需要将DefaultEngin.ini文件进行修改
完整代码
character.h
#include "Interfaces/OnlineSessionInterface.h"public://指向在线会话界面的指针,将会话接口存储在里面TSharedPtr<class IOnlineSession, ESPMode::ThreadSafe> OnlineSessionInterface;protected://创建游戏会话UFUNCTION(BlueprintCallable)void CreateGameSession();//加入游戏会话UFUNCTION(BlueprintCallable)void JoinGameSession();//回调函数,用于处理会话创建完成时的逻辑void OnCreateSessionComplete(FName SessionName, bool bWasSuccessful);void OnFindSessionsComplete(bool bWasSuccessful);void OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result);private://声明会话创建完成时的委托FOnCreateSessionCompleteDelegate CreateSessionCompleteDelegate;//声明查找会话完成时的委托FOnFindSessionsCompleteDelegate FindSessionCompleteDelegate;//加入会话结束时的委托FOnJoinSessionCompleteDelegate JoinSessionCompleteDelegate;//会话搜索结果TSharedPtr<FOnlineSessionSearch> SessionSearch;
Character.CPP
#include "Kismet/GameplayStatics.h" #include "OnlineSubsystem.h" #include "OnlineSessionSettings.h"//构造函数 AMenuSystemCharacter::AMenuSystemCharacter() {//绑定会话创建完成委托CreateSessionCompleteDelegate.BindUObject(this, &ThisClass::OnCreateSessionComplete);FindSessionCompleteDelegate.BindUObject(this, &ThisClass::OnFindSessionsComplete);JoinSessionCompleteDelegate.BindUObject(this, &ThisClass::OnJoinSessionComplete); }//创建会话 void AMenuSystemCharacter::CreateGameSession() {if (!OnlineSessionInterface.IsValid()){return;}//通过NAME_GameSession创建一个临时会话FNamedOnlineSession* ExistingSession = OnlineSessionInterface->GetNamedSession(NAME_GameSession);if (ExistingSession != nullptr){//销毁之前的会话OnlineSessionInterface->DestroySession(NAME_GameSession);}//将委托添加到句柄中OnlineSessionInterface->AddOnCreateSessionCompleteDelegate_Handle(CreateSessionCompleteDelegate);//修改游戏会话设置TSharedPtr<FOnlineSessionSettings> SessionSettings = MakeShareable(new FOnlineSessionSettings());SessionSettings->bIsLANMatch = false;SessionSettings->NumPublicConnections = 4;SessionSettings->bAllowJoinInProgress = true;SessionSettings->bAllowJoinViaPresence = true;SessionSettings->bShouldAdvertise = true;SessionSettings->bUsesPresence = true;SessionSettings->bUseLobbiesIfAvailable = true;//设置一个键值队。当找到会话的时候需要检查一下会话类型是否和创建的会话一样SessionSettings->Set(FName("MatchType"), FString("FreeForAll"), EOnlineDataAdvertisementType::ViaOnlineServiceAndPing);//获取本地玩家const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();//将本地玩家的id作为会话房主OnlineSessionInterface->CreateSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, *SessionSettings);}//创建会话完成时的回调函数 void AMenuSystemCharacter::OnCreateSessionComplete(FName SessionName, bool bWasSuccessful) {if (bWasSuccessful){if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Blue,FString::Printf(TEXT("Created Session: %s"), *SessionName.ToString()));}//打开一个空白地图作为大厅UWorld* World = GetWorld();if (World){World->ServerTravel(FString("/Game/ThirdPerson/Maps/Lobby?listen"));}}else{if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Red,FString(TEXT("Fail to create session")));}} }//查找会话 void AMenuSystemCharacter::JoinGameSession() {if (!OnlineSessionInterface.IsValid()){return;}OnlineSessionInterface->AddOnFindSessionsCompleteDelegate_Handle(FindSessionCompleteDelegate);SessionSearch = MakeShareable(new FOnlineSessionSearch());SessionSearch->MaxSearchResults = 10000;SessionSearch->bIsLanQuery = false;SessionSearch->QuerySettings.Set(SEARCH_PRESENCE, true, EOnlineComparisonOp::Equals);const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();OnlineSessionInterface->FindSessions(*LocalPlayer->GetPreferredUniqueNetId(), SessionSearch.ToSharedRef());}//查找会话完成时的回调函数 void AMenuSystemCharacter::OnFindSessionsComplete(bool bWasSuccessful) {if (!OnlineSessionInterface.IsValid()){return;}for (FOnlineSessionSearchResult Result : SessionSearch->SearchResults){FString Id = Result.GetSessionIdStr();FString User = Result.Session.OwningUserName;if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Cyan,FString::Printf(TEXT("Id: %s ,User: %s"), *Id, *User));}//----------判断会话类型FString MatchType;Result.Session.SessionSettings.Get(FName("MatchType"), MatchType);if (MatchType == FString("FreeForAll")){if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Cyan,FString::Printf(TEXT("Joining Match Type: %s"), *MatchType));}//加入会话,OnlineSessionInterface->AddOnJoinSessionCompleteDelegate_Handle(JoinSessionCompleteDelegate);const ULocalPlayer* LocalPlayer = GetWorld()->GetFirstLocalPlayerFromController();OnlineSessionInterface->JoinSession(*LocalPlayer->GetPreferredUniqueNetId(), NAME_GameSession, Result);}} }//加入会话完成时的回调函数 void AMenuSystemCharacter::OnJoinSessionComplete(FName SessionName, EOnJoinSessionCompleteResult::Type Result) {if (!OnlineSessionInterface.IsValid()){return;}FString Address;if (OnlineSessionInterface->GetResolvedConnectString(NAME_GameSession,Address)){if (GEngine){GEngine->AddOnScreenDebugMessage(-1,15.f,FColor::Yellow,FString::Printf(TEXT("Connect String : %s"), *Address));}APlayerController* PlayerController = GetGameInstance()->GetFirstLocalPlayerController();if (PlayerController){PlayerController->ClientTravel(Address, ETravelType::TRAVEL_Absolute);}} }