Adding a verb (effect component)¶
Designers: Most puzzles only need rune data assets and existing effect components — start with Rune authoring and Adding a rune. This page is for engineers adding new C++ verb behavior.
For verbs that need new behavior. If you're reusing an existing effect component, use Adding a rune instead — no C++ required.
When you need C++¶
The Blueprint authoring layer is in progress (see Content pipeline). Until it ships, any verb that does any of the following needs a C++ component:
- Per-frame work (tick).
- Direct physics manipulation.
- Multi-target broadcasts via
URuneEventBus. - Accessing the
URuneableObjectRegistryfrom inside the effect. - Anything that doesn't fit into "spawn this Niagara, wait N seconds, undo on revert."
For a designer-tunable verb (just particle + state flag), Blueprint subclassing the existing component is enough.
C++ recipe¶
1. Create the header¶
Source/Rephrased_Demo/RuneSystem/Components/MyVerbComponent.h:
#pragma once
#include "CoreMinimal.h"
#include "RuneEffectComponent.h"
#include "MyVerbComponent.generated.h"
UCLASS(ClassGroup=(RuneSystem), meta=(BlueprintSpawnableComponent))
class REPHRASED_DEMO_API UMyVerbComponent : public URuneEffectComponent
{
GENERATED_BODY()
public:
UMyVerbComponent();
virtual void OnEffectApplied_Implementation(URuneDataAsset* InVerbRune, URuneDataAsset* InObjectNoun) override;
virtual void OnEffectRemoved_Implementation() override;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "My Verb")
float SomeKnob = 1.0f;
};
2. Create the source¶
Source/Rephrased_Demo/RuneSystem/Components/MyVerbComponent.cpp:
#include "MyVerbComponent.h"
#include "../../RuneableObject.h"
UMyVerbComponent::UMyVerbComponent()
{
PrimaryComponentTick.bCanEverTick = false;
// Set bBidirectional = false here if 3-word sentences should only affect the Subject.
}
void UMyVerbComponent::OnEffectApplied_Implementation(URuneDataAsset* InVerbRune, URuneDataAsset* InObjectNoun)
{
Super::OnEffectApplied_Implementation(InVerbRune, InObjectNoun);
ARuneableObject* Owner = GetRuneableOwner();
if (!Owner) { return; }
// Apply the effect. Read SomeKnob, mutate Owner state, etc.
}
void UMyVerbComponent::OnEffectRemoved_Implementation()
{
Super::OnEffectRemoved_Implementation();
// Undo whatever OnEffectApplied did.
}
3. Build¶
Right-click the .uproject → Generate Visual Studio project files, then build the editor target. The new class is now visible in TSubclassOf<URuneEffectComponent> dropdowns.
4. Author the data asset¶
Create the verb's URuneDataAsset (see Adding a rune for the recipe).
- Set
WordType = VERB. - Set
TwoWordEffectComponent(and optionallyThreeWordEffectComponent) to a Blueprint subclass ofUMyVerbComponent. Create that BP inContent/Blueprints/: - Right-click → Blueprint Class → All Classes → search
MyVerbComponent. - Name it
BP_MyVerbComponent. - Open it, configure designer-facing defaults (
SomeKnob, particle systems, etc.).
The data asset should reference BP_MyVerbComponent, not UMyVerbComponent directly. That keeps designer config in BP rather than hardcoded in C++.
5. Wire bidirectionality¶
By default URuneEffectComponent::bBidirectional = true — 3-word sentences attach the component to both Subject and Object targets. Override in the constructor when only the Subject should be affected:
UMoveTowardComponent is the existing example.
State to mutate on the runeable¶
The ARuneableObject exposes a few common knobs verbs use:
RuneSpeedScale— multiply for Slow/Accelerate-style verbs. Movement components (FloatUp, MoveToward) read this each tick.RuneDirectionScale—*= -1for Reverse.bIsDisabled— for verbs that effectively turn the object off (Hidden when collided with the object noun).SetNoun(...)— only for IS-style transformation (you almost never call this from a verb component; that'sUNounTransformStrategy's job).
If your verb mutates these stack-style values, undo them in OnEffectRemoved so multiple instances stack correctly.
Persistent components vs one-shot¶
- Persistent — the component lives until revert. Tick logic, ongoing forces, particle systems that should run for the duration.
- One-shot — you do the work in
OnEffectAppliedand immediately setbEffectActive = false. Don't need to wait for revert. Rare; usually a one-shot is just a noun transform, which isIS's job, not a component verb.
Per-noun overrides¶
If a specific noun should react to your verb differently:
- On the noun's
URuneDataAsset, add an entry toVerbComponentOverrides: key = your verb's data asset, value = the override component subclass. - The strategy reads that map first and uses the override class instead of the verb's default.
This is how the campfire makes Stop extinguish flames instead of pausing physics.
Verifying your work¶
- Place an
ARuneableObjectwith a noun your verb can affect. - Place a calculator with two slots.
- Form the sentence.
- The component should appear on the runeable in PIE (check World Outliner → expand the actor).
- Remove the rune. Component should disappear.
- Check
URuneEffectHistory— the calculator should record the apply and revert pair.
Source files¶
Source/Rephrased_Demo/RuneSystem/Components/RuneEffectComponent.h— baseSource/Rephrased_Demo/RuneSystem/Strategies/ComponentVerbStrategy.h— how attach/revert worksSource/Rephrased_Demo/RuneSystem/Components/FireComponent.h— non-trivial example with event bus, spread, particlesSource/Rephrased_Demo/RuneSystem/Components/MoveTowardComponent.h— bidirectional-false example
Change history¶
- 2026-05-23 — Gabriel Li — Designer vs engineer routing callout at top.