Revamped collision system

This commit is contained in:
Jan Racek
2026-03-27 16:39:42 +01:00
parent d29ef569b3
commit 1c48b8b425
16 changed files with 318 additions and 136 deletions

View File

@@ -13,11 +13,6 @@ namespace SplashEdit.EditorCode
private SerializedProperty bitDepthProp;
private SerializedProperty luaFileProp;
private SerializedProperty collisionTypeProp;
private SerializedProperty staticColliderProp;
private SerializedProperty exportCollisionMeshProp;
private SerializedProperty customCollisionMeshProp;
private SerializedProperty collisionLayerProp;
private SerializedProperty generateNavigationProp;
private MeshFilter meshFilter;
private MeshRenderer meshRenderer;
@@ -33,11 +28,6 @@ namespace SplashEdit.EditorCode
bitDepthProp = serializedObject.FindProperty("bitDepth");
luaFileProp = serializedObject.FindProperty("luaFile");
collisionTypeProp = serializedObject.FindProperty("collisionType");
staticColliderProp = serializedObject.FindProperty("staticCollider");
exportCollisionMeshProp = serializedObject.FindProperty("exportCollisionMesh");
customCollisionMeshProp = serializedObject.FindProperty("customCollisionMesh");
collisionLayerProp = serializedObject.FindProperty("collisionLayer");
generateNavigationProp = serializedObject.FindProperty("generateNavigation");
CacheMeshInfo();
}
@@ -165,33 +155,19 @@ namespace SplashEdit.EditorCode
EditorGUILayout.PropertyField(collisionTypeProp, new GUIContent("Type"));
var collType = (PSXCollisionType)collisionTypeProp.enumValueIndex;
if (collType != PSXCollisionType.None)
{
EditorGUILayout.PropertyField(staticColliderProp, new GUIContent("Static"));
bool isStatic = staticColliderProp.boolValue;
if (isStatic)
if (collType == PSXCollisionType.Static)
{
EditorGUILayout.LabelField(
"<color=#88cc88>Baked into world collision mesh. No runtime cost.</color>",
PSXEditorStyles.RichLabel);
}
else
else if (collType == PSXCollisionType.Dynamic)
{
EditorGUILayout.LabelField(
"<color=#88aaff>Runtime AABB collider. Fires Lua collision events.</color>",
"<color=#88aaff>Runtime AABB collider. Pushes player back + fires Lua events.</color>",
PSXEditorStyles.RichLabel);
}
EditorGUILayout.Space(2);
EditorGUILayout.PropertyField(exportCollisionMeshProp, new GUIContent("Export Collision Mesh"));
EditorGUILayout.PropertyField(customCollisionMeshProp, new GUIContent("Custom Mesh"));
EditorGUILayout.PropertyField(collisionLayerProp, new GUIContent("Layer"));
}
EditorGUILayout.Space(4);
EditorGUILayout.PropertyField(generateNavigationProp, new GUIContent("Generate Navigation"));
EditorGUI.indentLevel--;
}
@@ -231,5 +207,41 @@ namespace SplashEdit.EditorCode
serializedObject.ApplyModifiedProperties();
}
}
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected)]
private static void DrawColliderGizmo(PSXObjectExporter exporter, GizmoType gizmoType)
{
if (exporter.CollisionType != PSXCollisionType.Dynamic) return;
MeshFilter mf = exporter.GetComponent<MeshFilter>();
Mesh mesh = mf?.sharedMesh;
if (mesh == null) return;
Bounds local = mesh.bounds;
Matrix4x4 worldMatrix = exporter.transform.localToWorldMatrix;
Vector3 ext = local.extents;
Vector3 center = local.center;
Vector3 aabbMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 aabbMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
for (int i = 0; i < 8; i++)
{
Vector3 corner = center + new Vector3(
(i & 1) != 0 ? ext.x : -ext.x,
(i & 2) != 0 ? ext.y : -ext.y,
(i & 4) != 0 ? ext.z : -ext.z
);
Vector3 world = worldMatrix.MultiplyPoint3x4(corner);
aabbMin = Vector3.Min(aabbMin, world);
aabbMax = Vector3.Max(aabbMax, world);
}
bool selected = (gizmoType & GizmoType.Selected) != 0;
Gizmos.color = selected ? new Color(0.2f, 0.8f, 1f, 0.8f) : new Color(0.2f, 0.8f, 1f, 0.3f);
Vector3 c = (aabbMin + aabbMax) * 0.5f;
Vector3 s = aabbMax - aabbMin;
Gizmos.DrawWireCube(c, s);
}
}
}

View File

@@ -194,12 +194,13 @@ namespace SplashEdit.EditorCode
var exporters = FindObjectsOfType<PSXObjectExporter>();
int total = exporters.Length;
int active = exporters.Count(e => e.IsActive);
int withCollision = exporters.Count(e => e.CollisionType != PSXCollisionType.None);
int staticCol = exporters.Count(e => e.StaticCollider && e.CollisionType != PSXCollisionType.None);
int staticCol = exporters.Count(e => e.CollisionType == PSXCollisionType.Static);
int dynamicCol = exporters.Count(e => e.CollisionType == PSXCollisionType.Dynamic);
int triggerBoxes = FindObjectsOfType<PSXTriggerBox>().Length;
EditorGUILayout.BeginVertical(PSXEditorStyles.CardStyle);
EditorGUILayout.LabelField(
$"<b>{active}</b>/{total} objects | <b>{withCollision}</b> colliders ({staticCol} static)",
$"<b>{active}</b>/{total} objects | <b>{staticCol}</b> static <b>{dynamicCol}</b> dynamic <b>{triggerBoxes}</b> triggers",
PSXEditorStyles.RichLabel);
EditorGUILayout.EndVertical();
}

View File

@@ -0,0 +1,94 @@
using UnityEngine;
using UnityEditor;
using SplashEdit.RuntimeCode;
namespace SplashEdit.EditorCode
{
[CustomEditor(typeof(PSXTriggerBox))]
public class PSXTriggerBoxEditor : UnityEditor.Editor
{
private SerializedProperty sizeProp;
private SerializedProperty luaFileProp;
private void OnEnable()
{
sizeProp = serializedObject.FindProperty("size");
luaFileProp = serializedObject.FindProperty("luaFile");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.LabelField("PSX Trigger Box", EditorStyles.boldLabel);
EditorGUILayout.Space(4);
EditorGUILayout.PropertyField(sizeProp, new GUIContent("Size"));
EditorGUILayout.PropertyField(luaFileProp, new GUIContent("Lua Script"));
if (luaFileProp.objectReferenceValue != null)
{
EditorGUILayout.BeginHorizontal();
GUILayout.Space(EditorGUI.indentLevel * 15);
if (GUILayout.Button("Edit", EditorStyles.miniButtonLeft, GUILayout.Width(50)))
AssetDatabase.OpenAsset(luaFileProp.objectReferenceValue);
if (GUILayout.Button("Clear", EditorStyles.miniButtonRight, GUILayout.Width(50)))
luaFileProp.objectReferenceValue = null;
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
}
else
{
EditorGUILayout.BeginHorizontal();
GUILayout.Space(EditorGUI.indentLevel * 15);
if (GUILayout.Button("Create Lua Script", EditorStyles.miniButton, GUILayout.Width(130)))
CreateNewLuaScript();
GUILayout.FlexibleSpace();
EditorGUILayout.EndHorizontal();
}
serializedObject.ApplyModifiedProperties();
}
private void CreateNewLuaScript()
{
var trigger = target as PSXTriggerBox;
string defaultName = trigger.gameObject.name.ToLower().Replace(" ", "_");
string path = EditorUtility.SaveFilePanelInProject(
"Create Lua Script", defaultName + ".lua", "lua",
"Create a new Lua script for this trigger box");
if (string.IsNullOrEmpty(path)) return;
string template =
"function onTriggerEnter(triggerIndex)\nend\n\nfunction onTriggerExit(triggerIndex)\nend\n";
System.IO.File.WriteAllText(path, template);
AssetDatabase.Refresh();
var luaFile = AssetDatabase.LoadAssetAtPath<LuaFile>(path);
if (luaFile != null)
{
luaFileProp.objectReferenceValue = luaFile;
serializedObject.ApplyModifiedProperties();
}
}
[DrawGizmo(GizmoType.Selected | GizmoType.NonSelected)]
private static void DrawTriggerGizmo(PSXTriggerBox trigger, GizmoType gizmoType)
{
bool selected = (gizmoType & GizmoType.Selected) != 0;
Gizmos.color = selected ? new Color(0.2f, 1f, 0.3f, 0.8f) : new Color(0.2f, 1f, 0.3f, 0.25f);
Gizmos.matrix = trigger.transform.localToWorldMatrix;
Gizmos.DrawWireCube(Vector3.zero, trigger.Size);
if (selected)
{
Gizmos.color = new Color(0.2f, 1f, 0.3f, 0.08f);
Gizmos.DrawCube(Vector3.zero, trigger.Size);
}
Gizmos.matrix = Matrix4x4.identity;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5bdf647efcaa11a469e2e99025e3a20e

View File

@@ -15,7 +15,6 @@ namespace SplashEdit.RuntimeCode
Solid = 0x01,
Slope = 0x02,
Stairs = 0x04,
Trigger = 0x08,
NoWalk = 0x10,
}
@@ -84,8 +83,8 @@ namespace SplashEdit.RuntimeCode
foreach (var exporter in exporters)
{
// Dynamic objects are handled by the runtime collision system, skip them
if (!exporter.StaticCollider && exporter.CollisionType != PSXCollisionType.None)
// Dynamic objects use runtime AABB colliders, skip them
if (exporter.CollisionType == PSXCollisionType.Dynamic)
continue;
PSXCollisionType effectiveType = exporter.CollisionType;
@@ -94,7 +93,7 @@ namespace SplashEdit.RuntimeCode
{
if (autoIncludeSolid)
{
effectiveType = PSXCollisionType.Solid;
effectiveType = PSXCollisionType.Static;
autoIncluded++;
}
else
@@ -103,11 +102,8 @@ namespace SplashEdit.RuntimeCode
}
}
// Get the collision mesh (custom or render mesh)
MeshFilter mf = exporter.GetComponent<MeshFilter>();
Mesh collisionMesh = exporter.CustomCollisionMesh != null
? exporter.CustomCollisionMesh
: mf?.sharedMesh;
Mesh collisionMesh = mf?.sharedMesh;
if (collisionMesh == null)
continue;
@@ -133,22 +129,13 @@ namespace SplashEdit.RuntimeCode
// Determine surface flags
byte flags = 0;
if (effectiveType == PSXCollisionType.Trigger)
{
flags = (byte)PSXSurfaceFlag.Trigger;
}
else
{
// Floor-like: normal.y > cosWalkable
// Note: Unity Y is up; PS1 Y is down. We export in Unity space
// and convert to PS1 space during WriteToBinary.
float dotUp = normal.y;
if (dotUp > cosWalkable)
{
flags = (byte)PSXSurfaceFlag.Solid;
// Check if stairs (tagged on exporter or steep-ish)
if (dotUp < 0.95f && dotUp > cosWalkable)
{
flags |= (byte)PSXSurfaceFlag.Stairs;
@@ -156,15 +143,12 @@ namespace SplashEdit.RuntimeCode
}
else if (dotUp > 0.0f)
{
// Slope too steep to walk on
flags = (byte)(PSXSurfaceFlag.Solid | PSXSurfaceFlag.Slope);
}
else
{
// Wall or ceiling
flags = (byte)PSXSurfaceFlag.Solid;
}
}
_allTriangles.Add(new CollisionTriExport
{

View File

@@ -187,23 +187,48 @@ namespace SplashEdit.RuntimeCode
}
}
// ── Font pixel data (written BEFORE the UI table, alongside atlas/CLUT data) ──
// The C++ parser expects canvas descriptors immediately after font descriptors
// (font pixel data is at absolute offsets, not inline). Write pixel data here
// so it doesn't sit between font descriptors and canvas descriptors.
List<long> fontDataOffsetPositions = new List<long>();
List<long> fontPixelDataPositions = new List<long>();
if (fonts != null)
{
for (int fi = 0; fi < fonts.Length; fi++)
{
var font = fonts[fi];
if (font.PixelData == null || font.PixelData.Length == 0)
{
fontPixelDataPositions.Add(0);
continue;
}
AlignToFourBytes(writer);
long dataPos = writer.BaseStream.Position;
writer.Write(font.PixelData);
fontPixelDataPositions.Add(dataPos);
}
}
// ── UI table (same format as splashpack UI section) ──
AlignToFourBytes(writer);
long uiTableStart = writer.BaseStream.Position;
// ── Font descriptors (112 bytes each) ──
List<long> fontDataOffsetPositions = new List<long>();
if (fonts != null)
{
foreach (var font in fonts)
for (int fi = 0; fi < fonts.Length; fi++)
{
var font = fonts[fi];
writer.Write(font.GlyphWidth); // [0]
writer.Write(font.GlyphHeight); // [1]
writer.Write(font.VramX); // [2-3]
writer.Write(font.VramY); // [4-5]
writer.Write(font.TextureHeight); // [6-7]
fontDataOffsetPositions.Add(writer.BaseStream.Position);
writer.Write((uint)0); // [8-11] dataOffset placeholder
// dataOffset: use the pre-written pixel data position
long pixPos = fontPixelDataPositions[fi];
writer.Write((uint)pixPos); // [8-11] dataOffset (0 if no data)
writer.Write((uint)(font.PixelData?.Length ?? 0)); // [12-15] dataSize
if (font.AdvanceWidths != null && font.AdvanceWidths.Length >= 96)
writer.Write(font.AdvanceWidths, 0, 96);
@@ -212,26 +237,13 @@ namespace SplashEdit.RuntimeCode
}
}
// ── Font pixel data ──
if (fonts != null)
{
for (int fi = 0; fi < fonts.Length; fi++)
{
var font = fonts[fi];
if (font.PixelData == null || font.PixelData.Length == 0) continue;
AlignToFourBytes(writer);
long dataPos = writer.BaseStream.Position;
writer.Write(font.PixelData);
long curPos = writer.BaseStream.Position;
writer.Seek((int)fontDataOffsetPositions[fi], SeekOrigin.Begin);
writer.Write((uint)dataPos);
writer.Seek((int)curPos, SeekOrigin.Begin);
}
}
// Canvas descriptors now follow immediately after font descriptors
// (no font pixel data in between — it was written above).
// ── Canvas descriptor (12 bytes) ──
// Must align here: the C++ parser aligns fontDataEnd to 4 bytes
// when skipping past font pixel data to find the canvas descriptor.
AlignToFourBytes(writer);
var elements = canvas.Elements ?? new PSXUIElementData[0];
string cvName = canvas.Name ?? "loading";
if (cvName.Length > 24) cvName = cvName.Substring(0, 24);

View File

@@ -312,6 +312,8 @@ namespace SplashEdit.RuntimeCode
{
foreach (var exporter in exporters)
{
if (exporter.CollisionType == PSXCollisionType.Dynamic)
continue;
MeshFilter mf = exporter.GetComponent<MeshFilter>();
Mesh mesh = mf?.sharedMesh;

View File

@@ -8,9 +8,8 @@ namespace SplashEdit.RuntimeCode
public enum PSXCollisionType
{
None = 0,
Solid = 1,
Trigger = 2,
Platform = 3
Static = 1,
Dynamic = 2
}
[RequireComponent(typeof(Renderer))]
@@ -29,22 +28,11 @@ namespace SplashEdit.RuntimeCode
[SerializeField] private PSXBPP bitDepth = PSXBPP.TEX_8BIT;
[SerializeField] private LuaFile luaFile;
[FormerlySerializedAs("collisionType")]
[SerializeField] private PSXCollisionType collisionType = PSXCollisionType.None;
[SerializeField] private bool staticCollider = true;
[SerializeField] private bool exportCollisionMesh = false;
[SerializeField] private Mesh customCollisionMesh;
[Range(1, 8)]
[SerializeField] private int collisionLayer = 1;
[SerializeField] private bool generateNavigation = false;
public PSXBPP BitDepth => bitDepth;
public PSXCollisionType CollisionType => collisionType;
public bool StaticCollider => staticCollider;
public bool ExportCollisionMesh => exportCollisionMesh;
public Mesh CustomCollisionMesh => customCollisionMesh;
public int CollisionLayer => collisionLayer;
public bool GenerateNavigation => generateNavigation;
private readonly Dictionary<(int, PSXBPP), PSXTexture2D> cache = new();

View File

@@ -58,6 +58,7 @@ namespace SplashEdit.RuntimeCode
// Component arrays
private PSXInteractable[] _interactables;
private PSXAudioSource[] _audioSources;
private PSXTriggerBox[] _triggerBoxes;
// Phase 3+4: World collision and nav regions
private PSXCollisionExporter _collisionExporter;
@@ -120,6 +121,7 @@ namespace SplashEdit.RuntimeCode
// Collect components
_interactables = FindObjectsByType<PSXInteractable>(FindObjectsSortMode.None);
_audioSources = FindObjectsByType<PSXAudioSource>(FindObjectsSortMode.None);
_triggerBoxes = FindObjectsByType<PSXTriggerBox>(FindObjectsSortMode.None);
// Collect UI image textures for VRAM packing alongside 3D textures
PSXUIImage[] uiImages = FindObjectsByType<PSXUIImage>(FindObjectsSortMode.None);
@@ -164,7 +166,7 @@ namespace SplashEdit.RuntimeCode
_collisionExporter = new PSXCollisionExporter();
_collisionExporter.Build(_exporters, GTEScaling);
if (_collisionExporter.MeshCount == 0)
Debug.LogWarning("No collision meshes! Set CollisionType=Solid on your floor/wall objects.");
Debug.LogWarning("No collision meshes! Set CollisionType=Static on your floor/wall objects.");
// Phase 4+5: Room volumes are needed by BOTH the nav region builder
// (for spatial room assignment) and the room builder (for triangle assignment).
@@ -295,6 +297,7 @@ namespace SplashEdit.RuntimeCode
audioSources = _audioSources,
canvases = _canvases,
fonts = _fonts,
triggerBoxes = _triggerBoxes,
};
PSXSceneWriter.Write(path, in scene, (msg, type) =>

View File

@@ -39,6 +39,9 @@ namespace SplashEdit.RuntimeCode
// Custom fonts (v13, embedded in UI block)
public PSXFontData[] fonts;
// Trigger boxes (v16)
public PSXTriggerBox[] triggerBoxes;
// Player
public Vector3 playerPos;
public Quaternion playerRot;
@@ -105,32 +108,40 @@ namespace SplashEdit.RuntimeCode
}
if (scene.sceneLuaFile != null && !luaFiles.Contains(scene.sceneLuaFile))
luaFiles.Add(scene.sceneLuaFile);
// Trigger box Lua files
if (scene.triggerBoxes != null)
{
foreach (var tb in scene.triggerBoxes)
{
if (tb.LuaFile != null && !luaFiles.Contains(tb.LuaFile))
luaFiles.Add(tb.LuaFile);
}
}
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{
int colliderCount = 0;
foreach (var e in scene.exporters)
{
if (e.CollisionType == PSXCollisionType.None || e.StaticCollider)
continue;
Mesh cm = e.CustomCollisionMesh != null
? e.CustomCollisionMesh
: e.GetComponent<MeshFilter>()?.sharedMesh;
if (cm != null)
if (e.CollisionType != PSXCollisionType.Dynamic) continue;
MeshFilter mf = e.GetComponent<MeshFilter>();
if (mf?.sharedMesh != null)
colliderCount++;
}
int triggerBoxCount = scene.triggerBoxes?.Length ?? 0;
// Build exporter index lookup for components
Dictionary<PSXObjectExporter, int> exporterIndex = new Dictionary<PSXObjectExporter, int>();
for (int i = 0; i < scene.exporters.Length; i++)
exporterIndex[scene.exporters[i]] = i;
// ──────────────────────────────────────────────────────
// Header (104 bytes — splashpack v15)
// Header (104 bytes — splashpack v16)
// ──────────────────────────────────────────────────────
writer.Write('S');
writer.Write('P');
writer.Write((ushort)15);
writer.Write((ushort)16);
writer.Write((ushort)luaFiles.Count);
writer.Write((ushort)scene.exporters.Length);
writer.Write((ushort)scene.atlases.Length);
@@ -156,7 +167,7 @@ namespace SplashEdit.RuntimeCode
writer.Write((ushort)scene.bvh.TriangleRefCount);
writer.Write((ushort)scene.sceneType);
writer.Write((ushort)0); // pad0
writer.Write((ushort)triggerBoxCount); // was pad0
writer.Write((ushort)scene.collisionExporter.MeshCount);
writer.Write((ushort)scene.collisionExporter.TriangleCount);
@@ -278,30 +289,51 @@ namespace SplashEdit.RuntimeCode
}
// ──────────────────────────────────────────────────────
// Collider metadata (32 bytes each)
// Collider metadata (32 bytes each) — Dynamic objects only
// ──────────────────────────────────────────────────────
for (int exporterIdx = 0; exporterIdx < scene.exporters.Length; exporterIdx++)
{
PSXObjectExporter exporter = scene.exporters[exporterIdx];
if (exporter.CollisionType == PSXCollisionType.None || exporter.StaticCollider)
continue;
if (exporter.CollisionType != PSXCollisionType.Dynamic) continue;
MeshFilter meshFilter = exporter.GetComponent<MeshFilter>();
Mesh collisionMesh = exporter.CustomCollisionMesh != null
? exporter.CustomCollisionMesh
: meshFilter?.sharedMesh;
Mesh renderMesh = meshFilter?.sharedMesh;
if (renderMesh == null) continue;
if (collisionMesh == null)
continue;
WriteWorldAABB(writer, exporter, renderMesh.bounds, gte);
WriteWorldAABB(writer, exporter, collisionMesh.bounds, gte);
// Collision metadata (8 bytes)
writer.Write((byte)exporter.CollisionType);
writer.Write((byte)(1 << (exporter.CollisionLayer - 1)));
writer.Write((byte)1); // CollisionType::Solid on C++ side
writer.Write((byte)0xFF); // layerMask (all layers)
writer.Write((ushort)exporterIdx);
writer.Write((uint)0);
}
// ──────────────────────────────────────────────────────
// Trigger box metadata (32 bytes each)
// ──────────────────────────────────────────────────────
if (scene.triggerBoxes != null)
{
foreach (var tb in scene.triggerBoxes)
{
Bounds wb = tb.GetWorldBounds();
Vector3 wMin = wb.min;
Vector3 wMax = wb.max;
writer.Write(PSXTrig.ConvertWorldToFixed12(wMin.x / gte));
writer.Write(PSXTrig.ConvertWorldToFixed12(-wMax.y / gte));
writer.Write(PSXTrig.ConvertWorldToFixed12(wMin.z / gte));
writer.Write(PSXTrig.ConvertWorldToFixed12(wMax.x / gte));
writer.Write(PSXTrig.ConvertWorldToFixed12(-wMin.y / gte));
writer.Write(PSXTrig.ConvertWorldToFixed12(wMax.z / gte));
if (tb.LuaFile != null)
writer.Write((short)luaFiles.IndexOf(tb.LuaFile));
else
writer.Write((short)-1);
writer.Write((ushort)0); // padding
writer.Write((uint)0); // padding
}
}
// ──────────────────────────────────────────────────────
// BVH data (inline)

37
Runtime/PSXTriggerBox.cs Normal file
View File

@@ -0,0 +1,37 @@
using UnityEngine;
namespace SplashEdit.RuntimeCode
{
public class PSXTriggerBox : MonoBehaviour
{
[SerializeField] private Vector3 size = Vector3.one;
[SerializeField] private LuaFile luaFile;
public Vector3 Size => size;
public LuaFile LuaFile => luaFile;
public Bounds GetWorldBounds()
{
Vector3 halfSize = size * 0.5f;
Vector3 worldCenter = transform.position;
Vector3 worldMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 worldMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
for (int i = 0; i < 8; i++)
{
Vector3 corner = new Vector3(
(i & 1) != 0 ? halfSize.x : -halfSize.x,
(i & 2) != 0 ? halfSize.y : -halfSize.y,
(i & 4) != 0 ? halfSize.z : -halfSize.z
);
Vector3 world = transform.TransformPoint(corner);
worldMin = Vector3.Min(worldMin, world);
worldMax = Vector3.Max(worldMax, world);
}
Bounds b = new Bounds();
b.SetMinMax(worldMin, worldMax);
return b;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 72b9d8d2e8eafba46a30ba345beb9692

View File

@@ -161,10 +161,23 @@ namespace SplashEdit.RuntimeCode
List<PSXUIElementData> elements = new List<PSXUIElementData>();
Debug.Log($"[UIExporter] Canvas '{canvas.CanvasName}' on '{canvas.gameObject.name}' " +
$"canvasW={canvasW} canvasH={canvasH} childCount={canvas.transform.childCount}");
// Log what each collector finds
int prevCount = elements.Count;
CollectImages(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements);
Debug.Log($"[UIExporter] Images: {elements.Count - prevCount}");
prevCount = elements.Count;
CollectBoxes(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements);
Debug.Log($"[UIExporter] Boxes: {elements.Count - prevCount}");
prevCount = elements.Count;
CollectTexts(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements, uniqueFonts);
Debug.Log($"[UIExporter] Texts: {elements.Count - prevCount}");
prevCount = elements.Count;
CollectProgressBars(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements);
Debug.Log($"[UIExporter] ProgressBars: {elements.Count - prevCount}");
Debug.Log($"[UIExporter] TOTAL elements: {elements.Count}");
string name = canvas.CanvasName ?? "canvas";
if (name.Length > 24) name = name.Substring(0, 24);

View File

@@ -57,7 +57,7 @@ end
-- ============================================================================
--- Called when this object's collider overlaps another.
function onCollision(self, other)
function onCollideWithPlayer(self)
Debug.Log("Collision with another object")
end

View File

@@ -22,7 +22,7 @@ Add (or merge) the following into your workspace `.vscode/settings.json`:
// Event callbacks the engine calls — not "undefined" globals
"onCreate", "onUpdate", "onDestroy",
"onEnable", "onDisable",
"onCollision", "onInteract",
"onCollideWithPlayer", "onInteract",
"onTriggerEnter", "onTriggerStay", "onTriggerExit",
"onButtonPress", "onButtonRelease"
]

View File

@@ -351,7 +351,7 @@ function onDisable(self) end
--- Called when this object's collider overlaps another.
--- @param self EntityHandle
--- @param other EntityHandle
function onCollision(self, other) end
function onCollideWithPlayer(self) end
--- Called when the player interacts with this object (PSXInteractable).
--- @param self EntityHandle