Better testscene

This commit is contained in:
2026-03-29 13:18:13 +02:00
parent 1fdb223f5d
commit 3f462d3482
27 changed files with 3714 additions and 3036 deletions

3
.gitignore vendored
View File

@@ -1,4 +1,7 @@
# SplashEdit build output
./vscode
*.sln
*.slnx
/PSXBuild/
/.tools/
/Library

5
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"recommendations": [
"visualstudiotoolsforunity.vstuc"
]
}

10
.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Unity",
"type": "vstuc",
"request": "attach"
}
]
}

70
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,70 @@
{
"files.exclude": {
"**/.DS_Store": true,
"**/.git": true,
"**/.vs": true,
"**/.gitmodules": true,
"**/.vsconfig": true,
"**/*.booproj": true,
"**/*.pidb": true,
"**/*.suo": true,
"**/*.user": true,
"**/*.userprefs": true,
"**/*.unityproj": true,
"**/*.dll": true,
"**/*.exe": true,
"**/*.pdf": true,
"**/*.mid": true,
"**/*.midi": true,
"**/*.wav": true,
"**/*.gif": true,
"**/*.ico": true,
"**/*.jpg": true,
"**/*.jpeg": true,
"**/*.png": true,
"**/*.psd": true,
"**/*.tga": true,
"**/*.tif": true,
"**/*.tiff": true,
"**/*.3ds": true,
"**/*.3DS": true,
"**/*.fbx": true,
"**/*.FBX": true,
"**/*.lxo": true,
"**/*.LXO": true,
"**/*.ma": true,
"**/*.MA": true,
"**/*.obj": true,
"**/*.OBJ": true,
"**/*.asset": true,
"**/*.cubemap": true,
"**/*.flare": true,
"**/*.mat": true,
"**/*.meta": true,
"**/*.prefab": true,
"**/*.unity": true,
"build/": true,
"Build/": true,
"Library/": true,
"library/": true,
"obj/": true,
"Obj/": true,
"Logs/": true,
"logs/": true,
"ProjectSettings/": true,
"UserSettings/": true,
"temp/": true,
"Temp/": true
},
"files.associations": {
"*.asset": "yaml",
"*.meta": "yaml",
"*.prefab": "yaml",
"*.unity": "yaml",
},
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"*.sln": "*.csproj",
},
"dotnet.defaultSolution": "sampleproj.sln"
}

1
Assets/.~lock.SETUP.md# Normal file
View File

@@ -0,0 +1 @@
,jracek,NTBucitel,29.03.2026 12:52,file:///home/jracek/.config/libreoffice/4;

159
Assets/SETUP.md Normal file
View File

