UE5多人MOBA+GAS 22、创建技能图标UI,实现显示蓝耗,冷却,以及数字显示的倒数计时还有雷达显示的倒数计时

发布于:2025-07-15 ⋅ 阅读:(15) ⋅ 点赞:(0)


创建技能图标UI类

在这里插入图片描述

// 幻雨喜欢小猫咪

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/Image.h"
#include "Components/TextBlock.h"
#include "AbilityGauge.generated.h"

/**
 * 
 */
UCLASS()
class CRUNCH_API UAbilityGauge : public UUserWidget
{
	GENERATED_BODY()

private:
	// 技能图标
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UImage> Icon;

	// 冷却计时文本控件
	UPROPERTY(meta=(BindWidget))
	TObjectPtr<UTextBlock> CooldownCounterText;

	// 冷却总时长文本控件
	UPROPERTY(meta=(BindWidget))
	TObjectPtr<UTextBlock> CooldownDurationText;

	// 技能消耗文本控件
	UPROPERTY(meta=(BindWidget))
	TObjectPtr<UTextBlock> CostText;
};

放入cpp写好的控件
在这里插入图片描述

从角色中将技能表传递到UI中

在能力组件CAbilitySystemComponentCCharacter角色基类中添加获取技能表的函数

	const TMap<ECAbilityInputID, TSubclassOf<UGameplayAbility>>& GetAbilities() const;
const TMap<ECAbilityInputID, TSubclassOf<UGameplayAbility>>& UCAbilitySystemComponent::GetAbilities() const
{
	return Abilities;
}
const TMap<ECAbilityInputID, TSubclassOf<UGameplayAbility>>& ACCharacter::GetAbilities() const
{
	return CAbilitySystemComponent->GetAbilities();
}

GameplayWidget创建一个获取技能表传递配置的函数

void ConfigureAbilities(const TMap<ECAbilityInputID, TSubclassOf<UGameplayAbility>>& Abilities);

在玩家控制器CPlayerController中把技能表传递给UI

void ACPlayerController::SpawnGameplayWidget()
{
	// 检查当前玩家控制器是否是本地玩家控制器
	if (!IsLocalPlayerController()) return;
	if (GameplayWidgetClass)
	{
		GameplayWidget = CreateWidget<UGameplayWidget>(this, GameplayWidgetClass);
		if (GameplayWidget)
		{
			// 添加到视口中
			GameplayWidget->AddToViewport();
			// 将技能数据传递给UI
			GameplayWidget->ConfigureAbilities(CPlayerCharacter->GetAbilities());
		}
	}
}

创建一个技能列表

在这里插入图片描述

// 幻雨喜欢小猫咪

#pragma once

#include "CoreMinimal.h"
#include "Components/ListView.h"
#include "GAS/Core/CGameplayAbilityTypes.h"
#include "AbilityListView.generated.h"

/**
 * 
 */
UCLASS()
class CRUNCH_API UAbilityListView : public UListView
{
	GENERATED_BODY()
public:
	// 配置能力表
	void ConfigureAbilities(const TMap<ECAbilityInputID, TSubclassOf<class UGameplayAbility>>& Abilities);

};
#include "AbilityListView.h"

#include "Abilities/GameplayAbility.h"

void UAbilityListView::ConfigureAbilities(const TMap<ECAbilityInputID, TSubclassOf<class UGameplayAbility>>& Abilities)
{
	//OnEntryWidgetGenerated().AddUObject()
	for (const TPair<ECAbilityInputID, TSubclassOf<UGameplayAbility>>& AbilityPair : Abilities)
	{
		AddItem(AbilityPair.Value.GetDefaultObject());
	}
}

GameplayWidget中添加技能列表

	// 技能列表
	UPROPERTY(meta=(BindWidget))
	TObjectPtr<UAbilityListView> AbilityListView;
void UGameplayWidget::ConfigureAbilities(const TMap<ECAbilityInputID, TSubclassOf<UGameplayAbility>>& Abilities)
{
	AbilityListView->ConfigureAbilities(Abilities);
}

然后还不能用说缺东西
在这里插入图片描述
让技能图标继承IUserObjectListEntry接口

