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>
232 lines
8.8 KiB
Markdown
232 lines
8.8 KiB
Markdown
# Universal Bars
|
||
|
||
PEAK-style universal UMG bars for Unreal Engine 5.7 — one procedural material
|
||
drives every kind of stat bar (health, stamina, hunger, thirst, oxygen, cold,
|
||
shield, injury, boss HP, item durability, progress), with a global subsystem
|
||
API and animated damage / heal / low-value feedback.
|
||
|
||
Everything is **procedural** — no bar textures required. White rounded border,
|
||
soft corners, dark translucent backdrop, bright flat fill: clean cartoon
|
||
survival HUD.
|
||
|
||
---
|
||
|
||
## 1. Install / enable
|
||
|
||
The plugin lives at `Plugins/UniversalBars/`. It is a project plugin and is
|
||
enabled by default. After pulling, regenerate project files and build the
|
||
editor target once (it adds the `UniversalBars` runtime module). Content mounts
|
||
under `/UniversalBars/`.
|
||
|
||
> New C++ classes (a new module) cannot be hot-loaded by Live Coding — do a full
|
||
> editor build the first time.
|
||
|
||
---
|
||
|
||
## 2. What's inside
|
||
|
||
```
|
||
/UniversalBars/
|
||
Materials/
|
||
M_UI_UniversalBar master material (Domain=UI, Translucent, procedural SDF)
|
||
MI_UI_Bar_Health solo green bar
|
||
MI_UI_Bar_Stamina solo yellow-green bar
|
||
MI_UI_Bar_Injury striped "broken HP" bar
|
||
MI_UI_Bar_Shield blue bar + shield overlay
|
||
MI_UI_Bar_Boss segmented boss bar
|
||
MI_UI_Bar_PeakCombined HP + hunger + weight in ONE bar (PEAK capacity)
|
||
Components/
|
||
WBP_UniversalBar one reusable bar (parent: UUniversalBarWidget)
|
||
WBP_BarHealth combined-capacity variant
|
||
WBP_BarStamina stamina variant
|
||
WBP_HUD_InGame ready HUD: health + stamina + status chips
|
||
Theme/ put DA_UniversalBars_* theme assets here
|
||
|
||
C++ (module UniversalBars):
|
||
UUniversalBarWidget one animated bar
|
||
UUniversalHUDWidget HUD container with high-level stat setters
|
||
UUniversalBarsSubsystem global access point (UWorldSubsystem)
|
||
UUniversalBarsTheme palette / geometry / chip-colour DataAsset
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Quick start
|
||
|
||
### Blueprint — easiest path (global API, no widget reference)
|
||
|
||
1. On `BeginPlay` (player controller / HUD), call
|
||
`Universal Bars Subsystem → Create HUD` with `HUD Class = WBP_HUD_InGame`.
|
||
2. From **anywhere** in BP:
|
||
|
||
```
|
||
Get World Subsystem (UniversalBarsSubsystem)
|
||
→ Set Health (0.62) // 0..1, animates + flashes automatically
|
||
→ Set Stamina (0.8)
|
||
→ Set Hunger (0.16) // penalty zone eats into max HP (combined bar)
|
||
→ Set Weight (0.12)
|
||
→ Damage Health (0.2) // red flash + instant drop + lag tail
|
||
→ Heal Health (0.25) // green flash + smooth rise
|
||
```
|
||
|
||
Direction is detected for you: a decrease plays the damage animation, an
|
||
increase plays the heal animation.
|
||
|
||
### C++
|
||
|
||
```cpp
|
||
#include "UniversalBarsSubsystem.h"
|
||
|
||
if (UUniversalBarsSubsystem* Bars = UUniversalBarsSubsystem::Get(this))
|
||
{
|
||
Bars->SetHealth(0.62f);
|
||
Bars->SetHunger(0.16f);
|
||
Bars->DamageHealth(0.2f);
|
||
}
|
||
```
|
||
|
||
### Driving a single bar directly
|
||
|
||
Place a `WBP_UniversalBar` (or a preset variant) anywhere and call:
|
||
|
||
```cpp
|
||
UUniversalBarWidget* Bar = ...;
|
||
Bar->SetFillPercent(0.5f); // animated
|
||
Bar->SetShieldPercent(0.25f);
|
||
Bar->SetSegmentCount(10); // boss segments
|
||
Bar->SetPenaltyZone("Hunger", 0.16f, FLinearColor(0.9f,0.6f,0.2f,1)); // animated zone
|
||
Bar->PlayDamageFlash(); // manual flash
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Animation model (same as the HTML prototype)
|
||
|
||
| Change | Bright fill | Lag tail | Flash |
|
||
|---|---|---|---|
|
||
| **Decrease / damage** | snaps down instantly | holds `DelayedDelay`s, then drains at `DelayedFallSpeed` | red (`DamageFlashColor`) |
|
||
| **Increase / heal** | eases up at `FillRiseSpeed` | jumps to target (lighter "incoming" band) | green (`HealFlashColor`) |
|
||
| **value < `LowThreshold`** | — | — | border pulses (low-value warning) |
|
||
| **penalty zone change** | — | zone width eases at `ZoneInterpSpeed` | — |
|
||
|
||
All tuning fields live on `UUniversalBarWidget` (Bar|Anim category). Set
|
||
`bAutoFlashOnChange=false` to drive flashes manually.
|
||
|
||
Under the hood the material exposes `FillPercent`, `DelayedFillPercent`,
|
||
`FlashAmount`, `LowHPPulseAmount` — the widget tweens these every tick via a
|
||
Dynamic Material Instance.
|
||
|
||
---
|
||
|
||
## 5. Combined "capacity" bar (PEAK)
|
||
|
||
One bar = current value (bright) + depleted-but-recoverable zone (dark) +
|
||
striped penalty zones eating max from the right:
|
||
|
||
- `MaxFillPercent` — right edge of the usable region (`1 - sum(penalties)`).
|
||
- `PenaltyCount` + `PenaltyEnd1..4` + `PenaltyColor1..4` — up to 4 striped zones.
|
||
|
||
You never set these by hand — `SetHunger / SetWeight / SetCold` (HUD) or
|
||
`SetPenaltyZone(Id, Width, Color)` (bar) manage them and animate the widths.
|
||
Set a penalty to `0` to retract its zone.
|
||
|
||
`PenaltyCount = 0` → the same material is a plain solo bar.
|
||
|
||
---
|
||
|
||
## 6. Material parameter reference
|
||
|
||
**Scalars:** `FillPercent`, `DelayedFillPercent`, `ShieldPercent`,
|
||
`MaxFillPercent`, `PenaltyCount`, `PenaltyEnd1..4`, `BarOpacity`,
|
||
`BackgroundOpacity`, `CornerRadius`, `BorderSize`, `InnerPadding`,
|
||
`EdgeSoftness`, `BarAspect`, `FlashAmount`, `LowHPPulseAmount`, `PulseSpeed`,
|
||
`StripeAmount`, `StripeScale`, `StripeSpeed`, `SegmentCount`,
|
||
`SegmentDividerSize`, `SegmentDividerOpacity`, `UseVerticalFill`, `InvertFill`,
|
||
`NoiseAmount`, `TimeOffset`.
|
||
|
||
**Vectors:** `FillColor`, `DelayedFillColor`, `ShieldColor`, `BackgroundColor`,
|
||
`BorderColor`, `EmptyColor`, `FlashColor`, `StripeColorA`, `StripeColorB`,
|
||
`PenaltyColor1..4`.
|
||
|
||
`BarAspect` must roughly match the on-screen width/height ratio so the rounded
|
||
corners stay circular (default 8 ≈ a 600×75 bar).
|
||
|
||
---
|
||
|
||
## 7. Theme
|
||
|
||
`UUniversalBarsTheme` (DataAsset) centralises palette + geometry + chip colours.
|
||
Create one under `/UniversalBars/Theme/` (right-click → Miscellaneous → Data
|
||
Asset → Universal Bars Theme), then assign it to `WBP_HUD_InGame`'s `Theme`
|
||
property. `UUniversalHUDWidget::ApplyTheme()` runs on construct and retints both
|
||
bars and all chips. Per-preset look still lives in the `MI_UI_Bar_*` instances;
|
||
the theme is the HUD-level override.
|
||
|
||
---
|
||
|
||
## 8. Presets (recommended values)
|
||
|
||
| Preset | Fill | Notes |
|
||
|---|---|---|
|
||
| Health | `(0.30,0.85,0.20)` | white border, low-HP pulse, damage lag |
|
||
| Stamina | `(0.85,0.95,0.30)` | thinner, no pulse |
|
||
| Injury | `(0.75,0.20,0.20)` + `StripeAmount=1` | striped "broken" HP |
|
||
| Shield | `(0.30,0.70,1.0)` + `ShieldPercent` | blue + overlay |
|
||
| Boss | `(0.85,0.15,0.15)` + `SegmentCount=10` | wide, segmented, less rounded |
|
||
| PeakCombined | green + Hunger/Weight penalties | one-bar HP+hunger+weight |
|
||
|
||
Keep `BorderColor` pure white and `BorderSize` 0.06–0.10 for the toy/cartoon
|
||
look; `CornerRadius` 0.5–0.7 for horizontal bars.
|
||
|
||
---
|
||
|
||
## 9. Demo / study mode (WBP_HUD_InGame)
|
||
|
||
`WBP_HUD_InGame` ships with **Demo Mode ON** (`UUniversalHUDWidget::bDemoMode`).
|
||
While on, the HUD's `NativeTick` runs a 10-step cycle every `DemoStepInterval`
|
||
(1.6 s) so you can watch every animation live in PIE:
|
||
|
||
```
|
||
0 DamageHealth(0.25) red flash + instant drop + lag tail
|
||
1 SetStamina(0.30) stamina drop
|
||
2 HealHealth(0.20) green flash + smooth rise
|
||
3 SetHunger(0.18) amber zone eases in from the right
|
||
4 SetWeight(0.14) red zone eases in
|
||
5 SetStamina(0.95) stamina refill
|
||
6 HealHealth(0.30)
|
||
7 SetHunger(0.0) hunger zone retracts
|
||
8 SetWeight(0.0) weight zone retracts
|
||
9 DamageHealth(0.45) big hit -> low-HP border pulse
|
||
```
|
||
|
||
To watch: add the HUD (`Subsystem → Create HUD`, or just drop it in any widget /
|
||
PIE) and press Play. The cycle restarts each time the widget constructs.
|
||
|
||
**Turn it off for shipping:** open `WBP_HUD_InGame` → Class Defaults → uncheck
|
||
**Demo Mode**, or call `SetDemoMode(false)`. Read `DemoStepNow()` in
|
||
`UniversalHUDWidget.cpp` to see exactly which API call drives each animation.
|
||
|
||
## 9b. Status chips (PEAK markers)
|
||
|
||
In `WBP_HUD_InGame` the chips live in a `CanvasPanel` (`ChipCanvas`) **overlaid on
|
||
the health bar**, not in a row below it. Each tick `UUniversalHUDWidget::PositionChips()`
|
||
slides them to sit just above the centre of their zone, using
|
||
`UUniversalBarWidget::GetUsableEnd()` / `GetZoneCenter("Hunger"|"Weight"|"Cold")`:
|
||
|
||
- `ChipHeart` → the usable-HP / penalty boundary
|
||
- `ChipHunger` → centre of the hunger zone (hidden until `SetHunger > 0`)
|
||
- `ChipWeight` → centre of the weight zone
|
||
- `ChipCold` → centre of the cold zone
|
||
|
||
So when hunger/weight grow or shrink, the chips ride along with the zone edges.
|
||
Add your own marker by placing an `Image` in `ChipCanvas` and binding it (or extend
|
||
`PositionChips`). Swap the placeholder tints for real icon textures.
|
||
|
||
## 10. Notes / limits
|
||
|
||
- The bar is a UI-domain material — it only renders inside UMG/Slate (not on
|
||
meshes). Verify visuals in the UMG designer or content-browser thumbnail.
|
||
- Up to 4 penalty zones are drawn by the material in a single draw call; the
|
||
widget warns if you push more.
|
||
- `SetFillPercent` clamps to 0..1. Feed it `CurrentHP / MaxHP`, etc.
|