@@ -0,0 +1,159 @@
# PSXSplash Test Scene - Unity Setup Guide
This test scene exercises every Lua API namespace and callback. Follow these steps to set it up in SplashEdit.
## Prerequisites
- Unity project with SplashEdit (the `splashedit` package)
- A font atlas configured (for UI text)
- Audio clips imported (or skip audio-related tests)
## Step 1: Create the Scene
1. Create a new Unity scene
2. Add a **PSXSceneExporter** component to a root GameObject
3. Add a **PSXPlayer** prefab (for player movement, gravity, collision)
4. Add **PSXNavRegion** components to define walkable floor areas
## Step 2: Create Lua Files
Create **LuaFile** ScriptableObjects (Assets > Create > PSXSplash > Lua File) for each script:
| Lua File Name | Script |
|---------------|--------|
| `scene` | `scene.lua` (attach to scene, not an object) |
| `collectible` | `collectible.lua` |
| `door` | `door.lua` |
| `npc` | `npc.lua` |
| `switch` | `switch.lua` |
| `spinner` | `spinner.lua` |
| `movable` | `movable.lua` |
| `entity_scanner` | `entity_scanner.lua` |
Paste each `.lua` file's content into the corresponding LuaFile asset's text field.
## Step 3: Set Up Scene Script
On the PSXSceneExporter, assign the `scene` LuaFile to the **Scene Script** field. This handles `onSceneCreationStart`, `onSceneCreationEnd`, and `onTriggerEnter/Exit`.
## Step 4: Create Game Objects
For each entity script, create a GameObject in the scene:
### Collectibles (x3)
- Create 3 GameObjects with mesh renderers (cubes, spheres, etc.)
- Add **PSXObjectExporter** to each, assign the `collectible` LuaFile
- Space them around the scene so the player can walk into them
- They use `onCollideWithPlayer` - no PSXInteractable needed
### NPC
- Create a GameObject with a character mesh
- Add **PSXObjectExporter**, assign `npc` LuaFile
- Add **PSXInteractable** component (so `onInteract` fires when player presses Cross nearby)
### Door
- Create a door mesh GameObject
- Add **PSXObjectExporter**, assign `door` LuaFile
- Add **PSXInteractable** component
- Create a second GameObject named exactly **"DoorBlocker"** (invisible wall blocking the doorway)
- Add **PSXObjectExporter** to DoorBlocker (no script needed)
- The door script finds it by name and hides it when opened
### Switch
- Create a switch/lever mesh GameObject
- Add **PSXObjectExporter**, assign `switch` LuaFile
- Add **PSXInteractable** component
- Create a second GameObject named exactly **"SwitchTarget"**
- Add **PSXObjectExporter** (no script needed)
- The switch toggles this object's active state
### Spinner
- Create a decorative mesh (pillar, gem, etc.)
- Add **PSXObjectExporter**, assign `spinner` LuaFile
- Add **PSXInteractable** component (so player can start/stop the spin)
### Movable
- Create a box/crate mesh
- Add **PSXObjectExporter**, assign `movable` LuaFile
- Add **PSXInteractable** component (interact to select, then D-pad to move)
### Entity Scanner
- Create a terminal/pedestal mesh
- Add **PSXObjectExporter**, assign `entity_scanner` LuaFile
- Add **PSXInteractable** component
## Step 5: Create Trigger Boxes
Add **PSXTriggerBox** components to empty GameObjects. The scene script handles these by index:
| Trigger Index | Purpose | Placement |
|---------------|---------|-----------|
| 0 | Cutscene zone | Near a scenic viewpoint |
| 1 | Damage zone | In a hazard area (lava, spikes, etc.) |
| 2 | Scene transition portal | At a doorway/exit |
| 3 | Heal zone | Near a health pickup area |
Trigger indices are assigned in the order they appear in the scene hierarchy.
## Step 6: Create UI Canvases
In the SplashEdit UI editor, create two canvases:
### Canvas: "HUD"
| Element Name | Type | Purpose |
|-------------|------|---------|
| ScoreText | Text | Shows "Score: 0" |
| StatusText | Text | Shows status messages |
| HealthBar | Progress | Shows health 0-100 |
### Canvas: "Dialogue"
| Element Name | Type | Purpose |
|-------------|------|---------|
| DialogueText | Text | Shows NPC dialogue lines |
Set the Dialogue canvas to **initially hidden**.
## Step 7: Create Cutscenes
Create **PSXCutsceneClip** assets for:
| Cutscene Name | Type | Description |
|---------------|------|-------------|
| `ambient_spin` | Looping | Background ambient animation (object rotation, etc.) |
| `camera_flyover` | One-shot | Camera pan across the scene (Camera Position + Rotation tracks) |
| `door_open` | One-shot | Door opening animation (Object Position track) |
| `spin_loop` | Looping | Full 360-degree rotation for the spinner object (Object Rotation track) |
## Step 8: Audio Clips
Import or create placeholder audio clips named:
- `collect` - pickup sound
- `door_open` - door opening
- `switch_on` / `switch_off` - switch toggle sounds
- `heal` - healing sound
## Step 9: Build and Test
1. Open Splash Control Panel (Window > PSXSplash > Control Panel)
2. Click **Build and Run**
3. Watch the PSX Console for Debug.Log output from all scripts
4. Walk around and interact with objects to test each callback
## What Each Script Tests
| Script | Callbacks | API Namespaces |
|--------|-----------|----------------|
| scene.lua | onSceneCreationStart, onSceneCreationEnd, onTriggerEnter, onTriggerExit | 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 |
## Key Design Notes
- **No onUpdate anywhere.** All logic is event-driven. Rotation uses a looping cutscene.
- **No float literals.** PS1 Lua uses integer-only numbers. Use `1/2` instead of `0.5`, `1/4` instead of `0.25`, etc.
- **Scene globals.** `scene.lua` defines `addScore()`, `setStatus()`, `startDialogue()`, `advanceDialogue()`, `isInDialogue()`, `endDialogue()` as globals. Other scripts call these directly.