UCLASS()
class CRUNCH_API UAbilityGauge : public UUserWidget, public IUserObjectListEntry
{
	GENERATED_BODY()
public:
	virtual void NativeOnListItemObjectSet(UObject* ListItemObject) override;
};
void UAbilityGauge::NativeOnListItemObjectSet(UObject* ListItemObject)
{
	IUserObjectListEntry::NativeOnListItemObjectSet(ListItemObject);
}

就可以在UI中设置该技能图标类了,下面的数字可以控制显示的数目
在这里插入图片描述
调整为水平方向,间距也可以调整
在这里插入图片描述
创建数据表

// 技能控件数据结构,用于配置技能UI显示内容
USTRUCT(BlueprintType)
struct FAbilityWidgetData : public FTableRowBase
{
	GENERATED_BODY()

	// 技能类
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSubclassOf<class UGameplayAbility> AbilityClass;

	// 技能名称
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FName AbilityName;

	// 技能图标
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSoftObjectPtr<UTexture2D> Icon;

	// 技能描述
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FText Description;
};

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
补全技能列表AbilityListView

// 幻雨喜欢小猫咪

#pragma once

#include "CoreMinimal.h"
#include "Components/ListView.h"
#include "GAS/Core/CGameplayAbilityTypes.h"
#include "UI/Gameplay/Abilities/AbilityGauge.h"
#include "AbilityListView.generated.h"

/**
 * 
 */
UCLASS()
class CRUNCH_API UAbilityListView : public UListView
{
	GENERATED_BODY()
public:
	// 配置能力表
	void ConfigureAbilities(const TMap<ECAbilityInputID, TSubclassOf<class UGameplayAbility>>& Abilities);
private:
	UPROPERTY(EditAnywhere, Category = "Data")
	TObjectPtr<UDataTable> AbilityDataTable;

	// 技能生成绑定
	void AbilityGaugeGenerated(UUserWidget& Widget);

	// 查找指定技能的UI数据
	const FAbilityWidgetData* FindWidgetDataForAbility(const TSubclassOf<UGameplayAbility>& AbilityClass) const;
};

// 幻雨喜欢小猫咪


#include "AbilityListView.h"

#include "Abilities/GameplayAbility.h"

void UAbilityListView::ConfigureAbilities(const TMap<ECAbilityInputID, TSubclassOf<class UGameplayAbility>>& Abilities)
{
	OnEntryWidgetGenerated().AddUObject(this, &UAbilityListView::AbilityGaugeGenerated);
	// 添加技能
	for (const TPair<ECAbilityInputID, TSubclassOf<UGameplayAbility>>& AbilityPair : Abilities)
	{
		AddItem(AbilityPair.Value.GetDefaultObject());
	}
}

void UAbilityListView::AbilityGaugeGenerated(UUserWidget& Widget)
{
	UAbilityGauge* AbilityGauge = Cast<UAbilityGauge>(&Widget);

	if (AbilityGauge)
	{
		AbilityGauge->ConfigureWithWidgetData(FindWidgetDataForAbility(AbilityGauge->GetListItem<UGameplayAbility>()->GetClass()));
	}
}

const FAbilityWidgetData* UAbilityListView::FindWidgetDataForAbility(
	const TSubclassOf<UGameplayAbility>& AbilityClass) const
{
	if (!AbilityDataTable) return nullptr;

	for (auto& AbilityWidgetDataPair : AbilityDataTable->GetRowMap())
	{
		const FAbilityWidgetData* WidgetData = AbilityDataTable->FindRow<FAbilityWidgetData>(AbilityWidgetDataPair.Key, "");
		if (WidgetData && WidgetData->AbilityClass == AbilityClass)
		{
			return WidgetData;
		}
	}
	return nullptr;
}

在技能图标中添加配置函数以及要设置的材质对应的图标名称

	// 用数据配置控件显示
	void ConfigureWithWidgetData(const FAbilityWidgetData* WidgetData);
private:

	// 图标材质参数名
	UPROPERTY(EditDefaultsOnly, Category = "Visual")
	FName IconMaterialParamName = "Icon";
