// Version: 1.1.0 using AssetKits.ParticleImage.Enumerations; using UnityEditor; using UnityEditor.Experimental.SceneManagement; using UnityEditor.SceneManagement; using UnityEngine; using PlayMode = AssetKits.ParticleImage.Enumerations.PlayMode; namespace AssetKits.ParticleImage.Editor { [CanEditMultipleObjects] [CustomEditor(typeof(ParticleImage))] public class ParticleImageEditor : UnityEditor.Editor { private ParticleImage _particle; //General Properties private SerializedProperty _space; private SerializedProperty _timeScale; private SerializedProperty _playMode; private SerializedProperty _loop; private SerializedProperty _duration; private SerializedProperty _delay; private SerializedProperty _life; private SerializedProperty _speed; private SerializedProperty _startSize; private SerializedProperty _startRotation; private SerializedProperty _startColor; private SerializedProperty _raycast; private SerializedProperty _maskable; //Emitter Properties private SerializedProperty _rate; private SerializedProperty _rateOverLifetime; private SerializedProperty _rateOverDistance; private SerializedProperty _burst; private SerializedProperty _emitterShape; private SerializedProperty _width; private SerializedProperty _height; private SerializedProperty _length; private SerializedProperty _radius; private SerializedProperty _angle; private SerializedProperty _surface; private SerializedProperty _edge; private SerializedProperty _spreadType; private SerializedProperty _spreadLoop; private SerializedProperty _startPoint; private SerializedProperty _startPointTrans; //Particle Properties private SerializedProperty _texture; private SerializedProperty _material; private SerializedProperty _speedOverLifetime; private SerializedProperty _sizeOverLifetime; private SerializedProperty _sizeBySpeed; private SerializedProperty _sizeSpeedRange; private SerializedProperty _colorOverLifetime; private SerializedProperty _colorBySpeed; private SerializedProperty _colorSpeedRange; private SerializedProperty _rotateOverLifetime; private SerializedProperty _rotationBySpeed; private SerializedProperty _rotationSpeedRange; private SerializedProperty _alignDirection; private SerializedProperty _sheetModule; private SerializedProperty _sheetType; private SerializedProperty _tile; private SerializedProperty _frameOverTime; private SerializedProperty _startFrame; private SerializedProperty _frameSpeedRange; private SerializedProperty _frameFps; private SerializedProperty _cycles; private SerializedProperty _trailModule; private SerializedProperty _trailWidth; private SerializedProperty _trailColorOverLifetime; private SerializedProperty _trailColorOverTrail; private SerializedProperty _trailLifetime; private SerializedProperty _inheritColor; private SerializedProperty _dieWithParticle; private SerializedProperty _trailRatio; private SerializedProperty _minimumVertexDistance; //Movement Properties private SerializedProperty _targetModule; private SerializedProperty _targetTransform; private SerializedProperty _targetCurve; private SerializedProperty _targetMode; private SerializedProperty _noiseModule; private SerializedProperty _noiseFreq; private SerializedProperty _noiseOct; private SerializedProperty _noiseStrength; private SerializedProperty _velocityModule; private SerializedProperty _velocitySpace; private SerializedProperty _velocityOverLifetime; private SerializedProperty _gravityModule; private SerializedProperty _gravity; private SerializedProperty _vortexModule; private SerializedProperty _vortexStrength; //Event Properties private SerializedProperty _onStart; private SerializedProperty _onFinish; private SerializedProperty _onFirstParticleFinish; private SerializedProperty _onLastParticleFinish; private SerializedProperty _onParticleFinish; //Editor Icons private Texture _particleModuleIcon; private Texture _movementModuleIcon; private Texture _emitterModuleIcon; private Texture _eventModuleIcon; //Module Foldouts private GUIStyle _foldoutStyle; private GUIStyle FoldoutStyle { get { if (_foldoutStyle == null) { _foldoutStyle = new GUIStyle("ShurikenModuleTitle"); _foldoutStyle.font = new GUIStyle(EditorStyles.label).font; _foldoutStyle.border = new RectOffset(15, 7, 4, 4); _foldoutStyle.fixedHeight = 24; _foldoutStyle.contentOffset = new Vector2(20f, -2f); } return _foldoutStyle; } } void Awake() { //Set Icons MonoScript.FromMonoBehaviour(target as ParticleImage).SetIcon(Resources.Load("ComponentIcon")); _emitterModuleIcon = EditorGUIUtility.IconContent("AreaLight Gizmo").image; _particleModuleIcon = Resources.Load("ParticleModule"); _movementModuleIcon = Resources.Load("MovementModule"); _eventModuleIcon = Resources.Load("EventModule"); } private void OnEnable() { serializedObject.Update(); _particle = target as ParticleImage; //Initialize Properties _startPoint = serializedObject.FindProperty("_emitterConstraintEnabled"); _startPointTrans = serializedObject.FindProperty("_emitterConstraintTransform"); _timeScale = serializedObject.FindProperty("_timeScale"); _playMode = serializedObject.FindProperty("_playMode"); _delay = serializedObject.FindProperty("_startDelay"); _loop = serializedObject.FindProperty("_loop"); _duration = serializedObject.FindProperty("_duration"); _maskable = serializedObject.FindProperty("m_Maskable"); _raycast = serializedObject.FindProperty("m_RaycastTarget"); _rate = serializedObject.FindProperty("_rate"); _rateOverLifetime = serializedObject.FindProperty("_rateOverLifetime"); _rateOverDistance = serializedObject.FindProperty("_rateOverDistance"); _emitterShape = serializedObject.FindProperty("_shape"); _spreadType = serializedObject.FindProperty("_spread"); _spreadLoop = serializedObject.FindProperty("_spreadLoop"); _space = serializedObject.FindProperty("_space"); _angle = serializedObject.FindProperty("_angle"); _width = serializedObject.FindProperty("_width"); _height = serializedObject.FindProperty("_height"); _length = serializedObject.FindProperty("_length"); _radius = serializedObject.FindProperty("_radius"); _surface = serializedObject.FindProperty("_emitOnSurface"); _edge = serializedObject.FindProperty("_emitterThickness"); _colorOverLifetime = serializedObject.FindProperty("_colorOverLifetime"); _colorBySpeed = serializedObject.FindProperty("_colorBySpeed"); _colorSpeedRange = serializedObject.FindProperty("_colorSpeedRange"); _sizeOverLifetime = serializedObject.FindProperty("_sizeOverLifetime"); _sizeBySpeed = serializedObject.FindProperty("_sizeBySpeed"); _sizeSpeedRange = serializedObject.FindProperty("_sizeSpeedRange"); _startRotation = serializedObject.FindProperty("_startRotation"); _rotateOverLifetime = serializedObject.FindProperty("_rotationOverLifetime"); _rotationBySpeed = serializedObject.FindProperty("_rotationBySpeed"); _rotationSpeedRange = serializedObject.FindProperty("_rotationSpeedRange"); _targetTransform = serializedObject.FindProperty("_attractorTarget"); _targetCurve = serializedObject.FindProperty("_toTarget"); _burst = serializedObject.FindProperty("_bursts"); _speed = serializedObject.FindProperty("_startSpeed"); _startSize = serializedObject.FindProperty("_startSize"); _material = serializedObject.FindProperty("m_Material"); _startColor = serializedObject.FindProperty("_startColor"); _life = serializedObject.FindProperty("_lifetime"); _speedOverLifetime = serializedObject.FindProperty("_speedOverLifetime"); _texture = serializedObject.FindProperty("m_Texture"); _sheetModule = serializedObject.FindProperty("_sheetModule"); _sheetType = serializedObject.FindProperty("_sheetType"); _tile = serializedObject.FindProperty("_textureTile"); _frameOverTime = serializedObject.FindProperty("_frameOverTime"); _startFrame = serializedObject.FindProperty("_startFrame"); _frameSpeedRange = serializedObject.FindProperty("_frameSpeedRange"); _frameFps = serializedObject.FindProperty("_textureSheetFPS"); _cycles = serializedObject.FindProperty("_textureSheetCycles"); _targetMode = serializedObject.FindProperty("_targetMode"); _gravity = serializedObject.FindProperty("_gravity"); _targetModule = serializedObject.FindProperty("_targetModule"); _noiseModule = serializedObject.FindProperty("_noiseModule"); _noiseFreq = serializedObject.FindProperty("_noiseFrequency"); _noiseOct = serializedObject.FindProperty("_noiseOctaves"); _noiseStrength = serializedObject.FindProperty("_noiseStrength"); _gravityModule = serializedObject.FindProperty("_gravityModule"); _vortexModule = serializedObject.FindProperty("_vortexModule"); _vortexStrength = serializedObject.FindProperty("_vortexStrength"); _velocityModule = serializedObject.FindProperty("_velocityModule"); _velocitySpace = serializedObject.FindProperty("_velocitySpace"); _velocityOverLifetime = serializedObject.FindProperty("_velocityOverLifetime"); _alignDirection = serializedObject.FindProperty("_alignToDirection"); _trailModule = serializedObject.FindProperty("_trailModule"); _trailWidth = serializedObject.FindProperty("_trailWidth"); _trailColorOverLifetime = serializedObject.FindProperty("_trailColorOverLifetime"); _trailColorOverTrail = serializedObject.FindProperty("_trailColorOverTrail"); _trailLifetime = serializedObject.FindProperty("_trailLifetime"); _inheritColor = serializedObject.FindProperty("_inheritParticleColor"); _dieWithParticle = serializedObject.FindProperty("_dieWithParticle"); _trailRatio = serializedObject.FindProperty("_trailRatio"); _minimumVertexDistance = serializedObject.FindProperty("_minimumVertexDistance"); _onStart = serializedObject.FindProperty("_onStart"); _onFinish = serializedObject.FindProperty("_onStop"); _onFirstParticleFinish = serializedObject.FindProperty("_onFirstParticleFinish"); _onLastParticleFinish = serializedObject.FindProperty("_onLastParticleFinish"); _onParticleFinish = serializedObject.FindProperty("_onParticleFinish"); _particle.OnEnable(); if (Application.isEditor && !EditorApplication.isPlaying) { _particle.Invoke(nameof(ParticleImage.Play), 0.1f); } EditorApplication.update += EditorUpdate; SceneView.duringSceneGui += DrawSceneWindow; Undo.undoRedoPerformed += UndoRedoPerformed; } private void OnDisable() { EditorApplication.update -= EditorUpdate; SceneView.duringSceneGui -= DrawSceneWindow; Undo.undoRedoPerformed -= UndoRedoPerformed; if (Application.isEditor && !EditorApplication.isPlaying && _particle) { _particle.CancelInvoke(); _particle.Pause(); } } private void UndoRedoPerformed() { // Temporary fix for NullReferenceException on undo performed when Curve Editor is open (Unity bug) if (EditorWindow.focusedWindow.titleContent.text == "Curve Editor") { EditorWindow.focusedWindow.Close(); } } void OnSceneGUI() { Handles.color = Color.cyan; Handles.matrix = _particle.transform.localToWorldMatrix; // Draw emitter shape switch (_particle.shape) { case EmitterShape.Circle: Handles.DrawWireDisc(Vector3.zero, Vector3.forward, _particle.circleRadius); if (_particle.emitOnSurface) break; // Draw inner circle Handles.color = Color.gray; Handles.DrawWireDisc(Vector3.zero, Vector3.forward, _particle.circleRadius - _particle.emitterThickness); break; case EmitterShape.Rectangle: Handles.DrawWireCube(Vector3.zero, new Vector3(_particle.rectWidth, _particle.rectHeight)); if(_particle.emitOnSurface) break; // Draw inner rectangle Handles.DrawWireCube(Vector3.zero, new Vector3(_particle.rectWidth - _particle.emitterThickness, _particle.rectHeight - _particle.emitterThickness)); break; case EmitterShape.Line: Handles.DrawLine(new Vector3(-_particle.lineLength/2, 0, 0), new Vector3(_particle.lineLength/2, 0, 0)); break; case EmitterShape.Directional: Handles.DrawWireArc(Vector3.zero, Vector3.forward, PointInCircle(_angle.floatValue/2).normalized, _angle.floatValue,100); Handles.DrawLine(Vector3.zero, PointInCircle(_angle.floatValue/2).normalized * 100f); Handles.DrawLine(Vector3.zero, PointInCircle(-_angle.floatValue/2).normalized * 100f); break; } Handles.color = Color.white; } // Get point on circle from angle private Vector3 PointInCircle(float angle){ var rad = angle * Mathf.Deg2Rad; return new Vector3(Mathf.Sin( rad ), Mathf.Cos( rad ), 0); } // Draw control panel in scene view void DrawSceneWindow(SceneView sceneView) { Handles.BeginGUI(); Rect rect; if (PrefabStageUtility.GetCurrentPrefabStage()) { rect = new Rect(Screen.width / EditorGUIUtility.pixelsPerPoint - 230, Screen.height / EditorGUIUtility.pixelsPerPoint - 168, 220, 88); } else { rect = new Rect(Screen.width / EditorGUIUtility.pixelsPerPoint - 230, Screen.height / EditorGUIUtility.pixelsPerPoint - 142, 220, 88); } GUILayout.BeginArea(rect, new GUIContent(_particle.gameObject.name),new GUIStyle("window")); GUILayout.BeginHorizontal(); if (GUILayout.Button(_particle.isPlaying ? "Pause" : "Play", new GUIStyle("ButtonLeft"))) { if (_particle.isPlaying) _particle.Pause(); else _particle.Play(); } if (GUILayout.Button("Reset", new GUIStyle("ButtonMid"))) { _particle.Stop(true); _particle.Play(); } if (GUILayout.Button("Stop", new GUIStyle("ButtonRight"))) { _particle.Stop(true); } GUILayout.EndHorizontal(); EditorGUILayout.LabelField("Playback Time",_particle.main ? _particle.main.time.ToString("F") : _particle.time.ToString("F")); EditorGUILayout.LabelField("Particles",_particle.particles.Count.ToString()); GUILayout.EndArea(); Handles.EndGUI(); } public override void OnInspectorGUI() { EditorGUILayout.PropertyField(_space, new GUIContent("Simulation Space"), false); EditorGUILayout.PropertyField(_timeScale, new GUIContent("Simulation Time"), false); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(_playMode, new GUIContent("Play*", "Shared between the particles group"), false); if (EditorGUI.EndChangeCheck()) { _particle.PlayMode = (PlayMode)_playMode.enumValueIndex; EditorUtility.SetDirty(_particle); } EditorGUILayout.PropertyField(_loop, false); EditorGUILayout.PropertyField(_duration, false); EditorGUILayout.PropertyField(_delay,new GUIContent("Start Delay"), false); EditorGUILayout.PropertyField(_life, false); EditorGUILayout.PropertyField(_speed, false); EditorGUILayout.PropertyField(_startSize, new GUIContent("Start Size"), false); EditorGUILayout.PropertyField(_startRotation, new GUIContent("Start Rotation"), false); EditorGUILayout.PropertyField(_startColor, new GUIContent("Start Color"), false); EditorGUILayout.PropertyField(_raycast, false); EditorGUILayout.PropertyField(_maskable, false); _particle.moduleEmitterFoldout = Foldout("Emission", _particle.moduleEmitterFoldout, _emitterModuleIcon); if (_particle.moduleEmitterFoldout) { EditorGUILayout.PropertyField(_rate, new GUIContent("Rate per Second"), false); EditorGUILayout.PropertyField(_rateOverLifetime, new GUIContent("Rate over Duration") ,false); EditorGUILayout.PropertyField(_rateOverDistance, new GUIContent("Rate over Distance"), false); EditorGUILayout.PropertyField(_burst, true); DrawHorizontalLine(); EditorGUILayout.PropertyField(_emitterShape, new GUIContent("Shape"),false); switch (_particle.shape) { case EmitterShape.Point: EditorGUILayout.PropertyField(_spreadType, new GUIContent("Spread"), false); if (_particle.spreadType == SpreadType.Uniform) { EditorGUILayout.PropertyField(_spreadLoop, new GUIContent("Loop"), false); } break; case EmitterShape.Circle: EditorGUI.BeginDisabledGroup(_particle.fitRect); EditorGUILayout.PropertyField(_radius,new GUIContent("Radius"), false); EditorGUI.EndDisabledGroup(); _particle.fitRect = EditorGUILayout.Toggle("Fit Rect", _particle.fitRect); EditorGUILayout.PropertyField(_surface, false); if(!_surface.boolValue) EditorGUILayout.PropertyField(_edge, false); _edge.floatValue= Mathf.Clamp(_edge.floatValue, 0f, _particle.circleRadius); EditorGUILayout.PropertyField(_spreadType, new GUIContent("Spread"), false); if (_particle.spreadType == SpreadType.Uniform) { EditorGUILayout.PropertyField(_spreadLoop, new GUIContent("Loop"), false); } break; case EmitterShape.Rectangle: EditorGUI.BeginDisabledGroup(_particle.fitRect); EditorGUILayout.PropertyField(_width, false); EditorGUILayout.PropertyField(_height, false); EditorGUI.EndDisabledGroup(); _particle.fitRect = EditorGUILayout.Toggle("Fit Rect",_particle.fitRect); EditorGUILayout.PropertyField(_surface, false); if(!_surface.boolValue) EditorGUILayout.PropertyField(_edge, false); _edge.floatValue= Mathf.Clamp(_edge.floatValue, 0f, _particle.rectTransform.sizeDelta.x<_particle.rectTransform.sizeDelta.y?_particle.rectWidth:_particle.rectHeight); EditorGUILayout.PropertyField(_spreadType, new GUIContent("Spread"), false); if (_particle.spreadType == SpreadType.Uniform) { EditorGUILayout.PropertyField(_spreadLoop, new GUIContent("Loop"), false); } break; case EmitterShape.Line: EditorGUI.BeginDisabledGroup(_particle.fitRect); EditorGUILayout.PropertyField(_length, false); EditorGUI.EndDisabledGroup(); _particle.fitRect = EditorGUILayout.Toggle("Fit Rect",_particle.fitRect); EditorGUILayout.PropertyField(_spreadType, new GUIContent("Spread"), false); if (_particle.spreadType == SpreadType.Uniform) { EditorGUILayout.PropertyField(_spreadLoop, new GUIContent("Loop"), false); } break; case EmitterShape.Directional: EditorGUILayout.PropertyField(_angle, false); EditorGUILayout.PropertyField(_spreadType, new GUIContent("Spread"), false); if (_particle.spreadType == SpreadType.Uniform) { EditorGUILayout.PropertyField(_spreadLoop, new GUIContent("Loop"), false); } break; } DrawHorizontalLine(); EditorGUILayout.PropertyField(_startPoint,new GUIContent("Emitter Constraint"), false); if (_particle.emitterConstraintEnabled) { EditorGUILayout.PropertyField(_startPointTrans,new GUIContent("Transform"), false); } GUILayout.Space(2); } _particle.moduleParticleFoldout = Foldout("Particle", _particle.moduleParticleFoldout,_particleModuleIcon); if (_particle.moduleParticleFoldout) { EditorGUILayout.PropertyField(_texture, new GUIContent("Texture")); EditorGUILayout.PropertyField(_material, new GUIContent("Material")); DrawHorizontalLine(); EditorGUILayout.PropertyField(_speedOverLifetime, false); DrawHorizontalLine(); EditorGUILayout.PropertyField(_sizeOverLifetime, false); EditorGUILayout.PropertyField(_sizeBySpeed, false); EditorGUILayout.PropertyField(_sizeSpeedRange, new GUIContent("Size Speed Range"), false); DrawHorizontalLine(); EditorGUILayout.PropertyField(_colorOverLifetime, false); EditorGUILayout.PropertyField(_colorBySpeed, false); EditorGUILayout.PropertyField(_colorSpeedRange, new GUIContent("Color Speed Range"), false); DrawHorizontalLine(); EditorGUILayout.PropertyField(_rotateOverLifetime, false); EditorGUILayout.PropertyField(_rotationBySpeed, false); EditorGUILayout.PropertyField(_rotationSpeedRange, new GUIContent("Rotation Speed Range"), false); EditorGUILayout.PropertyField(_alignDirection); DrawHorizontalLine(); EditorGUILayout.PropertyField(_sheetModule, new GUIContent("Texture Sheet")); if (_sheetModule.FindPropertyRelative("enabled").boolValue) { EditorGUILayout.PropertyField(_tile, new GUIContent("Tiles"), false); EditorGUILayout.PropertyField(_sheetType, new GUIContent("Time Mode"), false); switch (_particle.textureSheetType) { case SheetType.Lifetime: EditorGUILayout.PropertyField(_frameOverTime, false); EditorGUILayout.PropertyField(_startFrame, false); EditorGUILayout.PropertyField(_cycles, false); ParticleSystem.MinMaxCurve c = _particle.textureSheetFrameOverTime; switch (_particle.textureSheetFrameOverTime.mode) { case ParticleSystemCurveMode.Curve: c.curveMultiplier = Mathf.Clamp(_particle.textureSheetFrameOverTime.curveMultiplier, 0, _particle.textureTile.x*_particle.textureTile.y); break; case ParticleSystemCurveMode.TwoCurves: c.curveMultiplier = Mathf.Clamp(_particle.textureSheetFrameOverTime.curveMultiplier, 0, _particle.textureTile.x*_particle.textureTile.y); break; case ParticleSystemCurveMode.TwoConstants: c.constantMax = Mathf.Clamp(_particle.textureSheetFrameOverTime.constantMax, 0, _particle.textureTile.x*_particle.textureTile.y); break; case ParticleSystemCurveMode.Constant: c.constant = Mathf.Clamp(_particle.textureSheetFrameOverTime.constant, 0, _particle.textureTile.x*_particle.textureTile.y); break; } _particle.textureSheetFrameOverTime = c; break; case SheetType.Speed: EditorGUILayout.PropertyField(_frameSpeedRange, new GUIContent("Speed Range"), false); EditorGUILayout.PropertyField(_startFrame, false); break; case SheetType.FPS: EditorGUILayout.PropertyField(_startFrame, false); EditorGUILayout.PropertyField(_frameFps, new GUIContent("FPS"),false); break; } ParticleSystem.MinMaxCurve sf = _particle.textureSheetStartFrame; switch (_particle.textureSheetStartFrame.mode) { case ParticleSystemCurveMode.Curve: sf.curveMultiplier = Mathf.Clamp(_particle.textureSheetStartFrame.curveMultiplier, 0, _particle.textureTile.x*_particle.textureTile.y); break; case ParticleSystemCurveMode.TwoCurves: sf.curveMultiplier = Mathf.Clamp(_particle.textureSheetStartFrame.curveMultiplier, 0, _particle.textureTile.x*_particle.textureTile.y); break; case ParticleSystemCurveMode.TwoConstants: sf.constantMax = Mathf.Clamp(_particle.textureSheetStartFrame.constantMax, 0, _particle.textureTile.x*_particle.textureTile.y); break; case ParticleSystemCurveMode.Constant: sf.constant = Mathf.Clamp(_particle.textureSheetStartFrame.constant, 0, _particle.textureTile.x*_particle.textureTile.y); break; } _particle.textureSheetStartFrame = sf; } DrawHorizontalLine(); EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(_trailModule, new GUIContent("Trails"), false); if (EditorGUI.EndChangeCheck()) { if (_trailModule.FindPropertyRelative("enabled").boolValue) { GameObject tr = new GameObject("Trails"); tr.transform.parent = _particle.transform; tr.transform.localPosition = Vector3.zero; tr.transform.localScale = Vector3.one; tr.transform.localEulerAngles = Vector3.zero; tr.AddComponent(); ParticleTrailRenderer r = tr.AddComponent(); _particle.particleTrailRenderer = r; r.particle = _particle; } else { var ch = _particle.GetComponentsInChildren(); for (int i = 0; i < ch.Length; i++) { DestroyImmediate(ch[i].gameObject); } } } if (_trailModule.FindPropertyRelative("enabled").boolValue) { EditorGUILayout.HelpBox("Please note that trails are in the beta stage and are not optimized for production use. Therefore, it is recommended that you apply for as few particles as possible.", MessageType.Warning); EditorGUILayout.PropertyField(_trailRatio, new GUIContent("Trail Ratio"),false); EditorGUILayout.PropertyField(_minimumVertexDistance, new GUIContent("Vertex Distance"),false); EditorGUILayout.PropertyField(_trailLifetime, new GUIContent("Trail Lifetime"),false); EditorGUILayout.PropertyField(_trailWidth, new GUIContent("Trail Width"),false); EditorGUILayout.PropertyField(_inheritColor, new GUIContent("Inherit Particle Color"),false); EditorGUILayout.PropertyField(_trailColorOverLifetime, new GUIContent("Color over Lifetime"),false); EditorGUILayout.PropertyField(_trailColorOverTrail, new GUIContent("Color over Trail"),false); EditorGUILayout.PropertyField(_dieWithParticle, new GUIContent("Die With Particle"),false); } GUILayout.Space(4); } _particle.moduleMovementFoldout = Foldout("Movement", _particle.moduleMovementFoldout,_movementModuleIcon); if (_particle.moduleMovementFoldout) { EditorGUILayout.PropertyField(_targetModule, new GUIContent("Attractor"),false); if (_targetModule.FindPropertyRelative("enabled").boolValue) { EditorGUILayout.PropertyField(_targetTransform,new GUIContent("Attractor"), false); EditorGUILayout.PropertyField(_targetCurve,new GUIContent("Attractor Lerp"), false); if(_particle.attractorTarget != null) EditorGUI.BeginDisabledGroup(_particle.attractorTarget.GetType() != typeof(RectTransform)); else EditorGUI.BeginDisabledGroup(false); EditorGUILayout.PropertyField(_targetMode, new GUIContent("Attractor Mode"),false); EditorGUI.EndDisabledGroup(); } DrawHorizontalLine(); EditorGUILayout.PropertyField(_noiseModule, new GUIContent("Noise"), false); if (_noiseModule.FindPropertyRelative("enabled").boolValue) { EditorGUILayout.PropertyField(_noiseStrength,new GUIContent("Strength"), false); EditorGUILayout.PropertyField(_noiseFreq,new GUIContent("Frequency"), false); EditorGUILayout.PropertyField(_noiseOct, new GUIContent("Octaves"),false); _particle.noise.SetFrequency(_particle.noiseFrequency/100f); _particle.noise.SetFractalOctaves(_particle.noiseOctaves); } DrawHorizontalLine(); EditorGUILayout.PropertyField(_velocityModule, new GUIContent("Velocity"), false); if (_velocityModule.FindPropertyRelative("enabled").boolValue) { EditorGUILayout.PropertyField(_velocitySpace,new GUIContent("Space"), false); EditorGUILayout.PropertyField(_velocityOverLifetime,new GUIContent("Velocity Over Lifetime"), false); } DrawHorizontalLine(); EditorGUILayout.PropertyField(_gravityModule, new GUIContent("Gravity"), false); if (_gravityModule.FindPropertyRelative("enabled").boolValue) { EditorGUILayout.PropertyField(_gravity,new GUIContent("Gravity Force"), false); } DrawHorizontalLine(); EditorGUILayout.PropertyField(_vortexModule, new GUIContent("Vortex"), false); if (_vortexModule.FindPropertyRelative("enabled").boolValue) { EditorGUILayout.PropertyField(_vortexStrength, false); } GUILayout.Space(4); } _particle.moduleEventsFoldout = Foldout("Events", _particle.moduleEventsFoldout,_eventModuleIcon); if (_particle.moduleEventsFoldout) { EditorGUILayout.PropertyField(_onStart, false); EditorGUILayout.PropertyField(_onFirstParticleFinish, false); EditorGUILayout.PropertyField(_onParticleFinish, false); EditorGUILayout.PropertyField(_onLastParticleFinish, false); EditorGUILayout.PropertyField(_onFinish, false); } serializedObject.ApplyModifiedProperties(); } void EditorUpdate() { EditorApplication.QueuePlayerLoopUpdate(); } private void DrawHorizontalLine(int height = 1) { GUILayout.Space(2); Rect rect = GUILayoutUtility.GetRect(10, height, GUILayout.ExpandWidth(true)); rect.height = height; rect.xMin = 18; rect.xMax = EditorGUIUtility.currentViewWidth - 18; Color lineColor = new Color(0.15f, 0.15f, 0.15f, 1); EditorGUI.DrawRect(rect, lineColor); GUILayout.Space(2); } private bool Foldout(string title, bool display, Texture icon) { var rect = GUILayoutUtility.GetRect(16f, 24f, FoldoutStyle); GUI.Box(rect, title, FoldoutStyle); var e = Event.current; var toggleRect = new Rect(rect.x + 4f, rect.y + 4f, 13f, 13f); if (e.type == EventType.Repaint) { EditorStyles.foldout.Draw(new Rect(rect.width - 4f, rect.y + 4f, 13f, 13f), false, false, display, false); GUI.DrawTexture(toggleRect, icon); } if (e.type == EventType.MouseDown && rect.Contains(e.mousePosition)) { display = !display; e.Use(); } return display; } } }