Verse Wiki — the Verse handbook for Blueprint authors
Deep Dive · EXTRA

Turning This Device into a Reusable Component

The main lesson turned BP_PressurePlate into one Verse device. It runs — but it does three jobs at once. Lessons 26 and 27 covered Scene Graph's composition model: an entity is a container, and capability comes from the components attached to it. This page takes the same logic apart along those lines — first seeing what the three jobs actually are, then what gets better and what gets more expensive once they are separated.

1. One Device, Three Jobs

Squint at those 43 lines from the main lesson and they are three unrelated things bolted together:

The three barely overlap, and yet they were crammed into one class. Why? Because under inheritance, a thing that can be placed in a level and receive Event BeginPlay is one indivisible lump — the same is true in Blueprint, where BP_PressurePlate is an Actor and its collision box, variables and Event Graph must live together. Want to reuse one part? The classic Blueprint answer is "make a new parent class and push the shared bits up", and the inheritance tree grows until nobody can say where BP_PressurePlate_Timed_Locked_V2 came from.

Composition flips the approach: an entity is an empty container and capability is attached. The same "timed door opening" capability can attach to a pressure plate, a lever, a button, or an empty entity driven purely by a timer — no inheritance relationship required. Scene Graph is that model, and it is built on Verse from the ground up: components are Verse classes, so there is no seam between "half in Blueprint, half in code".

2. The Split: One device → Three Responsibilities

Cut along those three jobs and the map looks like this:

This part of the main lesson's device Who owns it after the split What the split buys you
@editable Plate + Plate.InteractedWithEvent The sensor: does one thing — announce that it happened Swapping the trigger source (button → lever → timer) swaps this one piece; nothing downstream changes
var IsOpen:logic The state: a property of the door, queryable by anyone State follows the door rather than the mechanism that triggered it — two mechanisms on one door no longer means two ledgers
TargetDoor.Disable() / Enable() and the two helper functions The actuator: only ever "open this door / shut this door" The polarity trap is sealed inside one piece forever; exactly one place in the project knows that Disable is what opens it
The loop + Sleep(OpenDuration) choreography The rule: wires "who triggers" to "what is driven", and owns the timing "Press once, open for 5 seconds" becomes a reusable thing in its own right — swap the door or the trigger without rewriting it
@editable OpenDuration:float Travels with the rule The delay belongs to the rule, not the door and not the plate — put it in the right place and duplicate Duration fields stop breeding in the panel

Look closely at row two: IsOpen stops being "the plate's variable" and becomes "the door's property". That is not just a change of address — it puts a real design question on the table: if one door is controlled by two mechanisms, who owns the state? In the main lesson's version, two pressure plates each keep their own IsOpen and the ledgers drift apart sooner or later. After the split there is only one answer: the door keeps it. The biggest payoff of componentization is often not reuse but being forced to answer "who does this data actually belong to".

3. A Middle Form You Can Build Today

Scene Graph's component base class, lifecycle functions and exact syntax are still evolving — check the official docs for those. But the way you cut things up is practiceable today, with tools you already know: three Verse devices, each with one job, strung together by a custom event (Lesson 25 — Blueprint's Event Dispatcher).

plate_sensor.verse (the sensor)
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Concurrency }

# Answers one question: someone triggered it. What happens next is none of its business.
plate_sensor := class(creative_device):

    @editable
    Plate:button_device = button_device{}

    # A custom event = Blueprint's Event Dispatcher (Lesson 25)
    TriggeredEvent<public>:event(agent) = event(agent){}

    OnBegin<override>()<suspends>:void =
        Plate.InteractedWithEvent.Subscribe(OnPlateHit)

    OnPlateHit(Agent:agent):void =
        TriggeredEvent.Signal(Agent)
door_actuator.verse (the actuator, plus the state)
using { /Fortnite.com/Devices }

# Answers one question: how this door opens, how it shuts, what it is right now.
door_actuator := class(creative_device):

    @editable
    TargetDoor:barrier_device = barrier_device{}

    # State follows the door, not the mechanism that triggers it
    var IsOpen:logic = false

    Open<public>():void =
        set IsOpen = true
        TargetDoor.Disable()      # the polarity trap appears in exactly one place

    Close<public>():void =
        set IsOpen = false
        TargetDoor.Enable()
timed_open_rule.verse (the rule)
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/Concurrency }

# Answers one question: after a trigger, how long before it shuts again.
# @editable can reference Verse devices you wrote yourself (Lesson 25)
timed_open_rule := class(creative_device):

    @editable
    Sensor:plate_sensor = plate_sensor{}

    @editable
    Actuator:door_actuator = door_actuator{}

    @editable
    OpenDuration:float = 5.0

    OnBegin<override>()<suspends>:void =
        loop:
            Sensor.TriggeredEvent.Await()
            Actuator.Open()
            Sleep(OpenDuration)
            Actuator.Close()

Graph translation: place all three devices in the level and point them at each other in the Details panel. plate_sensor listens to the button and fires its own Event Dispatcher; timed_open_rule waits for that signal in its own main loop, calls door_actuator's Open(), sleeps OpenDuration seconds, then calls Close(); door_actuator never learns that a pressure plate exists.

Try swapping the trigger: write a lever_sensor that exposes the same TriggeredEvent, and the rule needs not one line changed — just repoint it in the panel. That is the promise of composition, and you already have half of it with today's tools.

4. What Changes on entity + component

The middle form above differs from a real component model in two main ways:

First, ownership becomes real. Right now the three devices know each other through panel references, and there is no physical meaning to who is attached to whom. Under entity + component, the actuator and the state are attached to the door entity, and the sensor is attached to the plate entity. "Which thing does this component belong to" stops being a wire you can point anywhere and becomes the structure itself. Lesson 27 covers writing a component, and 26-x3 is a dedicated exercise in taking an Actor Blueprint apart into components.

Second, configuration gets finer grained. Today you place three devices and wire three references; under a component model, "a door that opens on a timer" can be packaged as a prefab that drags in once with all its components and defaults. This is part of why Epic is changing the skeleton: composition beats inheritance not because it is fashionable, but because past a certain depth nobody dares touch an inheritance tree.

On the timeline, the facts once more in the official phrasing: Scene Graph is UE6's new gameplay framework, built on Verse from the ground up; Actor and Blueprint are fully supported in UE6 Early Access (targeted for late 2027) and the early releases after it, with deprecation waiting on Scene Graph maturity and no date given. So this page is not urging you to refactor today — it is asking you, next time you write something new, to pause and ask: do these three jobs really have to live in one class?

5. Splitting Is Not Free

Having been honest about the benefits, here is the bill. Three pieces cost more than one class: three @editable references to wire in the panel, one event chain to track in your head, and two extra hops for a single trigger to complete its journey. For one door, that may not be worth it.

The test is plain: ask whether the three jobs will each get reused. One door and one mechanism in the whole map? The 43-line version from the main lesson is the correct answer, and splitting is self-inflicted work. Ten doors, five trigger types and three different open/close rules? Then every new combination costs the monolithic style one more class, while the component style costs one more wire. The benefit of composition grows with the number of combinations; the cost of splitting is fixed — where those two curves cross is something only your own project knows.

6. Quick Quiz

After the split, why does IsOpen move to the door side rather than staying with the pressure plate?