void UAbilityGauge::ConfigureWithWidgetData(const FAbilityWidgetData* WidgetData)
{
	if (Icon && WidgetData)
	{
		// 设置图片
		Icon->GetDynamicMaterial()->SetTextureParameterValue(IconMaterialParamName, WidgetData->Icon.LoadSynchronous());
	}
}

把数据表添加进去
在这里插入图片描述

获取蓝耗以及冷却

CAbilitySystemStatics函数类中添加获取技能冷却和技能消耗的函数

UCLASS()
class UCAbilitySystemStatics : public UBlueprintFunctionLibrary
{
	GENERATED_BODY()
public:
	static FGameplayTag GetBasicAttackAbilityTag();

	// 获取技能冷却
	static float GetStaticCooldownDurationForAbility(const UGameplayAbility* Ability);
	// 获取技能消耗
	static float GetStaticCostForAbility(const UGameplayAbility* Ability);
};
float UCAbilitySystemStatics::GetStaticCooldownDurationForAbility(const UGameplayAbility* Ability)
{
	if (!Ability) return 0.f;

	// 获取冷却效果
	const UGameplayEffect* CoolDownEffect = Ability->GetCooldownGameplayEffect();
	if (!CoolDownEffect) return 0.f;

	float CooldownDuration = 0.f;
	// 调用GetStaticMagnitudeIfPossible方法从冷却效果中获取静态持续时间值
	CoolDownEffect->DurationMagnitude.GetStaticMagnitudeIfPossible(1, CooldownDuration);
	return CooldownDuration;
}

float UCAbilitySystemStatics::GetStaticCostForAbility(const UGameplayAbility* Ability)
{
	if (!Ability) return 0.f;

	// 获取消耗效果
	const UGameplayEffect* CostEffect = Ability->GetCostGameplayEffect();
	if (!CostEffect || CostEffect->Modifiers.Num() == 0) return 0.f;

	float Cost = 0.f;
	CostEffect->Modifiers[0].ModifierMagnitude.GetStaticMagnitudeIfPossible(1, Cost);
	// 取正值
	return FMath::Abs(Cost);
}

到技能图标AbilityGauge中设置一下cd和消耗

public:
	// 控件构建时调用
	virtual void NativeConstruct() override;
private:
	// 技能类默认对象
	UPROPERTY()
	TObjectPtr<UGameplayAbility> AbilityCDO;
void UAbilityGauge::NativeConstruct()
{
	Super::NativeConstruct();
	// 隐藏冷却计时器
	CooldownCounterText->SetVisibility(ESlateVisibility::Hidden);
}

void UAbilityGauge::NativeOnListItemObjectSet(UObject* ListItemObject)
{
	IUserObjectListEntry::NativeOnListItemObjectSet(ListItemObject);
	AbilityCDO = Cast<UGameplayAbility>(ListItemObject);

	// 获取冷却和消耗
	float CoolDownDuration = UCAbilitySystemStatics::GetStaticCooldownDurationForAbility(AbilityCDO);
	float Cost = UCAbilitySystemStatics::GetStaticCostForAbility(AbilityCDO);

	// 设置冷却和消耗
	CooldownDurationText->SetText(FText::AsNumber(CoolDownDuration));
	CostText->SetText(FText::AsNumber(Cost));
}

运行一下就能显示蓝耗以及cd了(为啥灰的,因为我偷懒了)
在这里插入图片描述

让冷却实现倒数计时

private:
	// 冷却倒数计时的间隔
	UPROPERTY(EditDefaultsOnly, Category = "Cooldown")
	float CooldownUpdateInterval = 0.1f;
	
    // 技能释放时回调
    void AbilityCommitted(UGameplayAbility* Ability);

    // 启动冷却计时
    void StartCooldown(float CooldownTimeRemaining, float CooldownDuration);

    // 缓存的冷却总时长
    float CachedCooldownDuration;

    // 缓存的冷却剩余时间
    float CachedCooldownTimeRemaining;

    // 冷却完成定时器
    FTimerHandle CooldownTimerHandle;

    // 冷却刷新定时器
    FTimerHandle CooldownTimerUpdateHandle;

    // 数字格式化选项(整数)
    FNumberFormattingOptions WholeNumberFormattingOptions;

    // 数字格式化选项(一位小数)
    FNumberFormattingOptions TwoDigitNumberFormattingOptions;
    
	// 冷却完成回调
	void CooldownFinished();

	// 冷却刷新回调
	void UpdateCooldown();
void UAbilityGauge::NativeConstruct()
{
	Super::NativeConstruct();
	// 隐藏冷却计时器
	CooldownCounterText->SetVisibility(ESlateVisibility::Hidden);

	UAbilitySystemComponent* OwnerASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetOwningPlayerPawn());
	if (OwnerASC)
	{
		// 监听技能释放
		OwnerASC->AbilityCommittedCallbacks.AddUObject(this, &UAbilityGauge::AbilityCommitted);
	}

	WholeNumberFormattingOptions.MaximumFractionalDigits = 0;
	TwoDigitNumberFormattingOptions.MaximumFractionalDigits = 2;
}

void UAbilityGauge::AbilityCommitted(UGameplayAbility* Ability)
{
	// 判断释放的技能是否为该图标的技能
	if (Ability->GetClass()->GetDefaultObject() == AbilityCDO)
	{
		// 获取技能冷却剩余时长
		float CooldownTimeRemaining = 0.f;
		// 获取技能冷却总时长
		float CooldownDuration = 0.f;
		// 返回当前激活的冷却剩余时间(秒)及该冷却的原始持续时间
		Ability->GetCooldownTimeRemainingAndDuration(Ability->GetCurrentAbilitySpecHandle(), Ability->GetCurrentActorInfo(), CooldownTimeRemaining, CooldownDuration);

		// 启动UI技能冷却
		StartCooldown(CooldownTimeRemaining, CooldownDuration);
	}
}

void UAbilityGauge::StartCooldown(float CooldownTimeRemaining, float CooldownDuration)
{
	// 设置冷却时间
	CooldownDurationText->SetText(FText::AsNumber(CooldownDuration));
	// 将倒数计时设置为可视
	CooldownDurationText->SetVisibility(ESlateVisibility::Visible);

	// 缓存冷却总时长
	CachedCooldownDuration = CooldownDuration;
	// 缓存冷却剩余时间
	CachedCooldownTimeRemaining = CooldownTimeRemaining;

	// 冷却结束监听
	GetWorld()->GetTimerManager().SetTimer(CooldownTimerHandle, this, &UAbilityGauge::CooldownFinished,CachedCooldownTimeRemaining);
	// 启动倒数计时
	GetWorld()->GetTimerManager().SetTimer(CooldownTimerUpdateHandle, this, &UAbilityGauge::UpdateCooldown, CooldownUpdateInterval, true, 0.f);
}

void UAbilityGauge::CooldownFinished()
{
	CachedCooldownDuration = CachedCooldownTimeRemaining = 0.f;
	// 冷却结束隐藏倒计时文本
	CooldownCounterText->SetVisibility(ESlateVisibility::Hidden);

	// 关闭倒数计时定时器
	GetWorld()->GetTimerManager().ClearTimer(CooldownTimerUpdateHandle);
}

void UAbilityGauge::UpdateCooldown()
{
	// 更新剩余时间
	CachedCooldownTimeRemaining -= CooldownUpdateInterval;
	// 剩余时间大于1就显示一位数
	FNumberFormattingOptions* FormattingOptions = CachedCooldownTimeRemaining > 1 ? &WholeNumberFormattingOptions : &TwoDigitNumberFormattingOptions;

	CooldownCounterText->SetText(FText::AsNumber(CachedCooldownTimeRemaining, FormattingOptions));
}

获取到倒数计时的显示
在这里插入图片描述

用扫描雷达做冷却倒数材质

在这里插入图片描述
技能图标中添加

	// 冷却百分比材质参数名
	UPROPERTY(EditDefaultsOnly, Category = "Visual")
	FName CooldownPercentParamName = "Percent";
void UAbilityGauge::CooldownFinished()
{
	CachedCooldownDuration = CachedCooldownTimeRemaining = 0.f;
	// 冷却结束隐藏倒计时文本
	CooldownCounterText->SetVisibility(ESlateVisibility::Hidden);

	// 关闭倒数计时定时器
	GetWorld()->GetTimerManager().ClearTimer(CooldownTimerUpdateHandle);

	Icon->GetDynamicMaterial()->SetScalarParameterValue(CooldownPercentParamName, 1.f);
}

