Polymorphic Powerup Classes with Player UI Feedback in Verse
What you'll learn
You'll define a powerup_base class with a <virtual> Apply method, then derive freeze_powerup and poison_powerup that <override> it with their own behavior. Because every derived type shares the base type, you can store them all in one []powerup_base array and call Apply without caring which concrete class you're holding — that's polymorphism. We then surface the result to the player by building a real text_block, wrapping it in a canvas, and adding it through GetPlayerUI[] so feedback genuinely renders on screen.
How it works
Verse polymorphism lets a derived class stand in anywhere its base type is expected. The base declares Apply<virtual>(...); each subclass supplies Apply<override>(...). At runtime, the actual instance decides which body runs — so iterating one array and calling Pwr.Apply(...) dispatches to the correct freeze or poison logic automatically.
For the UI, Player.GetPlayerUI[] is a fallible call (note the []), so we bind it inside an if. We construct a text_block, set its text with SetText, place it on a canvas via a canvas_slot, and hand that canvas to UI.AddWidget(...). Because each powerup carries its own DisplayName : message, the same UI code produces different text per type — no branching required.
Let's build it
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Base class: every powerup IS-A powerup_base.
powerup_base := class<abstract>:
# Shared data every powerup carries.
var DisplayName : string = "Unknown Powerup"
# Virtual method — derived classes override the behavior.
Apply(Agent : agent) : void =
Print("Base Apply (should be overridden)")
# Freeze variant overrides Apply with its own logic + name.
freeze_powerup := class(powerup_base):
Apply<override>(Agent : agent) : void =
set DisplayName = "Freeze!"
Print("Freezing target")
# Poison variant — same interface, different behavior.
poison_powerup := class(powerup_base):
Apply<override>(Agent : agent) : void =
set DisplayName = "Poison!"
Print("Poisoning target")
polymorphic_powerup_device := class<concrete>(creative_device):
# One mixed list, treated uniformly through the base type.
Powerups : []powerup_base = array{ freeze_powerup{}, poison_powerup{} }
OnBegin<override>()<suspends>: void =
# Reach the first player; GetPlayers[] is fallible, so guard it.
for (Player : GetPlayspace().GetPlayers()):
# Polymorphic dispatch: each Apply runs its own override.
for (Pwr : Powerups):
Pwr.Apply(Player)
ShowFeedback(Player, Pwr.DisplayName)
# Builds a real text widget and renders it via the Player UI.
ShowFeedback(Player : player, Text : string) : void =
if (UI := GetPlayerUI[Player]):
TextWidget := text_block{ DefaultText := ToMessage(Text) }
# Wrap the text in a canvas so the UI layer can position it.
Canvas := canvas:
Slots := array:
canvas_slot:
Anchors := anchors{ Minimum := vector2{X := 0.5, Y := 0.1}, Maximum := vector2{X := 0.5, Y := 0.1} }
Alignment := vector2{X := 0.5, Y := 0.0}
SizeToContent := true
Widget := TextWidget
# AddWidget makes the canvas (and our text) actually appear.
UI.AddWidget(Canvas)
ToMessage<localizes>(Value : string) : message = "{Value}"```
## Try it yourself
- Add a third subclass, e.g. `heal_powerup := class(powerup_base):` with its own `Apply<override>` and `DisplayName`, then drop `heal_powerup{}` into the `Powerups` array — no other code changes needed. That's the payoff of polymorphism.
- Give `powerup_base` a second virtual method like `Duration<virtual>() : float` and override it per type; read it in `ShowFeedback` to vary how long text stays up.
- Pass `Player` through to a real gameplay device (e.g. damage or movement modifier) inside each `Apply` so the effect does more than print.
## Recap
You built a base `powerup_base` class with a `<virtual>` `Apply`, derived two specialized powerups that `<override>` it, and looped over a single `[]powerup_base` array to dispatch behavior polymorphically. You also wired each activation to a real on-screen `text_block` inside a `canvas`, added through `GetPlayerUI[]`/`AddWidget`, so players see distinct feedback per powerup. Adding new powerups now means one new subclass — not another copy of the same code.
Check your understanding
Test yourself with an interactive quiz and track your progress + earn XP — free for members.
Turn this into a guided course
Add Implementing Polymorphic Powerup Classes in Verse to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.
References
Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.