Effect components¶
Every verb other than IS lives as a URuneEffectComponent subclass. The strategy creates one, attaches it to the target actor, calls OnEffectApplied, and removes it on revert. Components own their own state; the rune system never reaches inside them.
URuneEffectComponent (abstract base)¶
Lives at RuneSystem/Components/RuneEffectComponent.h. Marked Blueprintable so Blueprint subclasses are first-class.
Hooks (BlueprintNativeEvent):
OnEffectApplied(VerbRune, ObjectNoun)— the verb activates here. Spawn particles, start timers, register listeners.ObjectNounis null for 2-word sentences.OnEffectRemoved()— clean up. Destroy particles, cancel timers, restore state.CanHandleVerb(VerbRune)— gate. Default returns true; override if a component should be picky.
State:
bEffectActive— true betweenApplyandRemoved. Read from your tick if you want to skip work when inactive.bBidirectional(default true) — controls whether 3-word sentences attach this component to the Object targets too. Set to false for "subject only" verbs (MoveToward).SourceRune— the verb that caused this effect.ObjectNoun— for 3-word relational verbs (MoveToward,Penetration,Hidden), the other noun in the sentence.
Helpers (protected):
GetEventBus()—URuneEventBusaccessor.GetRuneableOwner()— owner cast toARuneableObject, or null.
How attach/revert works¶
UComponentVerbStrategy::AttachComponentToTargets runs once per dispatch:
- Look up which component class to use:
- If the target's noun has the verb in
VerbComponentOverrides, that subclass. - Otherwise the verb's
TwoWordEffectComponentorThreeWordEffectComponent(selected by sentence length). NewObject<URuneEffectComponent>(Target, ComponentClass).RegisterComponent().- Call
OnEffectApplied(Verb, ObjectNoun). - Record the effect in
URuneEffectHistorywithAddedComponentClassset.
Revert reads the history, finds each component on its owner, calls OnEffectRemoved, and destroys it.
Verb roster¶
Defined in Source/Rephrased_Demo/RuneSystem/Components/. Each component is one .h/.cpp pair.
| Verb | Component | Notes |
|---|---|---|
| FloatUp | UFloatUpComponent |
disables gravity, springs to a target height |
| Rotate | URotateComponent |
continuous Z rotation |
| MoveToward | UMoveTowardComponent |
bidirectional false; only subject moves |
| Penetration | UPenetrationComponent |
overlap-only collision; ground is preserved via the ECC_Ground channel (RuneSystemTypes.h) |
| Hidden | UHiddenComponent |
hides on collision with ObjectNoun |
| Burn | UFireComponent |
spreads via the event bus to flammables |
| Flammable | UFlammableComponent |
marker; does not ignite, marks "can be ignited" |
| Dangerous | UDangerousComponent |
hurts the player on contact |
| Slow | USlowComponent |
RuneSpeedScale *= 0.5 |
| Accelerate | UAccelerateComponent |
RuneSpeedScale *= 2.0 |
| Reverse | UReverseComponent |
RuneDirectionScale *= -1 |
| Enlarge | UEnlargeComponent |
uniform scale up |
| Shrink | UShrinkComponent |
uniform scale down |
| Mature | UMatureComponent |
growth-stage transform |
| Regress | URegressComponent |
reverse maturation |
| Stop | UStopComponent |
disables physics, special cases campfire extinguishment |
| Passing | UPassingComponent |
timed passage; tied to the Star Observatory device |
| Shattered | UShatteredRune (actor) |
dropped runes that auto-merge — utility actor, not a verb component |
Assigning components on data assets¶
The roster lists C++ class names (UFireComponent, etc.). In a rune data asset Details panel, pick the Blueprint subclass — typically BP_<Verb>Component under Content/Blueprints/Components/ (for example BP_FireComponent for Burn). See Adding a verb and Content pipeline.
Listener and marker components used by the system but not by direct verb dispatch:
UNounListenerComponent— registers its owner as a listener for a foreign noun. TheURuneableObjectRegistryreturns listeners alongside primary noun matches whenComponentVerbStrategyqueries.ListenerVerbOverrideslets the listener provide its own component class per verb without modifying the verb's data asset.UFlammableComponent— owner can be ignited by a fire spread event. Doesn't burn on its own.UFireSpawnPointComponent— designer-placed scene component on burnable actors.UFireComponentspawns one Niagara instance per spawn point at ignition. See VFX.
UFireComponent (worked example)¶
Most representative non-trivial component.
Behavior:
- On apply: spawn fire Niagara, start
SpreadTimerHandleto broadcastFFireSpreadEventperiodically, optionally scheduleConsumeTimerHandleif the owner has aUFlammableComponentwithbConsumeWhenBurned. - The event bus broadcasts to every other
UFireComponentlistener; the receiver checks distance and ignites the target if it has aUFlammableComponent. - Fire Niagara: one instance per
UFireSpawnPointComponent, or a single instance at the owner's root if no spawn points exist (legacy fallback).
Designer fields:
FireIntensity(default 1.0)SpreadRadius(default 300)SpreadDelay(default 2)FireParticleSystem— the Niagara asset.
The Blueprint subclass BP_FireComponent overrides SpawnFireParticles to assign the project's Niagara system; the C++ default does the spawn, BP just configures.
Bidirectional verbs¶
bBidirectional = true (default) means a 3-word sentence applies to both Subject and Object targets. Penetration and Hidden are bidirectional — "TREE PENETRATION ROCK" puts the component on both trees and rocks because the relationship is symmetric.
MoveToward overrides to false because the rock should not move toward the tree just because the tree is moving toward the rock. Make this decision per component in the constructor:
Stack-aware effects¶
Slow / Accelerate / Reverse mutate RuneSpeedScale and RuneDirectionScale on the runeable. They multiply rather than overwrite, so two Slows stack to 0.25x. Revert undoes the multiply (the strategy records the multiplier in ChangeDescription for debug; the component's OnEffectRemoved divides it back out).
Source files¶
Source/Rephrased_Demo/RuneSystem/Components/RuneEffectComponent.h— baseSource/Rephrased_Demo/RuneSystem/Components/FireComponent.hSource/Rephrased_Demo/RuneSystem/Components/FlammableComponent.hSource/Rephrased_Demo/RuneSystem/Components/FireSpawnPointComponent.hSource/Rephrased_Demo/RuneSystem/Components/NounListenerComponent.hSource/Rephrased_Demo/RuneSystem/Components/MoveTowardComponent.hSource/Rephrased_Demo/RuneSystem/Components/FloatUpComponent.hSource/Rephrased_Demo/RuneSystem/Components/RotateComponent.hSource/Rephrased_Demo/RuneSystem/Components/PenetrationComponent.hSource/Rephrased_Demo/RuneSystem/Components/HiddenComponent.hSource/Rephrased_Demo/RuneSystem/Components/DangerousComponent.hSource/Rephrased_Demo/RuneSystem/Components/SlowComponent.hSource/Rephrased_Demo/RuneSystem/Components/AccelerateComponent.hSource/Rephrased_Demo/RuneSystem/Components/ReverseComponent.hSource/Rephrased_Demo/RuneSystem/Components/EnlargeComponent.hSource/Rephrased_Demo/RuneSystem/Components/ShrinkComponent.hSource/Rephrased_Demo/RuneSystem/Components/MatureComponent.hSource/Rephrased_Demo/RuneSystem/Components/RegressComponent.hSource/Rephrased_Demo/RuneSystem/Components/StopComponent.hSource/Rephrased_Demo/RuneSystem/Components/PassingComponent.h
Known constraints¶
- The TDD's verb list mentions "Burn" but the component is
UFireComponent. Preserved for parity with existing Blueprints; rename is cosmetic. - New verbs require a C++ component until the Blueprint authoring layer ships. Subclassing
URuneEffectComponentin BP works for tuning but not for new tick logic. - Stack arithmetic for Slow/Accelerate/Reverse is multiplicative. Designers stacking many of these should be aware of the floating-point drift after revert.
Change history¶
- 2026-05-23 — Gabriel Li — BP subclass assignment note for data asset Details panel.