void UAbilityGauge::UpdateCooldown()
{
	// 更新剩余时间
	CachedCooldownTimeRemaining -= CooldownUpdateInterval;
	// 剩余时间大于1就显示一位数
	FNumberFormattingOptions* FormattingOptions = CachedCooldownTimeRemaining > 1 ? &WholeNumberFormattingOptions : &TwoDigitNumberFormattingOptions;
	Icon->GetDynamicMaterial()->SetScalarParameterValue(CooldownPercentParamName, 1.0f - CachedCooldownTimeRemaining / CachedCooldownDuration);
	CooldownCounterText->SetText(FText::AsNumber(CachedCooldownTimeRemaining, FormattingOptions));
}

在这里插入图片描述
技能图标代码

// 幻雨喜欢小猫咪

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/IUserObjectListEntry.h"
#include "Blueprint/UserWidget.h"
#include "Components/Image.h"
#include "Components/TextBlock.h"
#include "AbilityGauge.generated.h"

// 技能控件数据结构,用于配置技能UI显示内容
USTRUCT(BlueprintType)
struct FAbilityWidgetData : public FTableRowBase
{
	GENERATED_BODY()

	// 技能类
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSubclassOf<class UGameplayAbility> AbilityClass;

	// 技能名称
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FName AbilityName;

	// 技能图标
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	TSoftObjectPtr<UTexture2D> Icon;

	// 技能描述
	UPROPERTY(EditAnywhere, BlueprintReadWrite)
	FText Description;
};

/**
 * 技能槽UI控件,负责显示技能图标、冷却、等级、消耗等信息
 * 支持技能升级、冷却计时、能否释放等状态的动态刷新
 */
UCLASS()
class CRUNCH_API UAbilityGauge : public UUserWidget, public IUserObjectListEntry
{
	GENERATED_BODY()
public:
	// 控件构建时调用
	virtual void NativeConstruct() override;

	// 列表项对象设置时调用
	virtual void NativeOnListItemObjectSet(UObject* ListItemObject) override;

	// 用数据配置控件显示
	void ConfigureWithWidgetData(const FAbilityWidgetData* WidgetData);
private:
	// 冷却倒数计时的间隔
	UPROPERTY(EditDefaultsOnly, Category = "Cooldown")
	float CooldownUpdateInterval = 0.1f;
	// 图标材质参数名
	UPROPERTY(EditDefaultsOnly, Category = "Visual")
	FName IconMaterialParamName = "Icon";

	// 冷却百分比材质参数名
	UPROPERTY(EditDefaultsOnly, Category = "Visual")
	FName CooldownPercentParamName = "Percent";
	
	// 技能图标
	UPROPERTY(meta = (BindWidget))
	TObjectPtr<UImage> Icon;

	// 冷却计时文本控件
	UPROPERTY(meta=(BindWidget))
	TObjectPtr<UTextBlock> CooldownCounterText;

	// 冷却总时长文本控件
	UPROPERTY(meta=(BindWidget))
	TObjectPtr<UTextBlock> CooldownDurationText;

	// 技能消耗文本控件
	UPROPERTY(meta=(BindWidget))
	TObjectPtr<UTextBlock> CostText;

	// 技能类默认对象
	UPROPERTY()
	TObjectPtr<UGameplayAbility> AbilityCDO;

	// 技能释放时回调
	void AbilityCommitted(UGameplayAbility* Ability);

	// 启动冷却计时
	void StartCooldown(float CooldownTimeRemaining, float CooldownDuration);

	// 缓存的冷却总时长
	float CachedCooldownDuration;

	// 缓存的冷却剩余时间
	float CachedCooldownTimeRemaining;

	// 冷却完成定时器
	FTimerHandle CooldownTimerHandle;

	// 冷却刷新定时器
	FTimerHandle CooldownTimerUpdateHandle;

	// 数字格式化选项(整数)
	FNumberFormattingOptions WholeNumberFormattingOptions;

	// 数字格式化选项(一位小数)
	FNumberFormattingOptions TwoDigitNumberFormattingOptions;

