虚幻引擎UE5专用服务器游戏开发-19 设置头顶状态条可见性控制

头顶状态条的动态显示控制。状态条会根据与玩家角色的距离(默认300单位)进行自动隐藏,并通过定时器(默认0.2秒频率)持续检测距离变化。当角色由本地玩家控制时,状态条会自动隐藏。代码采用服务器-客户端初始化架构,并包含碰撞设置、组件创建等基础角色配置。

Source/Crunch/Public/Character/CCharacter.h:

变量:

cpp 复制代码
	//计时器频率
	UPROPERTY(EditDefaultsOnly, Category="UI")
	float CheakUpdateRate = 0.2f;

	//状态条可见距离
	UPROPERTY(EditDefaultsOnly, Category="UI")
	float CheakUpdateDistance = 300.f;

	// 距离检测计时器句柄
	FTimerHandle VisibilityCheckTimerHandle;

函数:

cpp 复制代码
	//检测状态条可见性
	void UpdateHeadGaugeVisibility();

Source/Crunch/Private/Character/CCharacter.cpp:

cpp 复制代码
		GetWorldTimerManager().ClearTimer(VisibilityCheckTimerHandle);
		GetWorldTimerManager().SetTimer(VisibilityCheckTimerHandle, this, &ACCharacter::UpdateHeadGaugeVisibility, CheakUpdateRate, true);
cpp 复制代码
void ACCharacter::UpdateHeadGaugeVisibility()
{
	//测算距离
	APawn* PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
	if (!PlayerPawn) return;
	float Distance = FVector::DistSquared(GetActorLocation(), PlayerPawn->GetActorLocation());
	//隐藏状态条
	OverHeadWidgetComponent->SetHiddenInGame(Distance > CheakUpdateDistance*CheakUpdateDistance);
}

源码:

Source/Crunch/Public/Character/CCharacter.h:

cpp 复制代码
// Copyright@ChenChao

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AbilitySystemInterface.h"
#include "CCharacter.generated.h"

class UWidgetComponent;
class UCAbilitySystemComponent;
class UCAttributeSet;

UCLASS(Abstract)
class CRUNCH_API ACCharacter : public ACharacter, public IAbilitySystemInterface
{
	GENERATED_BODY()

public:
	
	ACCharacter();
	// 只有服务器调用的方法
	virtual void PossessedBy(AController* NewController) override;
	
	void ServerSideInit();		//服务器端初始化
	void ClientSideInit();		//客户端初始化
	
protected:
	
	virtual void BeginPlay() override;
	
	/********************************************************************************/
	/*                             GameplayAbilitySystem                            */
	/********************************************************************************/
public:
	virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
	
private:
	UPROPERTY(VisibleDefaultsOnly, Category="GamePlay Ability")
	TObjectPtr<UCAbilitySystemComponent> CAbilitySystemComponent;
	
	UPROPERTY(VisibleDefaultsOnly, Category="GamePlay Ability")
	TObjectPtr<UCAttributeSet> CAttributeSet;
	
	/********************************************************************************/
	/*                                       UI                                     */
	/********************************************************************************/
private:
	//控制头顶状态部件
	void ConfigureOverHeadStateWidget();

	//判断是否有本地玩家控制
	bool IsLocallyControlledByPlayer() const;

	//检测状态条可见性
	void UpdateHeadGaugeVisibility();
private:
	UPROPERTY(VisibleDefaultsOnly, Category="UI")
	TObjectPtr<UWidgetComponent> OverHeadWidgetComponent;		//小部件组件

	//计时器频率
	UPROPERTY(EditDefaultsOnly, Category="UI")
	float CheakUpdateRate = 0.2f;

	//状态条可见距离
	UPROPERTY(EditDefaultsOnly, Category="UI")
	float CheakUpdateDistance = 300.f;

	// 距离检测计时器句柄
	FTimerHandle VisibilityCheckTimerHandle;
	
};

