Skip to main content

Scene Management

Polygon Engine projects can contain multiple scenes, but the PS1 runtime loads one authored scene at a time. Build Settings defines which scenes are staged, their deterministic order, and which scene starts when the generated game boots.

Configure Scenes in Build​

Open Build > Build Settings and verify:

  1. Every scene that can be loaded at runtime appears in Scenes In Build.
  2. The intended boot scene is selected as the startup scene.
  3. Scene paths remain inside the project's configured Scenes directory.
  4. Production Acceptance does not report a missing or duplicate build entry.

The build collects dependencies from every included scene and writes the scene mapping to the staged manifest. A scene file existing under Scenes/ is not enough by itself; it must be included in Build Settings.

Reuse a Scene with Its HUD and Scripts​

Use a configured scene as a starting point for another room in the same project. The copy keeps its authored GameObjects, component settings, Lua script references, UI canvases, and HUD elements.

  1. Open the source scene, stop Play Mode, and save with Ctrl+S.
  2. In Windows File Explorer, copy its scene file inside the project's Scenes folder. For example, copy Scenes/room_01.json to Scenes/room_02.json. Copy the source JSON, not a generated build file. Keep the original scene.
  3. In the engine, choose Scene > Open Scene... and open the new file from the Project Browser. Check that you are editing the copy.
  4. Change the room layout while keeping the player, camera, gameplay managers, and HUD you want to reuse. Check references before removing old room objects.
  5. Update room-specific values such as spawn positions, door destinations, interaction targets, and exposed Lua properties. Keep the object and UI names that shared scripts look up.
  6. Save the new scene and add it to Build > Build Settings > Scenes In Build. Set the intended startup scene and update transitions to use the new path.
  7. Test the HUD, controls, and transitions in Play Mode, then rebuild and test both rooms from the generated CUE in DuckStation or on a PlayStation.

Keep both scenes pointing to the same Lua files when they share behavior. You do not need to duplicate scripts, textures, or materials to copy a room. Changes to a shared asset affect every scene using it; make a separate asset first if you need an independent mesh or material variant.

The scene files are independent copies, not linked templates. Later changes to one scene's HUD layout do not automatically update the other. Reusing the setup also does not preserve live Lua variables, GameObjects, or UI across a scene change. Use Session for progress that should survive it.

Load a Scene from Lua​

Use SceneManager.LoadScene() with a staged scene name or path:

function openHub(gameObjectId)
SceneManager.LoadScene("hub")
end

The request is deferred until the runtime reaches its safe scene-transition point. The current scene is not replaced in the middle of the Lua callback. See the Scene Lua API for accepted names and path rules.

Loading Behavior​

Scene loading is an explicit CD-ROM operation. During boot and scene changes, the runtime presents its built-in loading display and pumps progress while it reads staged data. Long CD-XA music is suspended around scene data loading and can be restarted by the audio system after the transition. Resume currently starts the track from its beginning.

The packaged runtime spreads scene reads, asset decode, texture/SPU uploads, and final component initialization across bounded units of work. Scene-local sequential bundles reduce physical seeks; if a valid bundle is unavailable, the same logical files can be read from their loose staged paths. This is an implementation optimization, not a second authoring mode.

The loader preserves the previous scene while checking the destination size and reading its bounded BSN data. A failed size query does not allocate a maximum-size fallback buffer. After the destination header passes validation, the in-place path can release the previous scene to make room for decoding. A failure after that point clears partial state, leaves a valid empty scene, and reports an error. Cancellation and supersession also clean up staging. This is bounded, staged loading; it does not guarantee rollback to the previous playable scene after every failure.

Only one scene transition owns the CD path at a time. The Lua API rejects another request while one is pending. Check its boolean result and do not issue SceneManager.LoadScene() every frame; gate transitions in project state and submit one deliberate request. Acceptance means queued, not fully loaded.

Do not design a transition around instantaneous access. Keep startup and transition scenes within the reported loader and binary-scene budgets, and test from the generated CUE so the test uses the packaged disc layout.

Configure the authored display in Advanced Scene Authoring > Loading & UI. Each scene stores label, colors, optional image texture, bitmap font, progress and percentage visibility, minimum display time, and fade-out duration. The layout remains deliberately fixed and PS1-safe; these settings style its content rather than creating an arbitrary transition Canvas.

The build also copies a compact form of each scene's loading configuration into its staged manifest entry. A transition can therefore select the destination scene's presentation before opening that scene's .BSN, so its colors, label, image/font references, progress policy, and timing can be selected immediately. The image and font must still be read and uploaded: the loader prioritizes them before geometry, but the earliest frame can use the background and fallback text.

Loading display settings​