	// 冷却完成回调,隐藏冷却文本并重置进度条
	void CooldownFinished();

	// 冷却刷新回调,更新冷却文本和进度条
	void UpdateCooldown();
};

// 幻雨喜欢小猫咪


#include "UI/Gameplay/Abilities/AbilityGauge.h"

#include "AbilitySystemBlueprintLibrary.h"
#include "AbilitySystemComponent.h"
#include "Components/Image.h"
#include "GAS/Core/CAbilitySystemStatics.h"
#include "Abilities/GameplayAbility.h"

void UAbilityGauge::NativeConstruct()
{
	Super::NativeConstruct();
	// 隐藏冷却计时器
	CooldownCounterText->SetVisibility(ESlateVisibility::Hidden);

	UAbilitySystemComponent* OwnerASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetOwningPlayerPawn());
	if (OwnerASC)
	{
		// 监听技能释放
		OwnerASC->AbilityCommittedCallbacks.AddUObject(this, &UAbilityGauge::AbilityCommitted);
	}

	WholeNumberFormattingOptions.MaximumFractionalDigits = 0;
	TwoDigitNumberFormattingOptions.MaximumFractionalDigits = 2;
}

void UAbilityGauge::NativeOnListItemObjectSet(UObject* ListItemObject)
{
	IUserObjectListEntry::NativeOnListItemObjectSet(ListItemObject);
	AbilityCDO = Cast<UGameplayAbility>(ListItemObject);

	// 获取冷却和消耗
	float CoolDownDuration = UCAbilitySystemStatics::GetStaticCooldownDurationForAbility(AbilityCDO);
	float Cost = UCAbilitySystemStatics::GetStaticCostForAbility(AbilityCDO);

	// 设置冷却和消耗
	CooldownDurationText->SetText(FText::AsNumber(CoolDownDuration));
	CostText->SetText(FText::AsNumber(Cost));
}

void UAbilityGauge::ConfigureWithWidgetData(const FAbilityWidgetData* WidgetData)
{
	if (Icon && WidgetData)
	{
		// 设置图片
		Icon->GetDynamicMaterial()->SetTextureParameterValue(IconMaterialParamName, WidgetData->Icon.LoadSynchronous());
	}
}

void UAbilityGauge::AbilityCommitted(UGameplayAbility* Ability)
{
	// 判断释放的技能是否为该图标的技能
	if (Ability->GetClass()->GetDefaultObject() == AbilityCDO)
	{
		// 获取技能冷却剩余时长
		float CooldownTimeRemaining = 0.f;
		// 获取技能冷却总时长
		float CooldownDuration = 0.f;
		// 返回当前激活的冷却剩余时间(秒)及该冷却的原始持续时间
		Ability->GetCooldownTimeRemainingAndDuration(Ability->GetCurrentAbilitySpecHandle(), Ability->GetCurrentActorInfo(), CooldownTimeRemaining, CooldownDuration);

		// 启动UI技能冷却
		StartCooldown(CooldownTimeRemaining, CooldownDuration);
	}
}

void UAbilityGauge::StartCooldown(float CooldownTimeRemaining, float CooldownDuration)
{
	// 设置冷却时间
	// CooldownDurationText->SetText(FText::AsNumber(CooldownDuration));
	CooldownCounterText->SetText(FText::AsNumber(CooldownDuration));
	// 缓存冷却总时长
	CachedCooldownDuration = CooldownDuration;
	// 缓存冷却剩余时间
	CachedCooldownTimeRemaining = CooldownTimeRemaining;
	
	// 将倒数计时设置为可视
	CooldownCounterText->SetVisibility(ESlateVisibility::Visible);

	// 冷却结束监听
	GetWorld()->GetTimerManager().SetTimer(CooldownTimerHandle, this, &UAbilityGauge::CooldownFinished,CachedCooldownTimeRemaining);
	// 启动倒数计时
	GetWorld()->GetTimerManager().SetTimer(CooldownTimerUpdateHandle, this, &UAbilityGauge::UpdateCooldown, CooldownUpdateInterval, true, 0.f);
}

