头顶状态条的动态显示控制。状态条会根据与玩家角色的距离(默认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();
}
效果:
