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,32 +155,18 @@ namespace SplashEdit.EditorCode
EditorGUILayout.PropertyField(collisionTypeProp, new GUIContent("Type"));
var collType = (PSXCollisionType)collisionTypeProp.enumValueIndex;
if (collType != PSXCollisionType.None)
if (collType == PSXCollisionType.Static)
{
EditorGUILayout.PropertyField(staticColliderProp, new GUIContent("Static"));
bool isStatic = staticColliderProp.boolValue;
if (isStatic)
{
EditorGUILayout.LabelField(
"<color=#88cc88>Baked into world collision mesh. No runtime cost.</color>",
PSXEditorStyles.RichLabel);
}
else
{
EditorGUILayout.LabelField(
"<color=#88aaff>Runtime AABB collider. Fires Lua collision 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.LabelField(
"<color=#88cc88>Baked into world collision mesh. No runtime cost.</color>",
PSXEditorStyles.RichLabel);
}
else if (collType == PSXCollisionType.Dynamic)
{
EditorGUILayout.LabelField(
"<color=#88aaff>Runtime AABB collider. Pushes player back + fires Lua events.</color>",
PSXEditorStyles.RichLabel);
}
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