Source/Crunch/Private/Character/CCharacter.cpp:

cpp 复制代码
// Copyright@ChenChao


#include "Character/CCharacter.h"

#include "Components/WidgetComponent.h"
#include "GAS/CAbilitySystemComponent.h"
#include "GAS/CAttributeSet.h"
#include "Kismet/GameplayStatics.h"
#include "UI/Widget/OverHeadStateGauge.h"

// Sets default values
ACCharacter::ACCharacter()
{
 	// Set this character to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	// 网格体无碰撞
	GetMesh()->SetCollisionEnabled(ECollisionEnabled::NoCollision);

	//添加组件
	CAbilitySystemComponent = CreateDefaultSubobject<UCAbilitySystemComponent>(TEXT("CAbilitySystemComponent"));
	CAttributeSet = CreateDefaultSubobject<UCAttributeSet>(TEXT("CAttributeSet"));

	OverHeadWidgetComponent = CreateDefaultSubobject<UWidgetComponent>(TEXT("OverHeadWidgetComponent"));
	OverHeadWidgetComponent->SetupAttachment(GetRootComponent());
}

void ACCharacter::PossessedBy(AController* NewController)
{
	Super::PossessedBy(NewController);
	// AI控制的角色
	if (NewController && !NewController->IsPlayerController())
	{	
		ServerSideInit();
	}
}

void ACCharacter::ServerSideInit()
{
	CAbilitySystemComponent->InitAbilityActorInfo(this, this);	//应用能力系统组件前都要初始化
	CAbilitySystemComponent->ApplyInitialEffects();		//效果初始化
}

void ACCharacter::ClientSideInit()
{
	CAbilitySystemComponent->InitAbilityActorInfo(this, this);	//应用能力系统组件前都要初始化
}

UAbilitySystemComponent* ACCharacter::GetAbilitySystemComponent() const
{
	return CAbilitySystemComponent;
}

void ACCharacter::ConfigureOverHeadStateWidget()
{
	if (!OverHeadWidgetComponent)
	{
		UE_LOG(LogTemp, Error, TEXT("OverHeadWidgetComponent is NULL"));
		return;
	}
	//如果是本地玩家控制的角色,不显示状态条
	if (IsLocallyControlledByPlayer())
	{
		OverHeadWidgetComponent->SetHiddenInGame(true);
		return;
	}
	//得到小部件:头顶属性条
	UOverHeadStateGauge* OverHeadStateGauge = Cast<UOverHeadStateGauge>(OverHeadWidgetComponent->GetUserWidgetObject());
	if (OverHeadStateGauge)
	{
		//调用能力系统组件,并配置它
		OverHeadStateGauge ->ConfigWithASC(GetAbilitySystemComponent());
		OverHeadWidgetComponent->SetHiddenInGame(false);

		GetWorldTimerManager().ClearTimer(VisibilityCheckTimerHandle);
		GetWorldTimerManager().SetTimer(VisibilityCheckTimerHandle, this, &ACCharacter::UpdateHeadGaugeVisibility, CheakUpdateRate, true);
	}
}

bool ACCharacter::IsLocallyControlledByPlayer() const
{
	return GetController()  && GetController()->IsLocalPlayerController();
}

void ACCharacter::UpdateHeadGaugeVisibility()
{
	//测算距离
	APawn* PlayerPawn = UGameplayStatics::GetPlayerPawn(GetWorld(), 0);
	if (!PlayerPawn) return;
	float Distance = FVector::DistSquared(GetActorLocation(), PlayerPawn->GetActorLocation());
	//隐藏状态条
	OverHeadWidgetComponent->SetHiddenInGame(Distance > CheakUpdateDistance*CheakUpdateDistance);
}

void ACCharacter::BeginPlay()
{
	Super::BeginPlay();
	ConfigureOverHeadStateWidget();
}

效果: