using UnityEngine; using UnityEditor; using UnityEngine.VFX; using UnityEditorInternal; using System.Collections.Generic; namespace UnityEditor.VFX { static class VFXEventTesterWindow { public static bool visible { get { return s_Visible; } set { SetVisibility(value); } } static bool s_Visible; [SerializeField] static string m_CustomEvent = "CustomEvent"; [SerializeField] static List m_Attributes; static VisualEffect m_Effect; static ReorderableList list; static readonly string PreferenceName = "VFXEventTester.Visible"; static VFXEventTesterWindow() { m_Attributes = new List(); s_Visible = EditorPrefs.GetBool(PreferenceName, false); list = new ReorderableList(m_Attributes, typeof(EventAttribute), true, true, true, true); list.drawHeaderCallback = drawHeader; list.drawElementCallback = drawItem; list.onAddDropdownCallback = drawAddDropDown; } static void SetVisibility(bool visible) { if (visible != s_Visible) { s_Visible = visible; EditorPrefs.SetBool(PreferenceName, visible); UpdateVisibility(); } } [InitializeOnLoadMethod] static void UpdateVisibility() { if (s_Visible) SceneView.duringSceneGui += DrawWindow; else SceneView.duringSceneGui -= DrawWindow; } private static void drawAddDropDown(Rect buttonRect, ReorderableList list) { GenericMenu menu = new GenericMenu(); // Add Generic Attributes menu.AddItem(new GUIContent("Standard/Position"), false, AddVector3, "position"); menu.AddItem(new GUIContent("Standard/Velocity"), false, AddVector3, "velocity"); menu.AddItem(new GUIContent("Standard/Size"), false, AddFloat, "size"); menu.AddItem(new GUIContent("Standard/Mass"), false, AddFloat, "mass"); menu.AddItem(new GUIContent("Standard/Color"), false, AddColor, "color"); menu.AddItem(new GUIContent("Standard/Alpha"), false, AddFloat, "alpha"); menu.AddItem(new GUIContent("Standard/Age"), false, AddFloat, "age"); menu.AddItem(new GUIContent("Standard/Lifetime"), false, AddFloat, "lifetime"); menu.AddItem(new GUIContent("Standard/Alive"), false, AddBool, "alive"); menu.AddItem(new GUIContent("Standard/Scale.X"), false, AddFloat, "scaleX"); menu.AddItem(new GUIContent("Standard/Scale.Y"), false, AddFloat, "scaleY"); menu.AddItem(new GUIContent("Standard/Scale.Z"), false, AddFloat, "scaleZ"); menu.AddItem(new GUIContent("Standard/Angle.X"), false, AddFloat, "angleX"); menu.AddItem(new GUIContent("Standard/Angle.Y"), false, AddFloat, "angleY"); menu.AddItem(new GUIContent("Standard/Angle.Z"), false, AddFloat, "angleZ"); // Add Advanced Attributes menu.AddItem(new GUIContent("Advanced/OldPosition"), false, AddVector3, "oldPosition"); menu.AddItem(new GUIContent("Advanced/TargetPosition"), false, AddVector3, "targetPosition"); menu.AddItem(new GUIContent("Advanced/Direction"), false, AddVector3, "direction"); menu.AddItem(new GUIContent("Advanced/AngularVelocity.X"), false, AddFloat, "angularVelocityX"); menu.AddItem(new GUIContent("Advanced/AngularVelocity.Y"), false, AddFloat, "angularVelocityY"); menu.AddItem(new GUIContent("Advanced/AngularVelocity.Z"), false, AddFloat, "angularVelocityZ"); // Add Generic Attributes menu.AddItem(new GUIContent("Custom/Custom bool"), false, AddBool, "customBool"); menu.AddItem(new GUIContent("Custom/Custom Float"), false, AddFloat, "customFloat"); menu.AddItem(new GUIContent("Custom/Custom Vector2"), false, AddVector2, "customVector2"); menu.AddItem(new GUIContent("Custom/Custom Vector3"), false, AddVector3, "customVector3"); menu.AddItem(new GUIContent("Custom/Custom Color"), false, AddColor, "customColor"); // Add Custom Types menu.ShowAsContext(); } static void AddFloat(object name) { m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Float, 0.0f)); } static void AddBool(object name) { m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Bool, true)); } static void AddVector2(object name) { m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Vector2, Vector2.zero)); } static void AddVector3(object name) { m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Vector3, Vector3.zero)); } static void AddColor(object name) { m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Color, Color.white)); } static void DrawWindow(SceneView sceneView) { if (Selection.activeGameObject != null) { if (Selection.activeGameObject.TryGetComponent(out m_Effect)) { SceneViewOverlay.Window(Contents.title, WindowFunction, 599, SceneViewOverlay.WindowDisplayOption.OneWindowPerTitle); } else { m_Effect = null; } } } static void WindowFunction(UnityEngine.Object target, SceneView sceneView) { WindowGUI(); } [System.Serializable] enum EventAttributeType { Float = 0, Vector2 = 1, Vector3 = 2, Color = 3, Bool = 4 } [System.Serializable] class EventAttribute { public string name; public EventAttributeType type; public object value; public EventAttribute() { name = "Attribute"; type = EventAttributeType.Float; value = 0.0f; } public EventAttribute(string name, EventAttributeType type, object value) { this.name = name; this.type = type; this.value = value; } } private static void drawHeader(Rect rect) { GUI.Label(rect, "Event Attributes"); } static void drawItem(Rect rect, int index, bool isActive, bool isFocused) { if (m_Attributes[index] == null) { var color = GUI.color; GUI.color = Color.red; EditorGUI.LabelField(rect, "NULL OR DELETED"); GUI.color = color; return; } rect.yMin += 2; rect.height = 16; var namerect = rect; namerect.width = 100; m_Attributes[index].name = GUI.TextField(namerect, m_Attributes[index].name); var typerect = rect; typerect.xMin = rect.xMin + 108; typerect.width = 76; m_Attributes[index].type = (EventAttributeType)EditorGUI.EnumPopup(typerect, m_Attributes[index].type); var valueRect = rect; valueRect.xMin = rect.xMin + 192; switch (m_Attributes[index].type) { case EventAttributeType.Bool: if (m_Attributes[index].value == null || !(m_Attributes[index].value is bool)) m_Attributes[index].value = true; m_Attributes[index].value = (bool)EditorGUI.Toggle(valueRect, (bool)m_Attributes[index].value); break; case EventAttributeType.Float: if (m_Attributes[index].value == null || !(m_Attributes[index].value is float)) m_Attributes[index].value = 1.0f; m_Attributes[index].value = (float)EditorGUI.FloatField(valueRect, (float)m_Attributes[index].value); break; case EventAttributeType.Vector2: if (m_Attributes[index].value == null || !(m_Attributes[index].value is Vector2)) m_Attributes[index].value = Vector2.zero; m_Attributes[index].value = (Vector2)EditorGUI.Vector2Field(valueRect, "", (Vector2)m_Attributes[index].value); break; case EventAttributeType.Vector3: if (m_Attributes[index].value == null || !(m_Attributes[index].value is Vector3)) m_Attributes[index].value = Vector3.zero; m_Attributes[index].value = (Vector3)EditorGUI.Vector3Field(valueRect, "", (Vector3)m_Attributes[index].value); break; case EventAttributeType.Color: if (m_Attributes[index].value == null || !(m_Attributes[index].value is Color)) m_Attributes[index].value = Color.white; m_Attributes[index].value = (Color)EditorGUI.ColorField(valueRect, (Color)m_Attributes[index].value); // The is a hotControl id hash collision with the selection rectangle that cause of a lost of selection on mouseup. if (Event.current.type == EventType.MouseUp && valueRect.Contains(Event.current.mousePosition)) GUIUtility.hotControl = 0; break; } } static void WindowGUI() { EditorGUI.BeginDisabled(m_Effect == null); EditorGUILayout.Space(); list.DoLayoutList(); EditorGUILayout.Space(); using (new GUILayout.HorizontalScope(GUILayout.Width(358))) { if (GUILayout.Button("Play", Styles.leftButton, GUILayout.Height(24))) { SendEvent("OnPlay"); } if (GUILayout.Button("Stop", Styles.middleButton, GUILayout.Height(24))) { SendEvent("OnStop"); } if (GUILayout.Button("Custom", Styles.rightButton, GUILayout.Height(24))) { SendEvent(m_CustomEvent); } } m_CustomEvent = EditorGUILayout.TextField("Custom Event", m_CustomEvent); EditorGUI.EndDisabled(); } static void SendEvent(string name) { if (m_Effect == null) return; var attrib = m_Effect.CreateVFXEventAttribute(); if (attrib == null) return; // set all attributes foreach (var attribute in m_Attributes) { if (attribute == null) continue; switch (attribute.type) { case EventAttributeType.Bool: attrib.SetBool(attribute.name, (bool)attribute.value); break; case EventAttributeType.Float: attrib.SetFloat(attribute.name, (float)attribute.value); break; case EventAttributeType.Vector2: attrib.SetVector2(attribute.name, (Vector2)attribute.value); break; case EventAttributeType.Vector3: attrib.SetVector3(attribute.name, (Vector3)attribute.value); break; case EventAttributeType.Color: attrib.SetVector4(attribute.name, (Color)attribute.value); break; } } // then send event with attributes if (name == "OnPlay") m_Effect.Play(attrib); else if (name == "OnStop") m_Effect.Stop(attrib); else m_Effect.SendEvent(name, attrib); } static class Contents { public static readonly GUIContent title = new GUIContent("VFX Event Tester"); } static class Styles { public static GUIStyle leftButton; public static GUIStyle middleButton; public static GUIStyle rightButton; static Styles() { leftButton = new GUIStyle(EditorStyles.miniButtonLeft); middleButton = new GUIStyle(EditorStyles.miniButtonMid); rightButton = new GUIStyle(EditorStyles.miniButtonRight); leftButton.fontSize = 12; middleButton.fontSize = 12; rightButton.fontSize = 12; } } } }