Letzte Woche haben wir Dialog aus dem Blueprint-Graph in ein datengetriebenes System geholt. Abilities verdienen dieselbe Behandlung — nur schickt der Standard-Rat Anfänger hier direkt vor die Wand.
Frag irgendwo, wie man Abilities in Unreal baut, und die Antwort ist GAS: das Gameplay Ability System. Es ist wirklich exzellent. Es macht Cooldowns, Kosten, Attribute, Tags, Effekte und Client-Prediction, und Epic shippt Fortnite damit. Es ist aber auch ein Plugin das du in C++ aktivierst, ein Set aus fünf ineinandergreifenden Konzepten, und eine solide Woche deines Lebens, bevor ein Feuerball deine Hand verlässt.
Wenn du solo ein Singleplayer-Spiel baust, ist dieser Tausch meistens falsch. Hier die Version, die es nicht ist.
Was eine Ability wirklich braucht
Runterbrechen. Eine funktionierende Ability hat vier bewegliche Teile:
- Darf ich? (Cooldown, Ressource, State)
- Bezahlen.
- Die Sache tun.
- Der UI Bescheid sagen.
Das war's. Alles andere, was GAS dir gibt — Replication, Prediction, stapelnde Effekte, Attribut-Aggregation — ist echter Mehrwert, aber nur wenn du das Problem hast, das es löst.
Die Form: eine Component, N Data Assets
Pack eine AbilityComponent auf deinen Character. Sie besitzt nichts außer einer Liste und einer Map:
CB0
Jede Ability ist ein Primary Data Asset (UAbilityData) — die Wahl aus dem DataTable-vs-DataAsset-Post. Ein Asset pro Ability, um 4 Uhr morgens editierbar ohne einen Graph anzufassen:
CB1
Eine Ability hinzufügen heißt: Rechtsklick, Data Asset erstellen, sechs Felder ausfüllen. Kein neues Blueprint. Keine neue Klasse.
Cooldowns: eine Zahl, kein Timer
Der Instinkt sagt: ein Timer pro Ability. Lass es. Timer sind Objekte, brauchen Cleanup, und überleben kein Save/Load.
Speicher stattdessen einen Zeitstempel:
CB2
Ein Float pro Ability. GetRemaining(Tag) ist Cooldowns[Tag] - Now, geclampt auf null — das ist dein UI-Radial-Fill, gratis, ohne Per-Frame-Tick. Und weil es nur Zahlen in einer Map sind, wandert es ohne Nachdenken in deinen Save.
Eine Falle: GetTimeSeconds ist World-Time, und World-Time pausiert. Wenn du das Spiel pausierst und die Cooldowns sollen weiterlaufen, willst du GetRealTimeSeconds — such dir eins bewusst aus, statt es später zu merken.
States blocken mit Tags
"Kein Zauber während Stun." "Kein Sprint während Cast." Die Boolean-Variante davon verrottet schnell: bIsStunned && !bIsCasting && bHasMana && !bIsInDialogue.
Gib der Component einen Tag-Container. Stun fügt State.Stunned hinzu. Jedes Ability-Data-Asset bekommt einen BlockedByTags-Container. Die Aktivierung stellt eine Frage:
CB3
Neuer State? Neuer Tag. Kein Boolean, kein Anfassen des Aktivierungs-Codes. Das ist die eine Idee, die es sich lohnt komplett aus GAS zu klauen — FGameplayTag kannst du nutzen, ohne das Ability-System-Plugin überhaupt zu aktivieren.
Der UI Bescheid geben
Die Component broadcastet. OnAbilityActivated(Tag), OnCooldownStarted(Tag, Duration), OnAbilityFailed(Tag, Reason). Das HUD bindet einmal und fragt nie wieder — das Dispatcher-Muster, angewendet wo es offensichtlich hingehört. Dein HUD tickt nicht, und es hält keine Referenz auf deinen Character.
Wann GAS wirklich richtig ist
Ehrlich statt dogmatisch. Wechsel zu GAS wenn:
- Du Multiplayer machst und Abilities sich auf dem Client responsiv anfühlen müssen. Prediction ist wirklich schwer, und GAS hat es schon gelöst.
- Du stapelnde, zeitgesteuerte, aggregierende Effekte brauchst: fünf Gifte gleichzeitig, jedes mit eigener Dauer und Stärke, alle auf einem Attribut.
- Du Attribute hast die sich gegenseitig beeinflussen: Rüstung senkt Schaden, Resistenz senkt Rüstung, ein Buff verändert Resistenz.
Wenn du ein Singleplayer-Action-RPG baust, in dem ein Trank 50 Leben gibt und ein Feuerball 3 Sekunden Cooldown hat, ist GAS eine Framework-Steuer ohne Gegenwert.
Häufige Fehler
- Ein Timer pro Ability. Übersteht kein Save/Load, leakt beim Actor-Destroy, und liefert nichts, was ein Float nicht auch könnte.
- Cooldown-Logik im Character-Blueprint. Dann braucht sie jede Ability-fähige Klasse. Genau dafür ist die Component da.
- Montages und VFX hart im Data Asset referenzieren. Dann lädt jede Ability-Animation, wenn der Character lädt. Soft referenzieren und bei Aktivierung async laden.
- Booleans für States. Sie vermehren sich. Tags nicht.
- Mit GAS anfangen "weil man das so macht", bei 40% abbrechen und einen Halb-GAS-Hybrid shippen. Das ist schlechter als beide Optionen.
- Den Cooldown in der UI prüfen statt in der Component. Die UI ist eine Ansicht. Niemals der Türsteher.
30-Sekunden-Recap
- Vier Teile pro Ability: prüfen, bezahlen, ausführen, melden.
- Eine
AbilityComponentpro Character, ein Primary Data Asset pro Ability. - Cooldowns sind eine
Map<Tag, float>mit Zeitstempeln — speicherbar, tick-frei, UI-fertig. - Gameplay Tags für blockende States; nutzbar ohne das GAS-Plugin.
- Dispatcher zur UI, kein Polling.
- Wechsel zu GAS bei Multiplayer-Prediction, stapelnden Effekten oder interagierenden Attributen — vorher nicht.
Nächsten Sonntag: ein Settings-Menü von Grund auf — Auflösung, V-Sync, Audio-Slider, Tastenbelegung, und welche Teile davon UE 5.3 dir schon abnimmt.
— Marco
Comments
Leave a comment