void UAbilityGauge::CooldownFinished()
{
	CachedCooldownDuration = CachedCooldownTimeRemaining = 0.f;
	// 冷却结束隐藏倒计时文本
	CooldownCounterText->SetVisibility(ESlateVisibility::Hidden);

	// 关闭倒数计时定时器
	GetWorld()->GetTimerManager().ClearTimer(CooldownTimerUpdateHandle);

	Icon->GetDynamicMaterial()->SetScalarParameterValue(CooldownPercentParamName, 1.f);
}

void UAbilityGauge::UpdateCooldown()
{
	// 更新剩余时间
	CachedCooldownTimeRemaining -= CooldownUpdateInterval;
	// 剩余时间大于1就显示一位数
	FNumberFormattingOptions* FormattingOptions = CachedCooldownTimeRemaining > 1 ? &WholeNumberFormattingOptions : &TwoDigitNumberFormattingOptions;
	Icon->GetDynamicMaterial()->SetScalarParameterValue(CooldownPercentParamName, 1.0f - CachedCooldownTimeRemaining / CachedCooldownDuration);
	CooldownCounterText->SetText(FText::AsNumber(CachedCooldownTimeRemaining, FormattingOptions));
}

技能列表代码

// 幻雨喜欢小猫咪

#pragma once

#include "CoreMinimal.h"
#include "Components/ListView.h"
#include "GAS/Core/CGameplayAbilityTypes.h"
#include "UI/Gameplay/Abilities/AbilityGauge.h"
#include "AbilityListView.generated.h"

/**
 * 
 */
UCLASS()
class CRUNCH_API UAbilityListView : public UListView
{
	GENERATED_BODY()
public:
	// 配置能力表
	void ConfigureAbilities(const TMap<ECAbilityInputID, TSubclassOf<class UGameplayAbility>>& Abilities);
private:
	UPROPERTY(EditAnywhere, Category = "Data")
	TObjectPtr<UDataTable> AbilityDataTable;

	// 技能生成绑定
	void AbilityGaugeGenerated(UUserWidget& Widget);

	// 查找指定技能的UI数据
	const FAbilityWidgetData* FindWidgetDataForAbility(const TSubclassOf<UGameplayAbility>& AbilityClass) const;
};
// 幻雨喜欢小猫咪


#include "AbilityListView.h"

#include "Abilities/GameplayAbility.h"

void UAbilityListView::ConfigureAbilities(const TMap<ECAbilityInputID, TSubclassOf<class UGameplayAbility>>& Abilities)
{
	// 绑定技能生成事件
	OnEntryWidgetGenerated().AddUObject(this, &UAbilityListView::AbilityGaugeGenerated);
	// 添加技能
	for (const TPair<ECAbilityInputID, TSubclassOf<UGameplayAbility>>& AbilityPair : Abilities)
	{
		AddItem(AbilityPair.Value.GetDefaultObject());
	}
}

void UAbilityListView::AbilityGaugeGenerated(UUserWidget& Widget)
{
	// 将控件转换为UAbilityGauge类型
	UAbilityGauge* AbilityGauge = Cast<UAbilityGauge>(&Widget);

	if (AbilityGauge)
	{
		// 查找并配置技能计量器的数据
		AbilityGauge->ConfigureWithWidgetData(FindWidgetDataForAbility(AbilityGauge->GetListItem<UGameplayAbility>()->GetClass()));
	}
}

const FAbilityWidgetData* UAbilityListView::FindWidgetDataForAbility(
	const TSubclassOf<UGameplayAbility>& AbilityClass) const
{
	// 如果数据表为空则直接返回nullptr
	if (!AbilityDataTable) return nullptr;

	// 遍历数据表的所有行
	for (auto& AbilityWidgetDataPair : AbilityDataTable->GetRowMap())
	{
		// 查找当前行的数据
		const FAbilityWidgetData* WidgetData = AbilityDataTable->FindRow<FAbilityWidgetData>(AbilityWidgetDataPair.Key, "");
        
		// 如果找到数据且技能类匹配则返回
		if (WidgetData && WidgetData->AbilityClass == AbilityClass)
		{
			return WidgetData;
		}
	}
    
	// 未找到匹配的数据
	return nullptr;
}

网站公告

今日签到

点亮在社区的每一天
去签到