Реализуйте полосу здоровья UMG, которая обновляется без тика каждый кадр
Реализуйте виджет полосы здоровья UMG, у которого ProgressBar обновляется только при реальном изменении здоровья — без Event Tick и без покадровой привязки свойства UMG.
Ограничения:
- Виджет подписывается один раз на делегат
OnHealthChangedкомпонента здоровья. - Процент
ProgressBarвыставляется только внутри обработчика изменения. - Покажите верное значение один раз при подписке, до первого события.
void UHealthBarWidget::BindToComponent(UHealthComponent* Comp)
{
// ваш код здесь
}
void UHealthBarWidget::HandleHealthChanged(float NewHealth, float MaxHealth)
{
// ваш код здесь
}
Допишите реализацию.
Управляйте полосой через делегат: компонент здоровья транслирует событие OnHealthChanged, а виджет обновляет свой ProgressBar только в этом обработчике. Ни Event Tick, ни покадровая привязка свойства не нужны.
- ✗Использовать привязку свойств UMG, которая молча пересчитывается каждый кадр
- ✗Опрашивать здоровье в
NativeTickвместо реакции на событие изменения - ✗Забыть один раз выставить полосу в текущее значение при создании
- →Почему привязка свойства UMG фактически является покадровым
Tick? - →Как гарантировать, что полоса показывает верное значение до первого события?
Идея
Привязка свойства UMG выглядит дёшево, но Slate пересчитывает её каждый кадр — это скрытый Tick. Событийная модель обновляет полосу только при реальном изменении здоровья.
Компонент здоровья объявляет делегат:
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(
FOnHealthChanged, float, NewHealth, float, MaxHealth);
UCLASS()
class UHealthComponent : public UActorComponent
{
GENERATED_BODY()
public:
UPROPERTY(BlueprintAssignable) FOnHealthChanged OnHealthChanged;
void ApplyDamage(float Amount)
{
Health = FMath::Clamp(Health - Amount, 0.f, MaxHealth);
OnHealthChanged.Broadcast(Health, MaxHealth); // транслируем только при изменении
}
private:
float Health = 100.f;
float MaxHealth = 100.f;
};
Виджет подписывается один раз и обновляет ProgressBar только в обработчике:
UCLASS()
class UHealthBarWidget : public UUserWidget
{
GENERATED_BODY()
UPROPERTY(meta = (BindWidget)) UProgressBar* HealthBar;
public:
void BindToComponent(UHealthComponent* Comp)
{
Comp->OnHealthChanged.AddDynamic(this, &UHealthBarWidget::HandleHealthChanged);
// выставляем стартовое значение один раз, до первого события
HandleHealthChanged(Comp->GetHealth(), Comp->GetMaxHealth());
}
UFUNCTION()
void HandleHealthChanged(float NewHealth, float MaxHealth)
{
HealthBar->SetPercent(MaxHealth > 0.f ? NewHealth / MaxHealth : 0.f);
}
};
Event Tick виджета не используется, привязки свойств нет — полоса перерисовывается только при попадании урона или лечении.