Better testscene
This commit is contained in:
@@ -1,382 +1,78 @@
|
||||
# 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
|
||||
# PSXSplash Test Scene
|
||||
|
||||
This Unity project is a complete test scene for PSXSplash's Lua scripting API.
|
||||
Open it in Unity with the SplashEdit package installed.
|
||||
|
||||
## What's In the Scene
|
||||
|
||||
### Game Objects
|
||||
- **PSXPlayer** - Player controller at (0, 0, -10)
|
||||
- **Floor** - Walkable ground plane
|
||||
- **Wall1-4** - Boundary walls
|
||||
- **Collectible1-3** - Pickup items (onCollideWithPlayer)
|
||||
- **NPC** - Interactable NPC with multi-line dialogue
|
||||
- **Door** - Interactable door with cutscene animation
|
||||
- **DoorBlocker** - Invisible wall removed when door opens
|
||||
- **Switch** - Toggle switch controlling SwitchTarget
|
||||
- **SwitchTarget** - Object toggled by the switch
|
||||
- **Spinner** - Object with looping cutscene rotation (onInteract to toggle)
|
||||
- **Movable** - Object selected via onInteract, moved via D-pad button presses
|
||||
- **Scanner** - Entity scanner terminal (onInteract)
|
||||
|
||||
### Trigger Boxes (PSXTriggerBox)
|
||||
Each trigger has its own Lua script - no trigger index routing.
|
||||
- **CutsceneTrigger** at (-8, 0, 5) - Plays camera_flyover cutscene
|
||||
- **DamageTrigger** at (8, 0, 5) - Damages player on entry
|
||||
- **PortalTrigger** at (0, 0, 12) - Scene transition
|
||||
- **HealTrigger** at (-8, 0, -5) - Heals player on entry
|
||||
|
||||
### UI Canvases (PSXCanvas)
|
||||
- **HUD** (always visible, sort order 10):
|
||||
- ScoreText - shows "Score: 0"
|
||||
- StatusText - shows status messages
|
||||
- HealthBar - progress bar 0-100
|
||||
- **Dialogue** (hidden by default, sort order 20):
|
||||
- DialogueText - shows NPC dialogue lines
|
||||
|
||||
## Still Needed
|
||||
|
||||
### Cutscenes
|
||||
Create PSXCutsceneClip assets with these names and add to SceneExporter:
|
||||
- `ambient_spin` - Looping background animation
|
||||
- `camera_flyover` - One-shot camera pan (Camera Position + Rotation tracks)
|
||||
- `door_open` - Door opening animation (Object Position track)
|
||||
- `spin_loop` - Full 360 rotation for Spinner (Object Rotation track)
|
||||
|
||||
### Audio Clips
|
||||
- `collect` - pickup sound
|
||||
- `door_open` - door opening
|
||||
- `switch_on` / `switch_off` - switch toggle
|
||||
- `heal` - healing sound
|
||||
|
||||
### Navigation
|
||||
Bake nav regions from the floor geometry via PlayStation 1 > Nav Region Builder.
|
||||
|
||||
## Design Notes
|
||||
|
||||
- **Zero onUpdate.** All logic is event-driven.
|
||||
- **Zero float literals.** Uses `1/2` instead of `0.5` etc.
|
||||
- **Each trigger has its own script.** No index-based routing.
|
||||
- **Scene globals.** scene.lua defines: setStatus(), addScore(), applyDamage(),
|
||||
applyHeal(), startDialogue(), advanceDialogue(), isInDialogue(), endDialogue().
|
||||
|
||||
## API Coverage
|
||||
|
||||
| Script | Callbacks | Namespaces |
|
||||
|--------|-----------|------------|
|
||||
| scene.lua | onSceneCreationStart/End | Scene, Persist, UI, Audio, Controls, Cutscene, Timer, Debug, PSXMath, Vec3 |
|
||||
| collectible.lua | onCreate, onDestroy, onEnable, onDisable, onCollideWithPlayer | Entity, Audio, Persist |
|
||||
| door.lua | onCreate, onInteract | Entity, Audio, Controls, Cutscene |
|
||||
| npc.lua | onCreate, onInteract, onButtonPress | Input, Controls, UI |
|
||||
| switch.lua | onCreate, onInteract | Entity, Audio |
|
||||
| spinner.lua | onCreate, onInteract, onCollideWithPlayer | Cutscene, Entity, Timer |
|
||||
| movable.lua | onCreate, onInteract, onButtonPress | Entity, Vec3, Camera, Input |
|
||||
| entity_scanner.lua | onInteract | Entity, Vec3 |
|
||||
| cutscene_trigger.lua | onTriggerEnter | Controls, Cutscene |
|
||||
| damage_trigger.lua | onTriggerEnter, onTriggerExit | Debug |
|
||||
| portal_trigger.lua | onTriggerEnter | Persist, Scene |
|
||||
| heal_trigger.lua | onTriggerEnter, onTriggerExit | Audio, Debug |
|
||||
|
||||
Reference in New Issue
Block a user