Unity粒子路径动画

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 }

 

上一篇:Unity资源命名管理工具(硬规范)


下一篇:Unity生成简易代码工具