Down in the Deeps, the Sunken Athenaeum has a problem every treasure game eventually hits: it needs a lot of treasure. Hand-placing thirty relics — each a mesh, an identity component, a swim animation, and a glow — is how islands drown in copy-paste. The Scene Graph's answer is the prefab: one template that packages mesh + components + child entities, stamped out as fresh instances whenever and wherever you need them. In this lesson you build the relic prefab two ways — the editor-asset way (how you will ship it) and the pure-Verse factory way (so you understand exactly what the editor is doing for you) — and spawn N instances per round at tagged pedestal entities.
What you will build
The relic prefab — the beating heart of the Athenaeum Depths capstone: one template, N spawned treasures per round. It packages two pieces you already built:
relic_componentfrom lesson 10 (deeps-add-component-review): the relic's identity card — name and score value.- The animate-to-targets motor from lesson 12 (animate-to-targets-component-verse): the motion component that makes each spawned relic swim up to its pedestal.
Plus the new skill of this lesson: a vault spawner that finds pedestal entities by tag, instantiates the template at each one, and can sweep every instance away at round end. In the capstone, every relic banked during the Sunken Dive Round becomes one spawned instance of exactly this prefab.
Walkthrough
Step 1 — What a prefab actually is
In the Scene Graph, a class that derives from entity is called a prefab. You normally author one in the editor: assemble an entity with its mesh, components, and child entities, then save it as a prefab asset. UEFN generates a Verse class for it in your project's Assets.digest.verse, and spawning an instance is just constructing that class and parenting it into the scene.
Epic's own guidance (straight from the digest docs) is worth tattooing on a kraken: keep logic in components, not in the entity subclass. Prefabs get restructured constantly during production — if your behaviour lives in components, you can rearrange the prefab freely without refactoring a class hierarchy.
Because the generated class only exists in a project that owns the asset, the compilable code below uses the second form: a Verse factory — a function that builds the same packaged template at runtime with entity{} + AddComponents. Same semantics, and it works on any island.
Step 2 — Tag the pedestals
Under your vault entity, place one small pedestal entity per spawn point and add the relic_spawn_point tag to each (Details panel → Tags). Tags are how Verse finds scene entities without hard-wired references — FindDescendantEntitiesWithTag walks everything beneath the vault and hands back the matches.
Step 3 — Package, spawn, sweep
One complete file: the two imported components (slim recaps, clearly marked), the tag classes, and the vault spawner with its MakeRelic factory.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/Simulation/Tags }
using { /Verse.org/SpatialMath }
# ── Tags: how the vault finds its pedestals, and how cleanup finds relics ──
# In the editor, add the relic_spawn_point tag to each pedestal entity.
relic_spawn_point := class(tag){}
# Stamped onto every spawned relic so end-of-round cleanup can find them.
relic_instance_tag := class(tag){}
# ── From lesson 10: the relic's identity card ──
# Pure data, no logic. This is the component the Athenaeum capstone reads
# when a banked relic is scored.
relic_component := class<final_super>(component):
@editable
var RelicName<public>:string = "Sunken Idol"
@editable
var ScoreValue<public>:int = 100
# ── From lesson 12: the swim-to-pedestal motor (slim recap) ──
# The full eased version lives in the animate-to-targets lesson; this recap
# rises in 20 small steps so a freshly spawned relic visibly swims upward.
animate_to_target_component := class<final_super>(component):
@editable
var RiseHeight<public>:float = 150.0
@editable
var SwimSeconds<public>:float = 2.0
OnSimulate<override>()<suspends>:void =
Start := Entity.GetLocalTransform()
StepHeight := RiseHeight / 20.0
StepTime := SwimSeconds / 20.0
var UpOffset:float = 0.0
var StepsDone:int = 0
loop:
if (StepsDone >= 20):
break
set UpOffset += StepHeight
Target := transform:
Translation := vector3:
Left := Start.Translation.Left
Up := Start.Translation.Up + UpOffset
Forward := Start.Translation.Forward
Rotation := Start.Rotation
Scale := Start.Scale
Entity.SetLocalTransform(Target)
Sleep(StepTime)
set StepsDone += 1
# ── The prefab template + the vault spawner ──
# Attach this to the vault entity. Pedestal entities live UNDER the vault
# in the hierarchy, each tagged relic_spawn_point.
relic_vault_component := class<final_super>(component):
@editable
var RelicsPerRound<public>:int = 5
@editable
var BaseScore<public>:int = 100
# The factory IS the prefab, expressed in Verse: one template that
# packages identity + motion into a fresh entity on every call.
MakeRelic<public>(RelicIndex:int):entity =
RelicEntity := entity{}
Identity := relic_component{Entity := RelicEntity, RelicName := "Deep Relic {RelicIndex}", ScoreValue := BaseScore}
Swimmer := animate_to_target_component{Entity := RelicEntity}
RelicEntity.AddComponents(array{Identity, Swimmer})
RelicEntity.AddTag(relic_instance_tag{})
RelicEntity
OnSimulate<override>()<suspends>:void =
# Spawn one relic instance at each tagged pedestal, up to the cap.
var SpawnedCount:int = 0
for:
SpawnPoint : Entity.FindDescendantEntitiesWithTag(relic_spawn_point)
do:
if (SpawnedCount < RelicsPerRound):
Relic := MakeRelic(SpawnedCount + 1)
# Parenting places the relic AT the pedestal: a fresh entity's
# local transform is identity, so it sits exactly on its parent.
SpawnPoint.AddEntities(array{Relic})
set SpawnedCount += 1
# End of round: sweep every spawned relic back out of the scene.
ClearRelics<public>():void =
for:
Relic : Entity.FindDescendantEntitiesWithTag(relic_instance_tag)
do:
Relic.RemoveFromParent()
Line-by-line highlights
| Lines | What's happening |
|---|---|
relic_spawn_point := class(tag){} |
A tag is just an empty class deriving from tag. The editor surfaces it in every entity's Tags panel. |
relic_component / animate_to_target_component |
The lesson 10 and lesson 12 imports, recapped slim. In your own project, using the module where you defined them rather than re-declaring. |
Entity.GetLocalTransform() / SetLocalTransform |
The lesson 11 transform APIs — the swim is 20 small local-space steps upward. |
MakeRelic |
The factory = the prefab template in code. entity{} makes a blank entity; each component is constructed with Entity := RelicEntity (components must know their parent entity at construction) and then attached with AddComponents. |
RelicEntity.AddTag(relic_instance_tag{}) |
Runtime tagging, so cleanup can find every instance later without keeping an array. |
Entity.FindDescendantEntitiesWithTag(relic_spawn_point) |
Finds every tagged pedestal anywhere beneath the vault — grandchildren included. |
SpawnPoint.AddEntities(array{Relic}) |
THE spawn call. Parenting adds the instance to the scene, runs its components through OnAddedToScene → OnBeginSimulation → OnSimulate, and places it at the pedestal (a fresh entity's local transform is identity). |
Relic.RemoveFromParent() |
The inverse: removal tears the instance down through OnEndSimulation → OnRemovingFromScene. |
Step 4 — Editor checklist
- Create the vault entity; add
relic_vault_componentto it. - Add pedestal child entities beneath it; tag each one
relic_spawn_point. - Set
RelicsPerRound(default 5) andBaseScorein the Details panel. - Launch a session: five relics appear on five pedestals and swim upward.
Common patterns
Pattern 1 — Wake parts the prefab already carries
An editor-authored prefab can ship with native components packaged inside — say a keyframed_movement_component holding a pedestal-orbit animation. Your logic component should query for the part and drive it, never construct a duplicate:
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/Simulation }
# If the relic prefab was authored in the editor with a keyframed mover
# already packaged inside it, wake the mover the moment the relic starts
# simulating. Query, don't construct: the prefab already carries the part.
relic_reveal_component := class<final_super>(component):
OnBeginSimulation<override>():void =
(super:)OnBeginSimulation()
if (Mover := Entity.GetComponent[keyframed_movement_component]):
Mover.Play()
Pattern 2 — Editor prefabs, versioning, and shipping to other islands
# Editor-authored prefabs: in UEFN, assemble the relic once (mesh entity,
# relic_component, animate-to-targets component, glow child entity), then
# right-click it in the Outliner and choose "Create Prefab". UEFN generates
# a Verse class for the asset in your project's Assets.digest.verse:
#
# relic_prefab := class(entity): # generated — never edit by hand
#
# Spawning an instance is then one line instead of a hand-rolled factory:
#
# Instance := relic_prefab{}
# Pedestal.AddEntities(array{Instance})
#
# Every placed or spawned instance keeps a LIVE LINK to the template.
# Update the prefab asset — swap the mesh, retune a component default —
# and every instance on the island picks up the change on the next build.
# A deep-copied entity tree has NO such link: it is a one-time snapshot.
That live link is the versioning story: the prefab asset is the single source of truth, so shipping version 2 of the relic means editing one asset, not thirty instances. To reuse the relic on another island (or hand it to the other zone teams), migrate the prefab asset together with the Verse module that defines its components, and keep every tunable a component @editable — the importing island retunes data in the Details panel instead of editing your code.
Where this goes next
This is piece thirteen of the Athenaeum Depths capstone. Lesson 15 (deeps-custom-asset-component) bolts VFX and SFX asset components into this same prefab — one more reason the packaging matters. Lesson 14's UMG data fields read relic_component.ScoreValue for the pedestal plaques. And in lesson 21, the capstone loop closes: every relic a Diver banks during the Sunken Dive Round spawns one instance of this prefab, which swims — via the lesson 12 motor — to its pedestal in the drowned library. One template. N treasures. Zero copy-paste.