创建会话
基于上篇配置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); } } }