7
Assets/SETUP.md.meta Normal file
View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 302b4fd6078e4e32da249346a54e7647
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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 |

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: e49b0a0d77a22f64c80581f45d810ac5
guid: 5ac18ef38b923116eab9127de3b028e0
TextScriptImporter:
externalObjects: {}
userData:

View File

@@ -132,6 +132,7 @@ GameObject:
- component: {fileID: 172047739}
- component: {fileID: 172047738}
- component: {fileID: 172047742}
- component: {fileID: 900000301}
m_Layer: 0
m_Name: Movable
m_TagString: Untagged
@@ -856,6 +857,7 @@ GameObject:
- component: {fileID: 672874949}
- component: {fileID: 672874948}
- component: {fileID: 672874947}
- component: {fileID: 900000302}
m_Layer: 0
m_Name: Spinner
m_TagString: Untagged
@@ -1099,6 +1101,53 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &717858643
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 717858645}
- component: {fileID: 717858644}
m_Layer: 0
m_Name: Room
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &717858644
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 717858643}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a3c7d8e2f41b5a94b826e91f3d7c0a5e, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXRoom
RoomName:
VolumeSize: {x: 48.78, y: 22.38, z: 57.94}
VolumeOffset: {x: 0, y: 0, z: 0}
--- !u!4 &717858645
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 717858643}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -2.31339, y: 0, z: -0.27116}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &794639167
GameObject:
m_ObjectHideFlags: 0
@@ -1553,6 +1602,596 @@ Transform:
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &900000001
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000002}
- component: {fileID: 900000003}
m_Layer: 0
m_Name: CutsceneTrigger
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &900000002
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000001}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -8, y: 0, z: 5}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &900000003
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000001}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 72b9d8d2e8eafba46a30ba345beb9692, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXTriggerBox
size: {x: 6, y: 4, z: 6}
luaFile: {fileID: 271950057456261835, guid: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6, type: 3}
--- !u!1 &900000011
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000012}
- component: {fileID: 900000013}
m_Layer: 0
m_Name: DamageTrigger
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &900000012
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000011}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 8, y: 0, z: 5}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &900000013
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000011}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 72b9d8d2e8eafba46a30ba345beb9692, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXTriggerBox
size: {x: 4, y: 3, z: 4}
luaFile: {fileID: 271950057456261835, guid: b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7, type: 3}
--- !u!1 &900000021
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000022}
- component: {fileID: 900000023}
m_Layer: 0
m_Name: PortalTrigger
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &900000022
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000021}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 12}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &900000023
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000021}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 72b9d8d2e8eafba46a30ba345beb9692, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXTriggerBox
size: {x: 3, y: 4, z: 3}
luaFile: {fileID: 271950057456261835, guid: c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8, type: 3}
--- !u!1 &900000031
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000032}
- component: {fileID: 900000033}
m_Layer: 0
m_Name: HealTrigger
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &900000032
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000031}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -8, y: 0, z: -5}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &900000033
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000031}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 72b9d8d2e8eafba46a30ba345beb9692, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXTriggerBox
size: {x: 4, y: 3, z: 4}
luaFile: {fileID: 271950057456261835, guid: d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9, type: 3}
--- !u!1 &900000101
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000102}
- component: {fileID: 900000103}
- component: {fileID: 900000104}
m_Layer: 5
m_Name: HUDCanvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &900000102
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000101}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 900000112}
- {fileID: 900000122}
- {fileID: 900000132}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 160, y: 120}
m_SizeDelta: {x: 320, y: 240}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!223 &900000103
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000101}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 2
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!114 &900000104
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000101}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc481397cd94e03409e462478df09d58, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXCanvas
canvasName: HUD
startVisible: 1
sortOrder: 10
defaultFont: {fileID: 0}
--- !u!1 &900000111
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000112}
- component: {fileID: 900000113}
m_Layer: 5
m_Name: ScoreText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &900000112
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000111}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 900000102}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 80, y: -10}
m_SizeDelta: {x: 150, y: 16}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &900000113
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000111}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ca4c021b4490c8f4fb9de4e14055b9e3, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXUIText
elementName: ScoreText
defaultText: 'Score: 0'
textColor: {r: 1, g: 1, b: 1, a: 1}
startVisible: 1
fontOverride: {fileID: 0}
--- !u!1 &900000121
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000122}
- component: {fileID: 900000123}
m_Layer: 5
m_Name: StatusText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &900000122
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000121}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 900000102}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
m_AnchoredPosition: {x: 0, y: 20}
m_SizeDelta: {x: 300, y: 16}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &900000123
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000121}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ca4c021b4490c8f4fb9de4e14055b9e3, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXUIText
elementName: StatusText
defaultText:
textColor: {r: 1, g: 0.92, b: 0, a: 1}
startVisible: 1
fontOverride: {fileID: 0}
--- !u!1 &900000131
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000132}
- component: {fileID: 900000133}
m_Layer: 5
m_Name: HealthBar
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &900000132
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000131}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 900000102}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 1, y: 1}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: -60, y: -10}
m_SizeDelta: {x: 100, y: 12}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &900000133
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000131}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a3c1e93bdff6a714ca5b47989b5b2401, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXUIProgressBar
elementName: HealthBar
backgroundColor: {r: 0.2, g: 0, b: 0, a: 1}
fillColor: {r: 0, g: 1, b: 0, a: 1}
initialValue: 100
startVisible: 1
--- !u!1 &900000201
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000202}
- component: {fileID: 900000203}
- component: {fileID: 900000204}
m_Layer: 5
m_Name: DialogueCanvas
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &900000202
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000201}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 900000212}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 160, y: 120}
m_SizeDelta: {x: 320, y: 240}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!223 &900000203
Canvas:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000201}
m_Enabled: 1
serializedVersion: 3
m_RenderMode: 2
m_Camera: {fileID: 0}
m_PlaneDistance: 100
m_PixelPerfect: 0
m_ReceivesEvents: 1
m_OverrideSorting: 0
m_OverridePixelPerfect: 0
m_SortingBucketNormalizedSize: 0
m_VertexColorAlwaysGammaSpace: 0
m_AdditionalShaderChannelsFlag: 0
m_UpdateRectTransformForStandalone: 0
m_SortingLayerID: 0
m_SortingOrder: 0
m_TargetDisplay: 0
--- !u!114 &900000204
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000201}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: dc481397cd94e03409e462478df09d58, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXCanvas
canvasName: Dialogue
startVisible: 0
sortOrder: 20
defaultFont: {fileID: 0}
--- !u!1 &900000211
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 900000212}
- component: {fileID: 900000213}
m_Layer: 5
m_Name: DialogueText
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &900000212
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000211}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 900000202}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0}
m_AnchorMax: {x: 0.5, y: 0}
m_AnchoredPosition: {x: 0, y: 40}
m_SizeDelta: {x: 280, y: 50}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &900000213
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 900000211}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: ca4c021b4490c8f4fb9de4e14055b9e3, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXUIText
elementName: DialogueText
defaultText:
textColor: {r: 1, g: 1, b: 1, a: 1}
startVisible: 1
fontOverride: {fileID: 0}
--- !u!114 &900000301
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 172047737}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9b542f4ca31fa6548b8914e96dd0fae2, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXInteractable
interactionRadius: 3
interactButton: 15
isRepeatable: 1
cooldownFrames: 30
showPrompt: 1
promptCanvasName: canvas_int
requireLineOfSight: 0
--- !u!114 &900000302
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 672874946}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9b542f4ca31fa6548b8914e96dd0fae2, type: 3}
m_Name:
m_EditorClassIdentifier: net.psxsplash.splashedit.Runtime::SplashEdit.RuntimeCode.PSXInteractable
interactionRadius: 3
interactButton: 15
isRepeatable: 1
cooldownFrames: 30
showPrompt: 1
promptCanvasName: canvas_int
requireLineOfSight: 0
--- !u!1 &903185315
GameObject:
m_ObjectHideFlags: 0
@@ -1974,8 +2613,8 @@ MonoBehaviour:
SceneType: 1
Cutscenes: []
LoadingScreenPrefab: {fileID: 7823618876958668176, guid: c528a266b6b4ef649a6dac4e7d5a71aa, type: 3}
PreviewBVH: 1
PreviewRoomsPortals: 1
PreviewBVH: 0
PreviewRoomsPortals: 0
BVHPreviewDepth: 9999
--- !u!4 &1233752199
Transform:
@@ -2797,3 +3436,10 @@ SceneRoots:
- {fileID: 172047741}
- {fileID: 836539219110679941}
- {fileID: 284994642}
- {fileID: 900000002}
- {fileID: 900000012}
- {fileID: 900000022}
- {fileID: 900000032}
- {fileID: 900000102}
- {fileID: 900000202}
- {fileID: 717858645}

