Files
pgs/Assets/ProCamera2D/Code/Extensions/Editor/ProCamera2DRailsEditor.cs

392 lines
16 KiB
C#
Raw Normal View History

2026-02-21 16:58:22 -08:00
using UnityEditor;
using UnityEngine;
using System;
using System.Collections.Generic;
using UnityEditorInternal;
namespace Com.LuisPedroFonseca.ProCamera2D
{
[CustomEditor(typeof(ProCamera2DRails))]
public class ProCamera2DRailsEditor : Editor
{
Func<Vector3, float> Vector3H;
Func<Vector3, float> Vector3V;
Func<float, float, Vector3> VectorHV;
static List<Vector3> _playModeNodes = new List<Vector3>();
static string _currentScene;
MonoScript _script;
GUIContent _tooltip;
ReorderableList _targetsList;
void OnEnable()
{
if (target == null)
return;
var proCamera2DRails = (ProCamera2DRails)target;
// Get nodes from play mode
serializedObject.Update();
#if UNITY_5_3_OR_NEWER
if (_currentScene != UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name)
_playModeNodes.Clear();
_currentScene = UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name;
#else
if (_currentScene != EditorApplication.currentScene)
_playModeNodes.Clear();
_currentScene = EditorApplication.currentScene;
#endif
if (!Application.isPlaying && _playModeNodes.Count > 0)
{
var list = serializedObject.FindProperty("RailNodes");
list.ClearArray();
for (int i = 0; i < _playModeNodes.Count; i++)
{
list.InsertArrayElementAtIndex(i);
var preset = list.GetArrayElementAtIndex(i);
preset.vector3Value = _playModeNodes[i];
}
_playModeNodes.Clear();
}
serializedObject.ApplyModifiedProperties();
// Script
_script = MonoScript.FromMonoBehaviour(proCamera2DRails);
// Create Vector conversion methods
switch (proCamera2DRails.ProCamera2D.Axis)
{
case MovementAxis.XY:
Vector3H = vector => vector.x;
Vector3V = vector => vector.y;
VectorHV = (h, v) => new Vector3(h, v, 0);
break;
case MovementAxis.XZ:
Vector3H = vector => vector.x;
Vector3V = vector => vector.z;
VectorHV = (h, v) => new Vector3(h, 0, v);
break;
case MovementAxis.YZ:
Vector3H = vector => vector.z;
Vector3V = vector => vector.y;
VectorHV = (h, v) => new Vector3(0, v, h);
break;
}
// Create nodes if non-existant
if (proCamera2DRails.RailNodes.Count < 2)
{
proCamera2DRails.RailNodes.Add(VectorHV(1, 1));
proCamera2DRails.RailNodes.Add(VectorHV(2, 2));
}
// Show correct axis name
var hAxis = "";
var vAxis = "";
switch (proCamera2DRails.ProCamera2D.Axis)
{
case MovementAxis.XY:
hAxis = "X";
vAxis = "Y";
break;
case MovementAxis.XZ:
hAxis = "X";
vAxis = "Z";
break;
case MovementAxis.YZ:
hAxis = "Y";
vAxis = "Z";
break;
}
// Targets List
_targetsList = new ReorderableList(serializedObject, serializedObject.FindProperty("CameraTargets"), false, false, true, true);
_targetsList.onSelectCallback = (list) =>
{
EditorGUIUtility.PingObject(_targetsList.serializedProperty.GetArrayElementAtIndex(_targetsList.index).FindPropertyRelative("TargetTransform").objectReferenceValue);
};
_targetsList.drawElementCallback = (rect, index, isActive, isFocused) =>
{
rect.y += 2;
var element = _targetsList.serializedProperty.GetArrayElementAtIndex(index);
#if UNITY_5
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y, 65, 10), new GUIContent("Transform", "The target transform"), EditorStyles.boldLabel);
#else
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y, 65, 10), new GUIContent("Transform", "The target transform"));
#endif
EditorGUI.PropertyField(new Rect(
rect.x + 65,
rect.y,
80,
EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("TargetTransform"), GUIContent.none);
#if UNITY_5
EditorGUI.PrefixLabel(new Rect(rect.x + 160, rect.y, 65, 10), new GUIContent("Offset", "Offset the camera position relative to this target"), EditorStyles.boldLabel);
#else
EditorGUI.PrefixLabel(new Rect(rect.x + 160, rect.y, 65, 10), new GUIContent("Offset", "Offset the camera position relative to this target"));
#endif
EditorGUI.PropertyField(new Rect(
rect.x + 200,
rect.y,
rect.width - 200,
EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("TargetOffset"), GUIContent.none);
#if UNITY_5
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 25, 65, 10), new GUIContent("Influence" + hAxis, "How much does this target horizontal position influences the camera position?"), EditorStyles.boldLabel);
#else
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 25, 65, 10), new GUIContent("Influence" + hAxis, "How much does this target horizontal position influences the camera position?"));
#endif
EditorGUI.PropertyField(new Rect(
rect.x + 80,
rect.y + 25,
rect.width - 80,
EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("TargetInfluenceH"), GUIContent.none);
#if UNITY_5
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 40, 65, 10), new GUIContent("Influence" + vAxis, "How much does this target vertical position influences the camera position?"), EditorStyles.boldLabel);
#else
EditorGUI.PrefixLabel(new Rect(rect.x, rect.y + 40, 65, 10), new GUIContent("Influence" + vAxis, "How much does this target vertical position influences the camera position?"));
#endif
EditorGUI.PropertyField(new Rect(
rect.x + 80,
rect.y + 40,
rect.width - 80,
EditorGUIUtility.singleLineHeight),
element.FindPropertyRelative("TargetInfluenceV"), GUIContent.none);
};
_targetsList.elementHeight = 80;
_targetsList.headerHeight = 0;
_targetsList.draggable = true;
}
void OnDisable()
{
var proCamera2DRails = (ProCamera2DRails)target;
_playModeNodes = proCamera2DRails.RailNodes;
}
public override void OnInspectorGUI()
{
if (target == null)
return;
var proCamera2DRails = (ProCamera2DRails)target;
if(proCamera2DRails.ProCamera2D == null)
EditorGUILayout.HelpBox("ProCamera2D is not set.", MessageType.Error, true);
serializedObject.Update();
// Show script link
GUI.enabled = false;
_script = EditorGUILayout.ObjectField("Script", _script, typeof(MonoScript), false) as MonoScript;
GUI.enabled = true;
// ProCamera2D
_tooltip = new GUIContent("Pro Camera 2D", "");
EditorGUILayout.PropertyField(serializedObject.FindProperty("_pc2D"), _tooltip);
EditorGUILayout.Space();
// Targets Drop Area
Event evt = Event.current;
Rect drop_area = GUILayoutUtility.GetRect(0.0f, 50.0f, GUILayout.ExpandWidth(true));
var style = new GUIStyle("box");
if (EditorGUIUtility.isProSkin)
style.normal.textColor = Color.white;
GUI.Box(drop_area, "\nDROP CAMERA TARGETS HERE", style);
switch (evt.type)
{
case EventType.DragUpdated:
case EventType.DragPerform:
if (!drop_area.Contains(evt.mousePosition))
return;
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
if (evt.type == EventType.DragPerform)
{
DragAndDrop.AcceptDrag();
foreach (UnityEngine.Object dragged_object in DragAndDrop.objectReferences)
{
var newCameraTarget = new CameraTarget
{
TargetTransform = ((GameObject)dragged_object).transform,
TargetInfluence = 1f
};
proCamera2DRails.CameraTargets.Add(newCameraTarget);
EditorUtility.SetDirty(proCamera2DRails);
}
}
break;
}
EditorGUILayout.Space();
// Targets List
_targetsList.DoLayoutList();
EditorGUILayout.Space();
EditorGUILayout.Space();
// Follow mode
_tooltip = new GUIContent("FollowMode", "This defines which axis to use to calculate the targets position on the rails");
EditorGUILayout.PropertyField(serializedObject.FindProperty("FollowMode"), _tooltip);
EditorGUILayout.Space();
// Apply modified properties
serializedObject.ApplyModifiedProperties();
}
void OnSceneGUI()
{
var proCamera2DRails = (ProCamera2DRails)target;
// Return if less than 2 nodes
var nodesCount = proCamera2DRails.RailNodes.Count;
if (nodesCount < 2)
return;
// Detect delete mode
bool deleteMode = false;
Event e = Event.current;
if (e.alt)
{
deleteMode = true;
}
// Handles color
Handles.color = EditorPrefsX.GetColor(PrefsData.RailsColorKey, PrefsData.RailsColorValue);
// Draw line between nodes
Handles.DrawPolyLine(proCamera2DRails.RailNodes.ToArray());
// Handle size
float handleSize = HandleUtility.GetHandleSize(Vector3.zero) * .1f;
// Draw left and right handles
var rightHandlePos = (proCamera2DRails.RailNodes[nodesCount - 1] - proCamera2DRails.RailNodes[nodesCount - 2]).normalized * .5f + proCamera2DRails.RailNodes[nodesCount - 1];
if (Handles.Button(
rightHandlePos,
Quaternion.identity,
handleSize * .5f,
handleSize,
#if UNITY_5_5_OR_NEWER
Handles.RectangleHandleCap))
#else
Handles.RectangleCap))
#endif
{
Undo.RecordObject(proCamera2DRails, "Add");
proCamera2DRails.RailNodes.Insert(nodesCount, rightHandlePos);
}
var leftHandlesPos = (proCamera2DRails.RailNodes[0] - proCamera2DRails.RailNodes[1]).normalized * .5f + proCamera2DRails.RailNodes[0];
if (Handles.Button(
leftHandlesPos,
Quaternion.identity,
handleSize * .5f,
handleSize,
#if UNITY_5_5_OR_NEWER
Handles.RectangleHandleCap))
#else
Handles.RectangleCap))
#endif
{
Undo.RecordObject(proCamera2DRails, "Add");
proCamera2DRails.RailNodes.Insert(0, leftHandlesPos);
}
// Snap value
var pointSnap = Vector3.one * EditorPrefs.GetFloat("RailsSnapping", PrefsData.RailsSnapping);
// Draw a handle for each node
for (int i = 0; i < nodesCount; i++)
{
var oldPos = proCamera2DRails.RailNodes[i];
var newPos = Handles.FreeMoveHandle(
oldPos,
Quaternion.identity,
handleSize,
pointSnap,
#if UNITY_5_5_OR_NEWER
Handles.DotHandleCap);
#else
Handles.DotCap);
#endif
// Move
if (newPos != oldPos)
{
newPos.x = Handles.SnapValue(newPos.x, pointSnap.x);
newPos.y = Handles.SnapValue(newPos.y, pointSnap.y);
newPos.z = Handles.SnapValue(newPos.z, pointSnap.z);
Undo.RecordObject(proCamera2DRails, "Move");
proCamera2DRails.RailNodes[i] = VectorHV(Vector3H(newPos), Vector3V(newPos));
}
// Draw the midpoint button
if (i > 0)
{
var midPoint = Vector3.Lerp(proCamera2DRails.RailNodes[i - 1], proCamera2DRails.RailNodes[i], 0.5f);
if (Handles.Button(
midPoint,
Quaternion.identity,
handleSize * .5f,
handleSize,
#if UNITY_5_5_OR_NEWER
Handles.RectangleHandleCap))
#else
Handles.RectangleCap))
#endif
{
Undo.RecordObject(proCamera2DRails, "Add");
proCamera2DRails.RailNodes.Insert(i, midPoint);
}
}
// Draw the delete button
if (deleteMode && nodesCount > 2)
{
Handles.color = Color.red;
var deleteButtonPos = proCamera2DRails.RailNodes[i];
if (Handles.Button(
deleteButtonPos,
Quaternion.identity,
handleSize,
handleSize,
#if UNITY_5_5_OR_NEWER
Handles.DotHandleCap))
#else
Handles.DotCap))
#endif
{
Undo.RecordObject(proCamera2DRails, "Remove");
proCamera2DRails.RailNodes.RemoveAt(i);
return;
}
Handles.color = EditorPrefsX.GetColor(PrefsData.RailsColorKey, PrefsData.RailsColorValue);
}
}
}
}
}