using System.Collections.Generic; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using Test_2022.CameraControl; [CustomEditor(typeof(CameraWaypointSwitcher))] [CanEditMultipleObjects] public sealed class CameraWaypointSwitcherEditor : Editor { SerializedProperty targetProp; SerializedProperty waypointsProp; void OnEnable() { targetProp = serializedObject.FindProperty("target"); waypointsProp = serializedObject.FindProperty("waypoints"); } public override void OnInspectorGUI() { serializedObject.Update(); DrawDefaultInspector(); serializedObject.ApplyModifiedProperties(); EditorGUILayout.Space(10); using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { EditorGUILayout.LabelField("Tools", EditorStyles.boldLabel); using (new EditorGUILayout.HorizontalScope()) { if (GUILayout.Button("Use Main Camera")) UseMainCamera(); if (GUILayout.Button("Create Point From Target")) CreatePointFromTarget(); } using (new EditorGUILayout.HorizontalScope()) { if (GUILayout.Button("Add Selected")) AddSelected(false); if (GUILayout.Button("Add Selected (+Children)")) AddSelected(true); } using (new EditorGUILayout.HorizontalScope()) { if (GUILayout.Button("Remove Nulls")) RemoveNulls(); if (GUILayout.Button("Clear Points")) ClearPoints(); } } EditorGUILayout.Space(10); using (new EditorGUILayout.VerticalScope(EditorStyles.helpBox)) { EditorGUILayout.LabelField("Runtime", EditorStyles.boldLabel); if (!Application.isPlaying) EditorGUILayout.HelpBox("进入 Play 模式后才会执行点位切换与摇晃。Transition Mode = Instant 为瞬切,Tween 为平滑移动。Shake Mode = Handheld 为手持式平滑摇晃。", MessageType.Info); using (new EditorGUI.DisabledScope(!Application.isPlaying)) { using (new EditorGUILayout.HorizontalScope()) { if (GUILayout.Button("Start")) StartPlayback(); if (GUILayout.Button("Stop (Restore)")) StopPlayback(true); if (GUILayout.Button("Stop (No Restore)")) StopPlayback(false); } } } } void UseMainCamera() { var cam = Camera.main; if (cam == null) return; foreach (var t in targets) { Undo.RecordObject(t, "Assign Main Camera"); var sw = (CameraWaypointSwitcher)t; var so = new SerializedObject(sw); so.FindProperty("target").objectReferenceValue = cam.transform; so.ApplyModifiedPropertiesWithoutUndo(); EditorUtility.SetDirty(sw); MarkSceneDirty(sw); } serializedObject.Update(); } void CreatePointFromTarget() { if (targetProp == null) return; var target = targetProp.objectReferenceValue as Transform; if (target == null) return; var go = new GameObject("CamPoint"); Undo.RegisterCreatedObjectUndo(go, "Create Camera Point"); go.transform.SetPositionAndRotation(target.position, target.rotation); AddPointToAll(go.transform, -1f); Selection.activeGameObject = go; } void AddSelected(bool includeChildren) { var selected = Selection.gameObjects; if (selected == null || selected.Length == 0) return; var points = new List(); for (var i = 0; i < selected.Length; i++) { var go = selected[i]; if (go == null) continue; if (includeChildren) points.AddRange(go.GetComponentsInChildren(true)); else points.Add(go.transform); } for (var i = 0; i < points.Count; i++) AddPointToAll(points[i], -1f); } void AddPointToAll(Transform point, float holdSeconds) { if (point == null) return; foreach (var t in targets) { var sw = (CameraWaypointSwitcher)t; Undo.RecordObject(sw, "Add Waypoint"); sw.AddWaypoint(point, holdSeconds); EditorUtility.SetDirty(sw); MarkSceneDirty(sw); } } void RemoveNulls() { foreach (var t in targets) { var sw = (CameraWaypointSwitcher)t; Undo.RecordObject(sw, "Remove Null Waypoints"); sw.RemoveNullWaypoints(); EditorUtility.SetDirty(sw); MarkSceneDirty(sw); } } void ClearPoints() { foreach (var t in targets) { var sw = (CameraWaypointSwitcher)t; Undo.RecordObject(sw, "Clear Waypoints"); sw.ClearWaypoints(); EditorUtility.SetDirty(sw); MarkSceneDirty(sw); } } void StartPlayback() { foreach (var t in targets) { var sw = (CameraWaypointSwitcher)t; sw.StartPlayback(); } } void StopPlayback(bool restore) { foreach (var t in targets) { var sw = (CameraWaypointSwitcher)t; sw.StopPlayback(restore); } } static void MarkSceneDirty(CameraWaypointSwitcher sw) { if (Application.isPlaying) return; if (!sw.gameObject.scene.IsValid()) return; EditorSceneManager.MarkSceneDirty(sw.gameObject.scene); } }