中文注释:UrealEngine-5.2.1源码-AbilitySystemComponent.h
学习内容:
cpp
/**
* 返回给定游戏属性的当前值,如果未找到该属性则返回零。
* 注意:这不会考虑预测的游戏效果修饰符,因此客户端的值可能并不总是准确的。
*
* @param Attribute 要查询的游戏属性
* @param bFound 如果属性在此组件中存在则设置为true
*/
UFUNCTION(BlueprintPure, Category = "Gameplay Attributes")
float GetGameplayAttributeValue(FGameplayAttribute Attribute, bool& bFound) const;
这是一个典型的Unreal Engine游戏属性系统(Gameplay Attributes System)中的函数声明。让我为您详细解释这个函数:
函数功能
-
作用:查询特定游戏属性(如生命值、法力值、攻击力等)的当前数值
-
返回值:属性的当前值(浮点数),如果属性不存在则返回0
-
输出参数 :
bFound表示是否成功找到该属性
参数说明
-
FGameplayAttribute Attribute:要查询的游戏属性,通常通过宏定义如UPROPERTY(BlueprintReadOnly, Category = "Attributes")声明 -
bool& bFound:输出参数,表示属性是否存在
使用示例
cpp
// 在C++中使用
bool bAttributeFound;
float CurrentHealth = AttributeComponent->GetGameplayAttributeValue(
UBaseAttributeSet::GetHealthAttribute(),
bAttributeFound
);
if (bAttributeFound)
{
// 处理健康值
UE_LOG(LogTemp, Warning, TEXT("Current Health: %f"), CurrentHealth);
}
blueprint
bash
// 在蓝图中使用
[Get Gameplay Attribute Value]
Attribute: [Get Health Attribute]
bFound: (输出引脚,连接到Branch节点)
Return Value: 连接到其他节点
重要注意事项
-
客户端准确性:如注释所述,这不考虑预测的效果修饰符,客户端值可能与服务器不同步
-
属性查找 :
bFound参数很重要,可以区分"属性值为0"和"属性不存在"的情况 -
性能考虑:频繁调用可能影响性能,建议缓存结果
典型应用场景
-
UI显示角色属性
-
技能条件检查
-
游戏逻辑决策
-
调试和信息显示
这个函数是Gameplay Ability System (GAS) 中访问属性值的常用方法之一。
在实际项目中,GetGameplayAttributeValue 函数有广泛的应用场景。以下是一些具体的实际用例:
1. UI 显示和更新
HUD 组件中显示角色属性
cpp
// 在HUD或Widget组件中
void UPlayerHUDWidget::UpdateHealthBar()
{
bool bFound;
float CurrentHealth = AbilitySystemComponent->GetGameplayAttributeValue(
UBaseAttributeSet::GetHealthAttribute(), bFound);
float MaxHealth = AbilitySystemComponent->GetGameplayAttributeValue(
UBaseAttributeSet::GetMaxHealthAttribute(), bFound);
if (bFound && HealthBar)
{
float HealthPercent = CurrentHealth / MaxHealth;
HealthBar->SetPercent(HealthPercent);
}
}
// 定时更新或使用委托绑定属性变化
void UPlayerHUDWidget::BindAttributeChanges()
{
if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent())
{
ASC->GetGameplayAttributeValueChangeDelegate(
UBaseAttributeSet::GetHealthAttribute())
.AddUObject(this, &UPlayerHUDWidget::OnHealthChanged);
}
}
2. 技能条件和消耗检查
技能释放前的条件验证
cpp
bool UFireballAbility::CanActivateAbility(...) const
{
if (!Super::CanActivateAbility(...)) return false;
bool bFound;
float CurrentMana = GetAbilitySystemComponentFromActorInfo()->GetGameplayAttributeValue(
UBaseAttributeSet::GetManaAttribute(), bFound);
float RequiredMana = 30.0f;
// 检查法力值是否足够
if (!bFound || CurrentMana < RequiredMana)
{
SendManaWarning(); // 显示法力不足提示
return false;
}
return true;
}
3. 装备和物品系统
装备属性要求检查
cpp
bool UEquipmentComponent::CanEquipItem(const UItemData* ItemData) const
{
if (!ItemData) return false;
bool bFound;
UAbilitySystemComponent* ASC = GetOwnerAbilitySystemComponent();
// 检查力量要求
float CurrentStrength = ASC->GetGameplayAttributeValue(
UBaseAttributeSet::GetStrengthAttribute(), bFound);
if (bFound && CurrentStrength < ItemData->RequiredStrength)
{
SendNotification("力量不足,无法装备此物品");
return false;
}
// 检查等级要求
float CurrentLevel = ASC->GetGameplayAttributeValue(
UBaseAttributeSet::GetLevelAttribute(), bFound);
if (bFound && CurrentLevel < ItemData->RequiredLevel)
{
SendNotification("等级不足,无法装备此物品");
return false;
}
return true;
}
4. AI 决策和行为树
AI 行为树中的条件判断
cpp
// 在行为树装饰器或任务中
UBTDecorator_CheckHealth::CalculateRawConditionValue(...) const
{
AAIController* AIController = ...;
APawn* ControlledPawn = AIController->GetPawn();
UAbilitySystemComponent* ASC = ControlledPawn->FindComponentByClass<UAbilitySystemComponent>();
if (!ASC) return false;
bool bFound;
float CurrentHealth = ASC->GetGameplayAttributeValue(
UBaseAttributeSet::GetHealthAttribute(), bFound);
float MaxHealth = ASC->GetGameplayAttributeValue(
UBaseAttributeSet::GetMaxHealthAttribute(), bFound);
if (bFound)
{
float HealthPercent = CurrentHealth / MaxHealth;
// 生命值低于30%时逃跑
return HealthPercent < 0.3f;
}
return false;
}
5. 成就和统计系统
成就条件检查
cpp
void UAchievementManager::CheckDamageAchievements(float DamageDealt)
{
bool bFound;
UAbilitySystemComponent* ASC = PlayerController->GetAbilitySystemComponent();
// 获取当前攻击力
float AttackPower = ASC->GetGameplayAttributeValue(
UBaseAttributeSet::GetAttackPowerAttribute(), bFound);
// 单次攻击造成超过1000伤害的成就
if (bFound && DamageDealt > 1000.0f)
{
UnlockAchievement("OneHitWonder");
}
// 累计伤害成就
TotalDamageDealt += DamageDealt;
if (TotalDamageDealt > 100000.0f)
{
UnlockAchievement("MasterDamageDealer");
}
}
6. 调试和开发工具
开发时属性监控
cpp
// 调试命令显示所有属性
void UAttributeDebugComponent::DisplayAllAttributes()
{
UAbilitySystemComponent* ASC = GetAbilitySystemComponent();
if (!ASC) return;
TArray<FGameplayAttribute> AllAttributes = GetRelevantAttributes();
for (const FGameplayAttribute& Attribute : AllAttributes)
{
bool bFound;
float Value = ASC->GetGameplayAttributeValue(Attribute, bFound);
if (bFound)
{
FString AttributeName = Attribute.GetName();
FString Message = FString::Printf(TEXT("%s: %.1f"), *AttributeName, Value);
GEngine->AddOnScreenDebugMessage(-1, 5.0f, FColor::White, Message);
}
}
}
7. 实际项目中的最佳实践
封装工具函数
cpp
// 工具类中封装常用操作
class GAMEMODULE_API UAttributeHelper
{
public:
static float GetAttributeValue(AActor* Actor, FGameplayAttribute Attribute, float DefaultValue = 0.0f)
{
if (UAbilitySystemComponent* ASC = UAbilityFunctionLibrary::GetAbilitySystemComponent(Actor))
{
bool bFound;
float Value = ASC->GetGameplayAttributeValue(Attribute, bFound);
return bFound ? Value : DefaultValue;
}
return DefaultValue;
}
static bool HasEnoughResource(AActor* Actor, FGameplayAttribute ResourceAttribute, float RequiredAmount)
{
float CurrentResource = GetAttributeValue(Actor, ResourceAttribute);
return CurrentResource >= RequiredAmount;
}
};
// 使用封装函数
bool CanCastSpell = UAttributeHelper::HasEnoughResource(
PlayerCharacter,
UBaseAttributeSet::GetManaAttribute(),
25.0f
);
性能优化建议
cpp
// 避免每帧调用,使用缓存或事件驱动
void UAttributeMonitorComponent::BeginPlay()
{
Super::BeginPlay();
// 监听属性变化而不是每帧查询
if (UAbilitySystemComponent* ASC = GetAbilitySystemComponent())
{
ASC->GetGameplayAttributeValueChangeDelegate(UBaseAttributeSet::GetHealthAttribute())
.AddUObject(this, &UAttributeMonitorComponent::OnHealthChanged);
}
}
void UAttributeMonitorComponent::OnHealthChanged(const FOnAttributeChangeData& Data)
{
// 只有属性实际变化时才更新
UpdateHealthDisplay(Data.NewValue);
}
这些实际应用展示了 GetGameplayAttributeValue 在游戏各个系统中的重要作用,从基础的UI显示到复杂的游戏逻辑决策。