UEC++学习(十五)创建、查找、加入会话

 创建会话

基于上篇配置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());
	//如果不使用steam的话就用本地连接
	SessionSettings->bIsLANMatch = IOnlineSubsystem::Get()->GetSubsystemName() == "NULL" ? true: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文件进行修改

设置游戏的最大人数,在DefaultGame.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);
		}
	}
}

UE4 C++中,你可以通过继承自`AActor`类的子类来创建自定义的`UserWidget`,这种类可以用来创建复杂的UI元素,包括血条。以下是一个简单的示例说明如何创建一个名为`AHudHealthBar`的血条UI: ```cpp // 包含必要的头文件 #include "Components/StaticMeshComponent.h" #include "Engine/UserWidget.h" #include "HudHealthBar.generated.h" // 定义一个新类,继承自UUserWidget UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent)) class YOURPROJECT_API AHudHealthBar : public AActor, public UUserWidget { public: GENERATED_BODY() private: // 血条UI的组成部分 UPROPERTY(EditAnywhere) USkeletalMeshComponent* HealthBarMesh; // 进度条组件 UPROPERTY(EditAnywhere) class SProgressBar* ProgressBar; public: // 构造函数 AHudHealthBar(); protected: virtual void BeginPlay() override; public: virtual bool SupportsWidgetInteractionInput() const override { return true; } // 更新血条值 void UpdateHealth(int32 Value); // 接受用户的输入更新血条 virtual bool UserInteraction(const FGeometry& MyGeometry, FInputEvent MouseEvent) override; // 在每次渲染时更新UI virtual void Tick(float DeltaTime) override; }; ``` 在这个例子中,我们首先声明了两个成员变量:一个`USkeletalMeshComponent`用于绘制基本的血条外观,一个`SProgressBar`用于显示血量进度。`BeginPlay()`函数在开始游戏时会调用,`SupportsWidgetInteractionInput()`用于允许用户与血条交互。 `UpdateHealth()`方法接收新的生命值,而`UserInteraction()`处理鼠标交互,将用户的动作映射到血条的更新。`Tick()`方法会在每个游戏帧上调用,用来持续更新UI。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值