Editor--ParticlePathEditor
1 using UnityEngine; 2 using UnityEditor; 3 using System.Reflection; 4 using System.Linq; 5 using System; 6 using System.Collections.Generic; 7 8 [CustomEditor(typeof(ParticleSystem))] 9 public class ParticlePathEditor : Editor 10 { 11 private ParticleSystem _particleSystem; 12 private Assembly _assembly; 13 private Type _particleSystemInspector; 14 private MethodInfo _onInspectorGUI; 15 private Editor _particleSystemEditor; 16 private ParticlePath _particlePath; 17 private int _currentCheckedPoint; 18 19 private void OnEnable() 20 { 21 _particleSystem = target as ParticleSystem; 22 //载入程序集 23 _assembly = Assembly.GetAssembly(typeof(Editor)); 24 //获取ParticleSystemInspector类 25 _particleSystemInspector = _assembly.GetTypes().Where(t => t.Name == "ParticleSystemInspector").FirstOrDefault(); 26 //获取OnInspectorGUI方法 27 _onInspectorGUI = _particleSystemInspector.GetMethod("OnInspectorGUI", BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic); 28 //创建ParticleSystemInspector的实例 29 _particleSystemEditor = CreateEditor(target, _particleSystemInspector); 30 _particlePath = _particleSystem.gameObject.GetComponent<ParticlePath>(); 31 _currentCheckedPoint = -1; 32 33 if (!_particlePath) 34 { 35 _particlePath = _particleSystem.gameObject.AddComponent<ParticlePath>(); 36 _particlePath.IsApprove = true; 37 _particlePath.hideFlags = HideFlags.HideInInspector; 38 _particlePath.Waypoints = new List<Vector3>(); 39 _particlePath.IsHideInInspector = false; 40 _particlePath.PS = _particleSystem; 41 } 42 if (!_particlePath.IsApprove) 43 { 44 DestroyImmediate(_particlePath); 45 _particlePath = _particleSystem.gameObject.AddComponent<ParticlePath>(); 46 _particlePath.IsApprove = true; 47 _particlePath.hideFlags = HideFlags.HideInInspector; 48 _particlePath.Waypoints = new List<Vector3>(); 49 _particlePath.IsHideInInspector = false; 50 _particlePath.PS = _particleSystem; 51 } 52 } 53 54 public override void OnInspectorGUI() 55 { 56 EditorGUILayout.BeginVertical("HelpBox"); 57 58 EditorGUILayout.BeginHorizontal(); 59 GUI.color = _particlePath.IsPath ? Color.white : Color.gray; 60 _particlePath.IsPath = GUILayout.Toggle(_particlePath.IsPath, "", GUILayout.Width(25)); 61 if (GUILayout.Button("路径模式", "label")) 62 { 63 _particlePath.IsHideInInspector = !_particlePath.IsHideInInspector; 64 } 65 GUI.enabled = _particlePath.IsPath; 66 EditorGUILayout.EndHorizontal(); 67 68 if (!_particlePath.IsHideInInspector) 69 { 70 for (int i = 0; i < _particlePath.Waypoints.Count; i++) 71 { 72 EditorGUILayout.BeginHorizontal(); 73 GUI.backgroundColor = _currentCheckedPoint == i ? Color.cyan : Color.white; 74 if (GUILayout.Button("路径点" + (i + 1), "toolbarbutton")) 75 { 76 _currentCheckedPoint = i; 77 } 78 if (i != 0) 79 { 80 if (GUILayout.Button("↑", "toolbarbutton", GUILayout.Width(20))) 81 { 82 Vector3 vec = _particlePath.Waypoints[i]; 83 _particlePath.Waypoints[i] = _particlePath.Waypoints[i - 1]; 84 _particlePath.Waypoints[i - 1] = vec; 85 } 86 } 87 if (i != _particlePath.Waypoints.Count - 1) 88 { 89 if (GUILayout.Button("↓", "toolbarbutton", GUILayout.Width(20))) 90 { 91 Vector3 vec = _particlePath.Waypoints[i]; 92 _particlePath.Waypoints[i] = _particlePath.Waypoints[i + 1]; 93 _particlePath.Waypoints[i + 1] = vec; 94 } 95 } 96 if (GUILayout.Button("-", "toolbarbutton", GUILayout.Width(20))) 97 { 98 _particlePath.Waypoints.RemoveAt(i); 99 _currentCheckedPoint = -1; 100 break; 101 } 102 EditorGUILayout.EndHorizontal(); 103 } 104 105 EditorGUILayout.BeginHorizontal(); 106 GUI.backgroundColor = Color.white; 107 GUILayout.FlexibleSpace(); 108 if (GUILayout.Button("", "OL Plus")) 109 { 110 if (_currentCheckedPoint != -1) 111 { 112 _particlePath.Waypoints.Add(_particlePath.Waypoints[_currentCheckedPoint]); 113 } 114 else 115 { 116 _particlePath.Waypoints.Add(_particlePath.transform.position); 117 } 118 } 119 EditorGUILayout.EndHorizontal(); 120 121 EditorGUILayout.BeginHorizontal(); 122 GUILayout.Label("Speed", "MiniLabel"); 123 _particlePath.Speed = EditorGUILayout.Slider(_particlePath.Speed, 10f, 0.5f); 124 EditorGUILayout.EndHorizontal(); 125 } 126 127 EditorGUILayout.EndVertical(); 128 129 GUI.color = Color.white; 130 GUI.enabled = true; 131 132 _onInspectorGUI.Invoke(_particleSystemEditor, null); 133 } 134 135 private void OnSceneGUI() 136 { 137 if (_particlePath.IsPath) 138 { 139 Handles.color = Color.cyan; 140 for (int i = 0; i < _particlePath.Waypoints.Count; i++) 141 { 142 if(i < _particlePath.Waypoints.Count - 1) 143 { 144 Handles.DrawLine(_particlePath.Waypoints[i], _particlePath.Waypoints[i + 1]); 145 } 146 } 147 148 if (_currentCheckedPoint != -1 && _currentCheckedPoint < _particlePath.Waypoints.Count) 149 { 150 Tools.current = Tool.None; 151 Vector3 oldVec = _particlePath.Waypoints[_currentCheckedPoint]; 152 Vector3 newVec = Handles.PositionHandle(oldVec, Quaternion.identity); 153 if (oldVec != newVec) 154 { 155 _particlePath.Waypoints[_currentCheckedPoint] = newVec; 156 } 157 Handles.Label(newVec, "路径点" + (_currentCheckedPoint + 1)); 158 } 159 } 160 } 161 }
Script
1 using UnityEngine; 2 using System.Collections.Generic; 3 4 [DisallowMultipleComponent] 5 public class ParticlePath : MonoBehaviour 6 { 7 [HideInInspector] 8 public bool IsApprove = false; 9 [HideInInspector] 10 public bool IsPath = false; 11 [HideInInspector] 12 public List<Vector3> Waypoints; 13 [HideInInspector] 14 public bool IsHideInInspector = false; 15 [HideInInspector] 16 public ParticleSystem PS; 17 [HideInInspector] 18 public float Speed = 2; 19 20 private ParticleSystem.MainModule _psmm; 21 private float _oldSpeed; 22 23 private void Awake() 24 { 25 if (!PS || Waypoints.Count <= 0) 26 { 27 IsApprove = false; 28 IsPath = false; 29 return; 30 } 31 32 _psmm = PS.main; 33 _oldSpeed = Speed; 34 _psmm.startLifetime = Waypoints.Count * Speed; 35 _psmm.simulationSpace = ParticleSystemSimulationSpace.Custom; 36 _psmm.customSimulationSpace = transform; 37 38 transform.localRotation = Quaternion.identity; 39 } 40 41 private void Update() 42 { 43 if (IsApprove && IsPath) 44 { 45 if (_oldSpeed != Speed) 46 { 47 _oldSpeed = Speed; 48 _psmm.startLifetime = Waypoints.Count * Speed; 49 } 50 51 ParticleSystem.Particle[] ps = new ParticleSystem.Particle[PS.particleCount]; 52 int pCount = PS.GetParticles(ps); 53 54 for (int i = 0; i < pCount; i++) 55 { 56 float proportion = (ps[i].startLifetime - ps[i].remainingLifetime) / ps[i].startLifetime; 57 int index = Mathf.FloorToInt(proportion * Waypoints.Count); 58 if (index >= 0 && index < Waypoints.Count - 1) 59 { 60 Vector3 direction = Waypoints[index + 1] - Waypoints[index]; 61 ps[i].velocity = direction * (1.0f / Speed) * (1.0f / transform.localScale.x); 62 } 63 else 64 { 65 ps[i].remainingLifetime = 0; 66 } 67 } 68 69 PS.SetParticles(ps, pCount); 70 } 71 } 72 }