# Test Scene Setup Guide This guide walks you through building the PSXSplash test scene in Unity step by step. The scene exercises every major feature: player movement, collision, Lua scripting (all callbacks), cutscenes (loop + callback), UI, audio, triggers, interactables, persist, controls enable/disable, and scene transitions. ## Prerequisites - SplashEdit package installed in Unity - PSXSplash native project cloned and configured in the Control Panel - The Lua files from `test-scene/lua/` copied into your Unity project's Assets folder --- ## Step 1: Create the Scene 1. File > New Scene (Basic Built-in) 2. Save as `TestScene` in your Scenes folder --- ## Step 2: Build the Room Create a simple enclosed room for the player to walk around in. ### Floor 1. GameObject > 3D Object > Plane 2. Name: `Floor` 3. Position: (0, 0, 0), Scale: (3, 1, 3) (gives a 30x30 unit floor) 4. Add component: **PSX Object Exporter** - Bit Depth: 8bpp - Collision Type: **Mesh** (nav regions will be generated from this) ### Walls (4 total) Create 4 stretched cubes around the edges: | Name | Position | Scale | |------|----------|-------| | WallNorth | (0, 2, 15) | (30, 4, 0.5) | | WallSouth | (0, 2, -15) | (30, 4, 0.5) | | WallEast | (15, 2, 0) | (0.5, 4, 30) | | WallWest | (-15, 2, 0) | (0.5, 4, 30) | For each wall: - Add component: **PSX Object Exporter** - Bit Depth: 4bpp - Collision Type: **Mesh** --- ## Step 3: Add the Player 1. Create an empty GameObject named `PSXPlayer` 2. Position: (0, 0, -10) (near the south wall) 3. Add component: **PSX Player** - Move Speed: 2.0 - Sprint Speed: 4.0 - Player Height: 3.0 - Player Radius: 1.0 - Jump Velocity: 8.0 - Gravity: 15.0 --- ## Step 4: Scene Exporter Setup 1. Select the scene root or create an empty `SceneSetup` object 2. Add component: **PSX Scene Exporter** - Scene Type: **Exterior** - GTE Scaling: 100 - Fog: Disabled (or enable for atmosphere) - Scene Lua File: Assign `scene.lua` --- ## Step 5: Create the Objects ### Collectibles (3x) | Name | Position | Lua File | |------|----------|----------| | Collectible1 | (-8, 1, 8) | collectible.lua | | Collectible2 | (0, 1, 8) | collectible.lua | | Collectible3 | (8, 1, 8) | collectible.lua | For each: 1. GameObject > 3D Object > Sphere, scale (0.5, 0.5, 0.5) 2. Add **PSX Object Exporter** - Bit Depth: 4bpp - Collision Type: **Sphere** - Lua File: `collectible.lua` - Collision Radius: 2.0 ### Spinner 1. GameObject > 3D Object > Cube, name: `Spinner` 2. Position: (-8, 1, 2), Scale: (1, 1, 1) 3. Add **PSX Object Exporter** - Lua File: `spinner.lua` - Collision Type: None ### Door 1. GameObject > 3D Object > Cube, name: `Door` 2. Position: (8, 2, 5), Scale: (0.5, 4, 3) 3. Add **PSX Object Exporter** - Collision Type: None - Lua File: `door.lua` 4. Add **PSX Interactable** - Interaction Radius: 3.0 - Interaction Button: Cross - Show Prompt: true - Repeatable: true ### Door Blocker 1. GameObject > 3D Object > Cube, name: `DoorBlocker` 2. Position: (8, 2, 5), Scale: (0.5, 4, 3) 3. Add **PSX Object Exporter** - Collision Type: **Mesh** (blocks the player) - No Lua file needed - the door script finds it by name ### NPC 1. GameObject > 3D Object > Capsule, name: `NPC` 2. Position: (0, 1.5, 2), Scale: (1, 1.5, 1) 3. Add **PSX Object Exporter** - Collision Type: None - Lua File: `npc.lua` 4. Add **PSX Interactable** - Interaction Radius: 3.0 - Interaction Button: Cross - Show Prompt: true - Repeatable: true ### Switch 1. GameObject > 3D Object > Cube, name: `Switch` 2. Position: (-8, 0.5, -5), Scale: (0.5, 1, 0.5) 3. Add **PSX Object Exporter** - Lua File: `switch.lua` 4. Add **PSX Interactable** - Interaction Radius: 2.5 - Interaction Button: Cross - Show Prompt: true - Repeatable: true ### Switch Target 1. GameObject > 3D Object > Cube, name: `SwitchTarget` 2. Position: (-5, 1, -5), Scale: (2, 2, 2) 3. Add **PSX Object Exporter** - Active: true (the switch script will toggle it) ### Movable Object 1. GameObject > 3D Object > Sphere, name: `Movable` 2. Position: (5, 0.5, -5), Scale: (1, 1, 1) 3. Add **PSX Object Exporter** - Lua File: `movable.lua` - Collision Type: None ### Entity Scanner 1. GameObject > 3D Object > Cylinder, name: `Scanner` 2. Position: (0, 1, -8), Scale: (0.5, 1, 0.5) 3. Add **PSX Object Exporter** - Lua File: `entity_scanner.lua` 4. Add **PSX Interactable** - Interaction Radius: 2.5 - Interaction Button: Cross - Show Prompt: true - Repeatable: true --- ## Step 6: Trigger Boxes ### Cutscene Trigger (index 0) 1. Create empty GameObject, name: `CutsceneTrigger` 2. Position: (10, 0, 0) 3. Add **PSXTriggerBox** - Size: (4, 4, 4) - Trigger Index: 0 ### Damage Zone (index 1) 1. Create empty GameObject, name: `DamageZone` 2. Position: (-10, 0, -10) 3. Add **PSXTriggerBox** - Size: (4, 2, 4) - Trigger Index: 1 ### Scene Portal (index 2) 1. Create empty GameObject, name: `ScenePortal` 2. Position: (0, 0, 12) 3. Add **PSXTriggerBox** - Size: (3, 4, 1) - Trigger Index: 2 --- ## Step 7: UI Canvases ### HUD Canvas 1. Create empty GameObject, name: `HUD` 2. Add **PSXCanvas** - Visible: true Add children with **PSXUIBox** or appropriate UI components: | Name | Component | Position | Details | |------|-----------|----------|---------| | ScoreText | PSXUIText | Top-left (10, 10) | Text: "Score: 0" | | StatusText | PSXUIText | Bottom-left (10, 220) | Text: "Welcome!" | | HealthBar | PSXUIProgressBar | Top-right (220, 10) | Value: 100, Width: 80 | ### Dialogue Canvas 1. Create empty GameObject, name: `Dialogue` 2. Add **PSXCanvas** - Visible: false (hidden by default) Add children: | Name | Component | Position | Details | |------|-----------|----------|---------| | DialogueText | PSXUIText | Center-bottom (40, 180) | Text: "" | ### Font 1. Create a **PSXFontAsset** (Right-click > Create > PSXFontAsset) 2. Assign your font texture 3. Reference it in the PSX Scene Exporter's font slot --- ## Step 8: Audio Clips Add the following audio clips to the scene (via PSXAudioClip components or the scene exporter's audio list): | Clip Name | Usage | |-----------|-------| | `collect` | Collectible pickup sound | | `door_open` | Door opening sound | | `switch_on` | Switch activation | | `switch_off` | Switch deactivation | These names must match what the Lua scripts pass to `Audio.Play()`. Use any short WAV files - they will be converted to PS1 ADPCM during export. --- ## Step 9: Cutscenes Create the following PSXCutsceneClip assets and add them to the Scene Exporter's cutscene list: ### ambient_spin A looping animation that rotates an object continuously (used with `loop = true`). - 1 track: **Object RotationY** targeting `Spinner` - Keyframes: frame 0 = 0.0, frame 60 = 2.0 (full rotation in 2 seconds) - Interpolation: Linear - Total frames: 60 ### camera_flyover A camera pan triggered by trigger box 0. - Track 1: **Camera Position** - Frame 0: Player position (0, 3, -10) - Frame 30: Above room (0, 15, 0) - Frame 60: Back to player (0, 3, -10) - Interpolation: EaseInOut - Track 2: **Camera Rotation** - Frame 0: (0.15, 0, 0) (slight downward tilt) - Frame 30: (0.5, 0, 0) (looking straight down) - Frame 60: (0.15, 0, 0) (back to normal) - Interpolation: EaseInOut - Total frames: 60 ### door_open Animates the door object and camera for the door interaction. - Track 1: **Camera Position** (pan to look at door) - Frame 0: (current position, captured automatically) - Frame 15: (7, 3, 2) (viewing angle on door) - Frame 45: (7, 3, 2) (hold) - Frame 60: (current position, blends back) - Interpolation: EaseInOut - Track 2: **Object Position** targeting `Door` - Frame 15: (8, 2, 5) (closed position) - Frame 45: (8, 6, 5) (moved up / opened) - Interpolation: EaseOut - Total frames: 60 --- ## Step 10: Navigation Setup 1. Select the Floor and Wall objects 2. In the PSX Scene Exporter, configure navigation: - Agent Radius: 1.0 - Agent Height: 3.0 - Max Step Height: 0.5 - Max Slope: 45 3. Bake navigation (this generates the nav regions from the floor mesh) 4. Verify the blue nav region overlay covers the walkable area --- ## Step 11: Export and Build 1. Open the SplashEdit Control Panel (Window > SplashEdit > Control Panel) 2. Go to the Scenes tab 3. Add `TestScene` as Scene 0 4. Go to the Build tab 5. Click **Export All Scenes** 6. Click **Build & Run** (for emulator) or **Build ISO** (for real hardware) --- ## What the Test Scene Verifies | Feature | How it's tested | |---------|-----------------| | Player movement | Walk around the room | | Jumping | Jump with Cross button | | Collision | Walk into walls, they block you | | Nav regions | Floor constrains movement | | Gravity | Fall back down after jumping | | onCollideWithPlayer | Touch the collectible spheres | | onInteract | Press Cross near Door, NPC, Switch, Scanner | | onTriggerEnter/Exit | Walk into the trigger boxes | | onButtonPress/Release | Hold Square near the Movable object | | onUpdate | Watch the Spinner rotate continuously | | onCreate/onDestroy | Check debug log at scene load | | onEnable/onDisable | Collect an item (disables it) | | onSceneCreationStart/End | Check debug log | | Cutscene.Play | Walk into trigger box 0 | | Cutscene loop | ambient_spin runs from scene start | | Cutscene onComplete | Door cutscene re-enables controls | | Cutscene.Stop | Stop ambient when needed | | Cutscene.IsPlaying | Door script checks before playing | | Controls.SetEnabled | Disabled during cutscenes and dialogue | | Controls.IsEnabled | Available for query | | Camera.GetPosition | Used by movable.lua | | Camera.SetPosition | Tested via cutscene camera tracks | | Camera.SetRotation | Tested via cutscene camera tracks | | Entity.Find | Door finds DoorBlocker, Switch finds SwitchTarget | | Entity.FindByIndex | Scanner tests this | | Entity.ForEach | Scanner iterates all entities | | Entity.GetCount | Switch and Scanner log it | | Entity.SetActive | Collectible, Switch, Door all toggle objects | | Entity.IsActive | Switch checks target state | | Entity.Get/SetPosition | Movable object moves via Lua | | Entity.Get/SetRotationY | Spinner rotates via Lua | | Vec3 (all functions) | scene.lua tests in onSceneCreationEnd | | PSXMath (all functions) | scene.lua tests in onSceneCreationEnd | | Audio.Play | Collectible, Door, Switch play sounds | | UI.FindCanvas | scene.lua resolves HUD and Dialogue | | UI.FindElement | scene.lua resolves text and progress bar | | UI.SetText | Score, status, dialogue display | | UI.SetProgress | Health bar updates on damage | | UI.SetCanvasVisible | Dialogue canvas show/hide | | Persist.Get/Set | Score persists across scene reloads | | Scene.Load | Portal trigger reloads scene | | Scene.GetIndex | Logged on scene start | | Timer.GetFrameCount | Spinner logs periodically | | Debug.Log | Used throughout all scripts | | Input constants | NPC dialogue uses Input.CROSS | --- ## Debugging Tips - Open the PSX Console window (Window > SplashEdit > PSX Console) to see Debug.Log output - In PCSX-Redux, enable the Lua console to see printf output - In Duckstation, check the CD-ROM debug window for drive state - If something doesn't work, check the debug log for error messages from the Lua scripts