View File

@@ -1,14 +1,13 @@
-- ============================================================================
-- collectible.lua - Pickup item
-- ============================================================================
-- Tests: onCreate, onDestroy, onCollideWithPlayer, onEnable, onDisable,
-- Tests: onCreate, onDestroy, onEnable, onDisable, onCollideWithPlayer,
-- Entity.SetActive, Audio.Play, Persist, self.active, self.position
local collected = false
function onCreate(self)
collected = false
Debug.Log("Collectible created at " .. self.position.x .. "," .. self.position.y .. "," .. self.position.z)
Debug.Log("Collectible created at "
.. self.position.x .. "," .. self.position.y .. "," .. self.position.z)
end
function onDestroy(self)
@@ -28,9 +27,8 @@ function onCollideWithPlayer(self)
collected = true
Audio.Play("collect", 127, 64)
Entity.SetActive(self, false)
-- Update score via scene script global
addScore(100)
setStatus("Collected! +100 points")
Entity.SetActive(self, false)
end

View File

@@ -0,0 +1,18 @@
-- cutscene_trigger.lua - Plays a camera flyover cutscene when player enters
-- Attach to a PSXTriggerBox in the cutscene area
local played = false
function onTriggerEnter()
if played then return end
played = true
setStatus("Cutscene playing...")
Controls.SetEnabled(false)
Cutscene.Play("camera_flyover", {
onComplete = function()
Controls.SetEnabled(true)
setStatus("Cutscene complete!")
played = false -- allow replay
end
})
end

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
-- damage_trigger.lua - Damages player on entry, heals on exit area
-- Attach to a PSXTriggerBox in a hazard zone
function onTriggerEnter()
Debug.Log("Entered damage zone")
setStatus("Ouch! Taking damage!")
applyDamage(25)
end
function onTriggerExit()
Debug.Log("Exited damage zone")
setStatus("Escaped the danger!")
end

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,34 +1,43 @@
-- ============================================================================
-- entity_scanner.lua - Scans all entities on interact (Entity.ForEach test)
-- ============================================================================
-- entity_scanner.lua - Scans all entities on interact
-- Tests: Entity.ForEach, Entity.GetPosition, Entity.IsActive, Entity.GetCount,
-- Entity.FindByIndex, onInteract
-- Entity.FindByIndex, Entity.FindByScriptIndex, Vec3.lerp, Vec3.distanceSq
function onInteract(self)
setStatus("Scanning all entities...")
Debug.Log("=== Entity Scan ===")
Debug.Log("Total entities: " .. Entity.GetCount())
local total = Entity.GetCount()
Debug.Log("Total entities: " .. total)
local activeCount = 0
local inactiveCount = 0
Entity.ForEach(function(obj)
Entity.ForEach(function(obj, index)
local pos = Entity.GetPosition(obj)
local active = Entity.IsActive(obj)
if active then
activeCount = activeCount + 1
else
inactiveCount = inactiveCount + 1
end
Debug.Log(" [" .. index .. "] pos="
.. pos.x .. "," .. pos.y .. "," .. pos.z
.. " active=" .. tostring(Entity.IsActive(obj)))
end)
Debug.Log("Active: " .. activeCount .. " Inactive: " .. inactiveCount)
setStatus("Scan: " .. activeCount .. " active, " .. inactiveCount .. " inactive")
Debug.Log("Active: " .. activeCount .. " of " .. total)
setStatus("Scan: " .. activeCount .. "/" .. total .. " active")
-- Test FindByIndex
local first = Entity.FindByIndex(0)
if first then
local pos = Entity.GetPosition(first)
Debug.Log("Entity 0 at " .. pos.x .. "," .. pos.y .. "," .. pos.z)
end
local byScript = Entity.FindByScriptIndex(0)
if byScript then
Debug.Log("Found entity using script 0")
end
local a = Vec3.new(0, 0, 0)
local b = Vec3.new(10, 20, 30)
local mid = Vec3.lerp(a, b, 1/2)
Debug.Log("Vec3.lerp midpoint: " .. mid.x .. "," .. mid.y .. "," .. mid.z)
local dsq = Vec3.distanceSq(a, b)
Debug.Log("Vec3.distanceSq: " .. dsq)
end

View File

@@ -0,0 +1,14 @@
-- heal_trigger.lua - Heals player when entering the zone
-- Attach to a PSXTriggerBox near a health pickup
function onTriggerEnter()
Debug.Log("Entered heal zone")
setStatus("Healing!")
applyHeal(50)
Audio.Play("heal", 100, 64)
end
function onTriggerExit()
Debug.Log("Left heal zone")
setStatus("Left the healing area")
end

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,43 +1,52 @@
-- ============================================================================
-- movable.lua - Object that can be pushed with button presses
-- ============================================================================
-- Tests: onButtonPress, onButtonRelease, Entity.SetPosition, Vec3 math,
-- Camera.GetPosition, Input constants, self.position
-- movable.lua - Object that teleports on button press (event-driven)
-- Tests: onButtonPress, Entity.SetPosition, Vec3 math, Camera.GetPosition,
-- Input constants, self.position, self.rotationY
local pushing = false
local selected = false
function onCreate(self)
pushing = false
Debug.Log("Movable object created")
selected = false
Debug.Log("Movable object created at "
.. self.position.x .. "," .. self.position.y .. "," .. self.position.z)
end
function onInteract(self)
selected = not selected
if selected then
setStatus("Object selected! D-pad to move, Triangle to deselect.")
else
setStatus("Object deselected.")
end
end
function onButtonPress(self, button)
if button == Input.SQUARE then
pushing = true
if not selected then return end
local pos = self.position
local step = 1
if button == Input.UP then
Entity.SetPosition(self, Vec3.new(pos.x, pos.y, pos.z + step))
elseif button == Input.DOWN then
Entity.SetPosition(self, Vec3.new(pos.x, pos.y, pos.z - step))
elseif button == Input.LEFT then
Entity.SetPosition(self, Vec3.new(pos.x - step, pos.y, pos.z))
elseif button == Input.RIGHT then
Entity.SetPosition(self, Vec3.new(pos.x + step, pos.y, pos.z))
elseif button == Input.L1 then
Entity.SetPosition(self, Vec3.new(pos.x, pos.y + step, pos.z))
elseif button == Input.R1 then
Entity.SetPosition(self, Vec3.new(pos.x, pos.y - step, pos.z))
elseif button == Input.TRIANGLE then
selected = false
setStatus("Object deselected.")
elseif button == Input.SQUARE then
local rot = Entity.GetRotationY(self)
Entity.SetRotationY(self, rot + 1/2)
end
end
function onButtonRelease(self, button)
if button == Input.SQUARE then
pushing = false
end
end
function onUpdate(self, dt)
if not pushing then return end
-- Move toward the camera position (player) slowly
local myPos = self.position
local camPos = Camera.GetPosition()
local dir = Vec3.sub(camPos, myPos)
local dist = Vec3.length(dir)
if dist > 1 then
local norm = Vec3.normalize(dir)
local step = Vec3.mul(norm, dt)
local newPos = Vec3.add(myPos, step)
-- Keep Y the same (don't float)
newPos.y = myPos.y
Entity.SetPosition(self, newPos)
end
local diff = Vec3.sub(self.position, camPos)
local dist = Vec3.length(diff)
Debug.Log("Movable moved. Dist to camera: " .. dist)
end

View File

@@ -0,0 +1,8 @@
-- portal_trigger.lua - Scene transition when player enters
-- Attach to a PSXTriggerBox at a doorway/exit
function onTriggerEnter()
setStatus("Loading next scene...")
Persist.Set("came_from", Scene.GetIndex())
Scene.Load(0) -- reload scene 0 as demo
end

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +1,8 @@
-- ============================================================================
-- scene.lua - Scene-level script for the PSXSplash test scene
-- ============================================================================
-- Tests: onSceneCreationStart, onSceneCreationEnd, onTriggerEnter/Exit (scene),
-- Persist, UI, Audio, Controls, Cutscene, Scene, Timer, Debug, PSXMath
-- Tests: onSceneCreationStart, onSceneCreationEnd, Persist, UI, Audio,
-- Controls, Cutscene, Scene, Timer, Debug, PSXMath, Vec3
-- HUD handles (resolved in onSceneCreationEnd)
local hudCanvas = -1
@@ -48,17 +48,17 @@ function onSceneCreationEnd()
UI.SetCanvasVisible(dialogueCanvas, false)
end
-- Play ambient looping cutscene (tests loop feature)
-- Play ambient looping cutscene
Cutscene.Play("ambient_spin", {loop = true})
-- Test PSXMath functions
-- Test PSXMath functions (all integer args)
local clamped = PSXMath.Clamp(150, 0, 100)
local lerped = PSXMath.Lerp(0, 10, 1)
local lerped = PSXMath.Lerp(0, 10, 1/2)
local sign = PSXMath.Sign(-42)
local abs = PSXMath.Abs(-7)
local mn = PSXMath.Min(3, 5)
local mx = PSXMath.Max(3, 5)
Debug.Log("PSXMath tests: clamp=" .. clamped .. " lerp=" .. lerped
Debug.Log("PSXMath: clamp=" .. clamped .. " lerp=" .. lerped
.. " sign=" .. sign .. " abs=" .. abs .. " min=" .. mn .. " max=" .. mx)
-- Test Vec3 functions
@@ -67,55 +67,17 @@ function onSceneCreationEnd()
local c = Vec3.add(a, b)
local d = Vec3.cross(a, b)
local dist = Vec3.distance(a, b)
Debug.Log("Vec3 tests: add=" .. c.x .. "," .. c.y .. "," .. c.z
Debug.Log("Vec3: add=" .. c.x .. "," .. c.y .. "," .. c.z
.. " cross=" .. d.x .. "," .. d.y .. "," .. d.z
.. " dist=" .. dist)
end
-- ============================================================================
-- Scene-level trigger callbacks (PSXTriggerBox)
-- ============================================================================
function onTriggerEnter(triggerIndex)
Debug.Log("Trigger entered: " .. triggerIndex)
if triggerIndex == 0 then
-- Trigger 0: Cutscene zone
setStatus("Cutscene playing...")
Controls.SetEnabled(false)
Cutscene.Play("camera_flyover", {
onComplete = function()
Controls.SetEnabled(true)
setStatus("Cutscene complete!")
end
})
elseif triggerIndex == 1 then
-- Trigger 1: Damage zone
health = PSXMath.Clamp(health - 25, 0, 100)
updateHealthBar()
setStatus("Ouch! Health: " .. health)
if health <= 0 then
setStatus("You died! Reloading...")
Controls.SetEnabled(false)
Persist.Set("score", 0)
Scene.Load(Scene.GetIndex())
end
elseif triggerIndex == 2 then
-- Trigger 2: Scene transition portal
setStatus("Loading next scene...")
Persist.Set("came_from", Scene.GetIndex())
Scene.Load(0) -- Reload scene 0 as demo
end
end
function onTriggerExit(triggerIndex)
Debug.Log("Trigger exited: " .. triggerIndex)
if triggerIndex == 0 then
setStatus("Left cutscene zone")
elseif triggerIndex == 1 then
setStatus("Escaped damage zone")
end
local scaled = Vec3.mul(a, 3)
local dotVal = Vec3.dot(a, b)
local lenSq = Vec3.lengthSq(Vec3.new(3, 4, 0))
local norm = Vec3.normalize(Vec3.new(0, 5, 0))
Debug.Log("Vec3: mul=" .. scaled.x .. "," .. scaled.y .. "," .. scaled.z
.. " dot=" .. dotVal .. " lenSq=" .. lenSq
.. " norm=" .. norm.x .. "," .. norm.y .. "," .. norm.z)
end
-- ============================================================================
@@ -163,7 +125,27 @@ function isInDialogue()
end
-- ============================================================================
-- Helpers
-- Health system (called from trigger scripts)
-- ============================================================================
function applyDamage(amount)
health = PSXMath.Clamp(health - amount, 0, 100)
updateHealthBar()
if health <= 0 then
setStatus("You died! Reloading...")
Controls.SetEnabled(false)
Persist.Set("score", 0)
Scene.Load(Scene.GetIndex())
end
end
function applyHeal(amount)
health = PSXMath.Clamp(health + amount, 0, 100)
updateHealthBar()
end
-- ============================================================================
-- Helpers (globals accessible from other scripts)
-- ============================================================================
function updateScoreDisplay()
@@ -176,6 +158,13 @@ end
function updateHealthBar()
if healthBar >= 0 then
UI.SetProgress(healthBar, health)
if health > 50 then
UI.SetProgressColors(healthBar, 0, 40, 0, 0, 255, 0)
elseif health > 25 then
UI.SetProgressColors(healthBar, 40, 40, 0, 255, 255, 0)
else
UI.SetProgressColors(healthBar, 40, 0, 0, 255, 0, 0)
end
end
end
@@ -191,3 +180,21 @@ function addScore(amount)
Persist.Set("score", score)
updateScoreDisplay()
end
-- ============================================================================
-- Export shared functions to _G so per-object scripts can call them.
-- Each script gets its own environment with __index = _G as fallback.
-- Functions defined here live in the scene's environment, not _G itself,
-- so we must explicitly publish them.
-- ============================================================================
_G.setStatus = setStatus
_G.addScore = addScore
_G.startDialogue = startDialogue
_G.advanceDialogue = advanceDialogue
_G.isInDialogue = isInDialogue
_G.endDialogue = endDialogue
_G.applyDamage = applyDamage
_G.applyHeal = applyHeal
_G.updateScoreDisplay = updateScoreDisplay
_G.updateHealthBar = updateHealthBar

View File

@@ -1,25 +1,24 @@
-- ============================================================================
-- spinner.lua - Continuously rotating object (onUpdate demo)
-- ============================================================================
-- Tests: onUpdate, self.rotationY, Entity.GetRotationY, Entity.SetRotationY,
-- Timer.GetFrameCount, self.position, Entity.GetPosition
local speed = 1 -- pi-units per frame
-- spinner.lua - Object that spins using a looping cutscene
-- Tests: onCreate, Cutscene.Play with loop, Cutscene.Stop, Cutscene.IsPlaying,
-- onInteract, onCollideWithPlayer, Entity.GetRotationY, Timer
function onCreate(self)
Debug.Log("Spinner created, initial rotY: " .. self.rotationY)
Cutscene.Play("spin_loop", {loop = true})
end
function onUpdate(self, dt)
-- Rotate the object by speed * dt each frame
local current = Entity.GetRotationY(self)
Entity.SetRotationY(self, current + speed * dt)
-- Every 300 frames, log position and rotation (test Timer)
if Timer.GetFrameCount() % 300 == 0 then
local pos = Entity.GetPosition(self)
Debug.Log("Spinner at frame " .. Timer.GetFrameCount()
.. " pos=" .. pos.x .. "," .. pos.y .. "," .. pos.z
.. " rotY=" .. Entity.GetRotationY(self))
function onInteract(self)
if Cutscene.IsPlaying() then
Cutscene.Stop()
setStatus("Spinner stopped!")
Debug.Log("Spinner stopped at rotY=" .. Entity.GetRotationY(self)
.. " frame=" .. Timer.GetFrameCount())
else
Cutscene.Play("spin_loop", {loop = true})
setStatus("Spinner started!")
end
end
function onCollideWithPlayer(self)
Debug.Log("Player touched spinner at frame " .. Timer.GetFrameCount())
end

View File

@@ -9,9 +9,10 @@
"com.unity.render-pipelines.universal": "17.2.0",
"com.unity.test-framework": "1.6.0",
"com.unity.timeline": "1.8.9",
"com.unity.toolchain.linux-x86_64": "2.0.11",
"com.unity.ugui": "2.0.0",
"com.unity.visualscripting": "1.9.7",
"net.psxsplash.splashedit": "file:E:/Code/psxsplashfix/splashedit",
"net.psxsplash.splashedit": "file:/home/jracek/code/secretsplash",
"com.unity.modules.accessibility": "1.0.0",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",

View File

@@ -153,6 +153,22 @@
"com.unity.searcher": "4.9.3"
}
},
"com.unity.sysroot": {
"version": "2.0.10",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.sysroot.linux-x86_64": {
"version": "2.0.9",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.sysroot": "2.0.10"
},
"url": "https://packages.unity.com"
},
"com.unity.test-framework": {
"version": "1.6.0",
"depth": 0,
@@ -185,6 +201,16 @@
},
"url": "https://packages.unity.com"
},
"com.unity.toolchain.linux-x86_64": {
"version": "2.0.11",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.sysroot": "2.0.10",
"com.unity.sysroot.linux-x86_64": "2.0.9"
},
"url": "https://packages.unity.com"
},
"com.unity.ugui": {
"version": "2.0.0",
"depth": 0,
@@ -205,7 +231,7 @@
"url": "https://packages.unity.com"
},
"net.psxsplash.splashedit": {
"version": "file:E:/Code/psxsplashfix/splashedit",
"version": "file:/home/jracek/code/secretsplash",
"depth": 0,
"source": "local",
"dependencies": {}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff