Scripting
advanced scriptingVoxel Pyramid · Scripting
Like Combat Zone, Voxel Pyramid exposes its generator and plan so you can build gameplay on the generated tomb.
Accessing the generator
var gen = env.world.GetGenerator<PyramidMazeGenerator>();Regenerating
gen.Regenerate(newSeed); // reloads the world with a new monument and mazeKnowing when the plan is ready
gen.CurrentPlan is null until the generator plans during the first chunk pass. Subscribe to VoxelPlayEnvironment.OnWorldLoaded, or check CurrentPlan != null, before driving spawns or objectives from the plan.
Reading the plan
gen.CurrentPlan returns the PyramidMazePlan, which carries the monument geometry as data:
| Member | What it gives you |
|---|---|
| frustum | Centre, base half-width, height, base and apex world Y, sampled ground datum and wall thickness. |
| entrance | Door centre, entry floor, south-face Z, opening size and how far the hall reaches inward. |
| basePosition | World voxel position of the base centre. |
Placing the pyramid in your own world
Set Base Position (in the inspector or on the plan) to drop the pyramid anywhere in an existing world. Because a detail generator only writes the chunks it intersects, you can add the Pyramid Maze Generator to a world that already has other generators (for example beyond a river in a city) and their footprints will not conflict.
Gameplay hooks
gen.TryGetVaultDoorBounds(out min, out max) returns the world-space box of the golden offering door when the river and vault are enabled. The exploration kit behaviours are plain components you can reuse or replace: PyramidCrumblingFloors decays cracked slabs under the player and PyramidVaultDoor listens to OnVoxelDamaged to guard the vault and consume the tribute. The gold currency is the ordinary item of the gold voxel: env.GetItemDefinition(ItemCategory.Voxel, gen.goldVoxel).
Driving creatures: the agent manager
A populated tomb holds hundreds of creatures, nests and traps, and Unity charges for every Update it has to invoke. The kit ticks them from a single place instead. DungeonAgentManager is created on its own the first time an agent registers, as a Dungeon Agents object in the hierarchy, so nothing has to be wired in the scene; drop the component in yourself if you prefer it explicit and that instance takes over.
Your own creature joins in by inheriting DungeonAgent and implementing one method:
public class MyCreature : DungeonAgent {
public override float AgentActiveRange => 20f; // full-rate distance it needs
public override void AgentTick (float deltaTime) {
// deltaTime is the time since THIS agent's own last tick, not the frame time
}
}Registration follows the component's enabled state, so there is nothing to unregister by hand. If your class already has a base class, implement IDungeonAgent instead and call DungeonAgentManager.Register and Unregister yourself. Drop the prefab into a spawner band and it is driven like everything else.
What the manager does with them:
- Near the player (40 m by default, or the agent's own active range if larger) every agent ticks each frame.
- Far away, agents are spread over a stride of frames, so only a fraction of the crowd runs on any one frame. Each still receives the real time elapsed since its own previous tick, so timers do not slow down with the cadence.
- The
VoxelPlayBehaviourof far agents is disabled, which stops Voxel Play recomputing voxel light for creatures nobody is looking at. It is switched back on, and refreshed, when they come close.
Tunables are static and set before the world loads: DungeonAgentManager.nearRange, farStride, suspendLightingWhenFar and cullWithChunks.
Following chunk occlusion culling
When Voxel Play's chunk occlusion culling hides a chunk, the creatures standing in it are behind the same rock. The manager follows that with the engine's own events rather than polling: it subscribes to OnChunkOccluded and OnChunkRevealed and keeps agents grouped by chunk, so a notice only walks the agents in that one chunk. Membership is recomputed when an agent crosses into another chunk, which for a nest or a trap is never.
Only the renderers are switched off, never the behaviour: a creature keeps hunting from behind the wall and simply is not drawn. Set DungeonAgentManager.cullWithChunks = false to opt out. The same two events are available to your own objects, see the Voxel Play 4 events reference.
Arrow traps
DungeonArrowTrap is a wall slit that shoots across a corridor on a fixed beat. It is not aimed and it cannot be dodged by backing away: it is read by its rhythm, and a run of them fires out of phase so crossing becomes a timing problem. The generator raises them on a share of the wall-light anchors, so they always sit flat on a gallery wall facing the corridor; the share, the damage and the interval come from the generator settings, and the prefab only carries the defaults.
Per-trap fields if you place one by hand: fireInterval, triggerRange, damage, boltSpeed, boltRange, hitRadius, boltPrefab and an optional fireSound. A bolt takes life through PyramidVitals, measured against the whole body rather than a single chest point, and the flight is stepped in slices no longer than the hit radius so a slow frame cannot let a bolt pass clean through the player.
Bolt pooling
Bolts are recycled through UnityEngine.Pool.ObjectPool, one pool per bolt prefab shared by every trap that fires it: a tomb with hundreds of slits keeps a handful of bolt objects alive instead of a private set each, and firing allocates nothing. Each trap only holds the state of its own bolts in flight, four at a time. If you swap in your own bolt prefab, it gets its own pool on first use; nothing else is needed.
Reading floor layouts
gen.BuildFloorPreviews(plan) returns the deterministic layout of every maze floor as plain data (grid, cell links, room rects and kinds, pits and stairs) with no Voxel Play calls: the same snapshots the inspector preview renders. Call it on a scratch instance (ScriptableObject.CreateInstance<PyramidMazeGenerator>() sharing the same settings) rather than on the live generator, since it rebuilds internal state.
Custom inventory UI
The demo hotbar (PyramidUI, under Demos/UI) subclasses VoxelPlayUIDefault: hotbar, paged inventory, drag and drop, and the depth and gold readouts. Voxel Play resolves UI overrides from the default assembly, so the script lives in a folder without an asmdef; keep that arrangement if you adapt it for your own game.
Suggest an improvement
Help us improve this documentation page.