SettingUser-visible behavior
EnabledUses the authored presentation; when disabled, the native loader uses its basic loading text
LabelShort message; the PS1 loading label holds 63 bytes, and the fixed display width may fit fewer
Image Texture GUIDImported image reference, not a path; included in the scene's texture/VRAM budget
Bitmap FontScene Default or one of the scene's bitmap fonts; its atlas also needs to fit the texture budget
Background / Text / Progress Background / Progress FillColors for the fixed loading layout
Show ProgressShows progress for the current disc read, not a smooth overall scene-completion estimate
Show PercentAdds that read's percentage when progress is enabled; it may restart between reads
Minimum Display (seconds)Minimum presentation duration; use 0–10 seconds for PS1. The editor accepts up to 60, but native playback caps it at 10
Fade Out (seconds)Loading presentation exit duration; use 0–2 seconds for PS1. The editor accepts up to 10, but native playback caps it at 2

For an intentionally black cinematic transition, request Black presentation through Session and transitions. It suppresses the regular image/bar. Scene Lua does not animate during disc loading; finish your door animation before queuing the transition. A load error still exposes diagnostics. Test loading from the packaged disc; Play Mode does not reproduce physical CD timing.

See Advanced Scene Authoring for every field.

State Across Scenes​

Authored GameObjects, UI elements, component state, and scene-local Lua instances belong to the loaded scene. Use Session for temporary run data that must survive scene replacement without becoming a save file:

if Session.Write("game.entry", "warehouse") then
if not SceneManager.LoadScene("Scenes/warehouse.json") then
Log.Print("Scene change was not accepted")
end
end

Session survives scene changes but clears on a new Play session, application exit or console reset. Use stable keys, not scene object IDs. For permanent progress, use SaveData or PlayerPrefs. SaveData.Write() changes its in-memory store; SaveData.Flush() commits it to the memory card. See SaveData for failure handling and format limits.

Example: Restore HUD Progress in the Next Room​

Create a Text element named KeyStatus in the HUD and an enabled GameObject named GameProgress with a Lua Behaviour using Assets/Scripts/GameProgress.lua. Keep this setup in both scenes, referencing the same script:

local keyLabel = -1

local function refreshHud()
if keyLabel < 0 then
return
end

if Session.Read("game.hasKey") == "1" then
Text.SetText(keyLabel, "KEY: YES")
else
Text.SetText(keyLabel, "KEY: NO")
end
end

function Start(gameObjectId)
keyLabel = UI.Find("KeyStatus")
if keyLabel < 0 then
Log.Print("HUD Text KeyStatus was not found")
end
refreshHud()
end

function CollectKey(gameObjectId)
if not Session.Write("game.hasKey", "1") then
Log.Print("Could not store key progress")
return
end

refreshHud()
end

function OpenNextRoom(gameObjectId)
if not SceneManager.LoadScene("Scenes/room_02.json") then
Log.Print("Scene change was not accepted")
end
end

Call CollectKey on the manager from your pickup interaction, and call OpenNextRoom from the first room's exit. From another Lua Behaviour, use GameObject.Invoke to call those functions on GameProgress. Do not call the exit every frame. The example records ownership and updates the HUD; your pickup logic still handles the world object's visibility and inventory rules.

When the destination loads, its new script instance runs Start, resolves the destination's KeyStatus, and restores the HUD from game.hasKey. A missing key returns nil and displays KEY: NO. Do not write a default value unconditionally in every scene's Start, or you will erase progress when changing rooms. Read the stored value first, and initialize it only if it is missing. Reset it only when intentionally starting a new game, for example with Session.Delete("game.hasKey").

Use the same pattern for collected items and opened doors: read their stable keys on scene entry and restore their visible state. Session does not serialize an inventory or the scene automatically. It stores strings, with up to 32 entries, 1–31 bytes per key, and 0–63 bytes per value. Check each write result and keep the data compact. See Session and transitions for the storage contract.

To verify this example, collect the key in the first room and change scenes without stopping Play Mode: the destination HUD should still show KEY: YES. Starting a fresh Play session should show KEY: NO. Test the same transition from the rebuilt CUE; Session alone does not retain progress after a console reset.

Validation Checklist​

  • Every SceneManager.LoadScene() target is in Build Settings.
  • The startup scene has an enabled playable camera.
  • Scene-local scripts do not assume that GameObject IDs from another scene remain valid.
  • Required save keys have sensible defaults when no memory-card data exists.
  • The build stays below the manifest scene cap and per-scene binary limits.
  • Transitions are tested repeatedly from the packaged CUE in DuckStation.
  • Loading progress advances without presenting partially initialized gameplay.
  • A failed destination produces an actionable runtime error and never leaves a partially populated scene active.

For staging and output details, see Build Pipeline.