Polymorphic Powerup Classes with Player UI Feedback in Verse
Tutorial intermediate compiles

Polymorphic Powerup Classes with Player UI Feedback in Verse

Updated intermediate Code verified

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.

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.

Comments

    Sign in to vote, comment, or suggest an edit. Sign in