Procedural M_UI_UniversalBar material (SDF rounded-rect, fill/delayed/shield/ penalty-zones/stripes/segments/flash/pulse), 6 preset instances, animated UUniversalBarWidget + UUniversalHUDWidget + global UUniversalBarsSubsystem API, UUniversalBarsTheme DataAsset, and a ready WBP_HUD_InGame with zone-tracking status chips. See README.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
158 lines
5.3 KiB
C++
158 lines
5.3 KiB
C++
// Copyright IHY. Universal Bars plugin.
|
|
// One animated UMG bar driven by M_UI_UniversalBar. Handles a single logical
|
|
// value (HP, stamina, durability, ...) plus optional data-driven penalty zones
|
|
// for combined PEAK-style capacity bars (hunger / weight / cold eating into max).
|
|
#pragma once
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Blueprint/UserWidget.h"
|
|
#include "UniversalBarWidget.generated.h"
|
|
|
|
class UImage;
|
|
class UMaterialInstanceDynamic;
|
|
|
|
// A penalty / reserve zone consuming capacity from the right end of the bar.
|
|
USTRUCT(BlueprintType)
|
|
struct FBarZone
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Zone")
|
|
FName Id = NAME_None;
|
|
|
|
// Target width as a fraction of the full track (0..1).
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Zone", meta=(ClampMin="0", ClampMax="1"))
|
|
float Width = 0.f;
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Zone")
|
|
FLinearColor Color = FLinearColor(0.9f, 0.6f, 0.2f, 1.f);
|
|
|
|
// Animated width that eases toward Width at runtime (not authored).
|
|
float DisplayWidth = 0.f;
|
|
};
|
|
|
|
UCLASS()
|
|
class UNIVERSALBARS_API UUniversalBarWidget : public UUserWidget
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
public:
|
|
UUniversalBarWidget(const FObjectInitializer& ObjectInitializer);
|
|
|
|
// Name this "BarImage" in the WBP; assign an MI_UI_Bar_* (or the master) to its Brush.
|
|
UPROPERTY(meta=(BindWidget))
|
|
TObjectPtr<UImage> BarImage = nullptr;
|
|
|
|
// ---- animation tuning ----
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim")
|
|
float FillRiseSpeed = 7.f; // how fast the bright fill grows on increase/heal
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim")
|
|
float DelayedFallSpeed = 4.f; // how fast the damage-lag tail drains on decrease
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim")
|
|
float DelayedDelay = 0.25f; // pause before the tail starts draining (sec)
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim")
|
|
float FlashSpeed = 6.f; // flash decay rate
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim")
|
|
float ZoneInterpSpeed = 8.f; // penalty-zone width easing
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim")
|
|
float LowThreshold = 0.25f; // below this, low-value pulse turns on
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Anim")
|
|
bool bAutoFlashOnChange = true; // SetFillPercent auto-plays damage/heal flash
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Colors")
|
|
FLinearColor DamageFlashColor = FLinearColor(1.f, 0.12f, 0.12f, 1.f);
|
|
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Colors")
|
|
FLinearColor HealFlashColor = FLinearColor(0.6f, 1.f, 0.6f, 1.f);
|
|
|
|
// ---- data-driven penalty zones (combined / PEAK mode) ----
|
|
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Bar|Zones")
|
|
TArray<FBarZone> PenaltyZones;
|
|
|
|
// ===== public API =====
|
|
// Animated set of the bar's main value (0..1). Decrease => instant drop + lag
|
|
// tail (+ damage flash). Increase => smooth rise (+ heal flash).
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void SetFillPercent(float NewValue, bool bAnimate = true);
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void SetShieldPercent(float NewValue);
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void PlayDamageFlash();
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void PlayHealFlash();
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void PlayFlash(FLinearColor Color);
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void SetBarColors(FLinearColor Fill, FLinearColor Empty, FLinearColor Border, FLinearColor Delayed);
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void SetSegmentCount(int32 Count);
|
|
|
|
// ---- penalty zone management (animated) ----
|
|
UFUNCTION(BlueprintCallable, Category="Bar|Zones")
|
|
void SetPenaltyZone(FName Id, float Width, FLinearColor Color);
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar|Zones")
|
|
void SetPenaltyZoneWidth(FName Id, float Width);
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar|Zones")
|
|
void RemovePenaltyZone(FName Id);
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar|Zones")
|
|
void ClearPenaltyZones();
|
|
|
|
// Generic escape hatches.
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void SetScalar(FName Param, float Value);
|
|
|
|
UFUNCTION(BlueprintCallable, Category="Bar")
|
|
void SetVector(FName Param, FLinearColor Value);
|
|
|
|
UFUNCTION(BlueprintPure, Category="Bar")
|
|
float GetFillPercent() const { return TargetFill; }
|
|
|
|
// ---- zone layout in bar-U space (0..1), using current animated widths ----
|
|
// Right edge of the usable region (1 - sum of penalty display widths).
|
|
UFUNCTION(BlueprintPure, Category="Bar|Zones")
|
|
float GetUsableEnd() const;
|
|
|
|
// U-coordinate of a penalty zone's centre; -1 if the zone is absent.
|
|
UFUNCTION(BlueprintPure, Category="Bar|Zones")
|
|
float GetZoneCenter(FName Id) const;
|
|
|
|
protected:
|
|
virtual void NativeConstruct() override;
|
|
virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override;
|
|
|
|
UMaterialInstanceDynamic* EnsureMID();
|
|
void PushZones(bool bImmediate);
|
|
|
|
private:
|
|
UPROPERTY(Transient)
|
|
TObjectPtr<UMaterialInstanceDynamic> BarMID = nullptr;
|
|
|
|
float TargetFill = 1.f;
|
|
float DisplayFill = 1.f;
|
|
float DelayedFill = 1.f;
|
|
float DelayTimer = 0.f;
|
|
|
|
float FlashAmount = 0.f;
|
|
bool bFlashing = false;
|
|
FLinearColor PendingFlashColor = FLinearColor::Red;
|
|
|
|
float PulseAmount = 0.f;
|
|
|
|
static constexpr int32 MaxMaterialZones = 4;
|
|
};
|