#if UNITY_EDITOR using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; using TMPro; using UnityEngine.Rendering; using DamageNumbersPro.Internal; using UnityEditor.SceneManagement; namespace DamageNumbersPro { [CustomEditor(typeof(DamageNumber), true), CanEditMultipleObjects] public class DamageNumberEditor : Editor { public static string version = "4.49"; void OnEnable() { DNPEditorInternal.PrepareInspector(this); } public override void OnInspectorGUI() { // For some operations bool isMesh = DNPEditorInternal.damageNumbers[0].IsMesh(); // Internal DNPEditorInternal.OnInspectorGUI(this); DNPEditorInternal.BeginInspector(); DNPEditorInternal.DrawInspectorTop(isMesh); // Structure if (DNPEditorInternal.CheckStructure(this)) { DNPEditorInternal.EndInspector(); return; } // Detect and warn about common mistakes WarningCheck(isMesh); // Update serializedObject.Update(); switch(DNPEditorInternal.currentTab) { case (0): // Main DisplayMainSettings(); DisplayFeature("enable3DGame", "3D Game"); break; case (1): // Text DisplayTextMain(isMesh); DisplayFeature("enableNumber", "Number"); DisplayFeature("enableLeftText", "Left Text"); DisplayFeature("enableRightText", "Right Text"); DisplayFeature("enableTopText", "Top Text"); DisplayFeature("enableBottomText", "Bottom Text"); DisplayFeature("enableColorByNumber", "Color By Number"); break; case (2): // Fade In DisplayFadeMain("In"); DisplayFeature("enableOffsetFadeIn", "Offset In", "Offset"); DisplayFeature("enableScaleFadeIn", "Scale In", "Scale"); DisplayFeature("enableShakeFadeIn", "Shake In", "Shake"); DisplayFeature("enableCrossScaleFadeIn", "Cross Scale In", "Cross Scale"); break; case (3): // Fade Out DisplayFadeMain("Out"); DisplayFeature("enableOffsetFadeOut", "Offset Out", "Offset"); DisplayFeature("enableScaleFadeOut", "Scale Out", "Scale"); DisplayFeature("enableShakeFadeOut", "Shake Out", "Shake"); DisplayFeature("enableCrossScaleFadeOut", "Cross Scale Out", "Cross Scale"); break; case (4): // Movement DisplayFeature("enableLerp", "Lerp"); DisplayFeature("enableVelocity", "Velocity"); DisplayFeature("enableShaking", "Shaking"); DisplayFeature("enableFollowing", "Following"); DisplayMovementHints(isMesh); break; case (5): // Scale DisplayFeature("enableStartRotation", "Start Rotation"); DisplayFeature("enableRotateOverTime", "Rotate Over Time"); DisplayFeature("enableScaleByNumber", "Scale By Number"); DisplayFeature("enableScaleOverTime", "Scale Over Time"); DisplayFeature("enableOrthographicScaling", "Orthographic Scaling"); break; case (6): // Spam Control DisplaySpamControlMain(isMesh); DisplayFeature("enableCombination", "Combination"); DisplayFeature("enableDestruction", "Destruction"); DisplayFeature("enableCollision", "Collision"); DisplayFeature("enablePush", "Push"); DisplaySpamControlHints(isMesh); break; case (7): // Performance DisplayPerformanceMain(); DisplayFeature("enablePooling", "Pooling"); DisplayPerformanceHints(); break; } // Fix Variables foreach(DamageNumber dn in DNPEditorInternal.damageNumbers) { FixAllVariables(dn); } // Apply Properties serializedObject.ApplyModifiedProperties(); // Update Text if (Application.isPlaying == false) { foreach (DamageNumber damageNumber in DNPEditorInternal.damageNumbers) { if(damageNumber.gameObject.activeInHierarchy) { if (isMesh) { DNPEditorInternal.FixTextMeshPro(); } try { damageNumber.UpdateText(); damageNumber.UpdateAlpha(1); } catch { } if (isMesh) { damageNumber.GetTextMesh().gameObject.SetActive(true); } } } } // External Editors DNPEditorInternal.Externalnspectors(isMesh, target); DNPEditorInternal.FinalInformation(); DNPEditorInternal.EndInspector(); } #region Editor Menus [MenuItem("GameObject/Damage Numbers Pro/Damage Number (Mesh)", priority = 1)] public static void CreateDamageNumberMesh(MenuCommand menuCommand) { // Create GameObject GameObject newDN = new GameObject("Damage Number (Mesh)"); GameObjectUtility.SetParentAndAlign(newDN, menuCommand.context as GameObject); Undo.RegisterCreatedObjectUndo(newDN, "Create " + newDN.name); Selection.activeObject = newDN; // Add damage number component newDN.AddComponent(); // Prepare Structure DNPEditorInternal.PrepareMeshStructure(newDN); // Position if(Camera.main != null) { // Position in front of the camera Vector3 position = Camera.main.transform.position + Camera.main.transform.forward * 10; // Set Z to 0 for 2D Games if(Camera.main.orthographic) { position.z = 0; } newDN.transform.position = position; } } [MenuItem("GameObject/Damage Numbers Pro/Damage Number (GUI)", priority = 2)] public static void CreateDamageNumberGUI(MenuCommand menuCommand) { // Create GameObject GameObject newDN = new GameObject("Damage Number (GUI)"); GameObjectUtility.SetParentAndAlign(newDN, menuCommand.context as GameObject); Undo.RegisterCreatedObjectUndo(newDN, "Create " + newDN.name); Selection.activeObject = newDN; // Add damage number component newDN.AddComponent(); // Prepare Structure DNPEditorInternal.PrepareGUIStructure(newDN); // Position if (Camera.main != null) { // Position in front of the camera Vector3 position = Camera.main.transform.position + Camera.main.transform.forward * 10; // Set Z to 0 for 2D Games if (Camera.main.orthographic) { position.z = 0; } newDN.transform.position = position; } } [MenuItem("CONTEXT/DamageNumberMesh/Switch to GUI (experimental)")] public static void SwitchToGUI(MenuCommand menuCommand) { foreach(GameObject selected in Selection.gameObjects) { DamageNumberMesh oldComponent = selected.GetComponent(); Undo.RecordObject(oldComponent.gameObject, "Switched " + oldComponent.name); if (oldComponent != null) { // Get TMP Settings TMP_FontAsset fontAsset = oldComponent.GetFontMaterial(); Color tmpColor = oldComponent.GetTextMesh().color; VertexGradient colorGradient = oldComponent.GetTextMesh().colorGradient; bool enableGradient = oldComponent.GetTextMesh().enableVertexGradient; // Clear Children while (oldComponent.transform.childCount > 0) { Object.DestroyImmediate(oldComponent.transform.GetChild(0).gameObject); } // Add GUI Component DamageNumberGUI newComponent = oldComponent.gameObject.AddComponent(); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); DNPEditorInternal.PrepareGUIStructure(selected); // TMP Settings newComponent.SetFontMaterial(fontAsset); foreach(TMP_Text tmp in newComponent.GetTextMeshs()) { tmp.color = tmpColor; tmp.enableVertexGradient = enableGradient; tmp.colorGradient = colorGradient; } // Settings foreach (System.Reflection.FieldInfo propA in oldComponent.GetType().GetFields()) { System.Reflection.FieldInfo propB = newComponent.GetType().GetField(propA.Name); if(propB.IsPublic && propB.IsPublic) { propB.SetValue(newComponent, propA.GetValue(oldComponent)); } } // 3D newComponent.enable3DGame = false; // Remove old component DestroyImmediate(oldComponent); } } } [MenuItem("CONTEXT/DamageNumberGUI/Switch to Mesh (experimental)")] public static void SwitchToMesh(MenuCommand menuCommand) { foreach (GameObject selected in Selection.gameObjects) { DamageNumberGUI previousComponent = selected.GetComponent(); Undo.RecordObject(previousComponent.gameObject, "Switched " + previousComponent.name); if (previousComponent != null) { // Get TMP Settings TMP_FontAsset fontAsset = previousComponent.GetFontMaterial(); Color tmpColor = previousComponent.GetTextMesh().color; VertexGradient colorGradient = previousComponent.GetTextMesh().colorGradient; bool enableGradient = previousComponent.GetTextMesh().enableVertexGradient; // Clear Children while (previousComponent.transform.childCount > 0) { Object.DestroyImmediate(previousComponent.transform.GetChild(0).gameObject); } // Add GUI Component DamageNumberMesh newComponent = previousComponent.gameObject.AddComponent(); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); UnityEditorInternal.ComponentUtility.MoveComponentUp(newComponent); DNPEditorInternal.PrepareMeshStructure(selected); // TMP Settings newComponent.SetFontMaterial(fontAsset); foreach (TMP_Text tmp in newComponent.GetTextMeshs()) { tmp.color = tmpColor; tmp.enableVertexGradient = enableGradient; tmp.colorGradient = colorGradient; } // Settings foreach (System.Reflection.FieldInfo propA in previousComponent.GetType().GetFields()) { System.Reflection.FieldInfo propB = newComponent.GetType().GetField(propA.Name); if (propB.IsPublic && propB.IsPublic) { propB.SetValue(newComponent, propA.GetValue(previousComponent)); } } // 3D newComponent.CheckAndEnable3D(); // Remove old components DestroyImmediate(previousComponent); RectTransform rectComponent = selected.GetComponent(); if(rectComponent != null) { Debug.Log("Please rightclick on the RectTransform component and select 'Remove Component'."); } } } } #endregion #region Fixing Variables void FixAllVariables(DamageNumber dn) { // Performance dn.updateDelay = Mathf.Max(0, dn.updateDelay); // Main dn.lifetime = Mathf.Max(0, dn.lifetime); dn.distanceScalingSettings.baseDistance = Mathf.Max(1, dn.distanceScalingSettings.baseDistance); // Text dn.numberSettings = FixTextSettings(dn.numberSettings); dn.leftTextSettings = FixTextSettings(dn.leftTextSettings); dn.rightTextSettings = FixTextSettings(dn.rightTextSettings); // Fade dn.durationFadeIn = Mathf.Max(0, dn.durationFadeIn); dn.durationFadeOut = Mathf.Max(0, dn.durationFadeOut); // Digit dn.digitSettings.decimals = Mathf.Max(0, dn.digitSettings.decimals); dn.digitSettings.dotDistance = Mathf.Max(0, dn.digitSettings.dotDistance); // Text Shader TMP_FontAsset font = dn.GetFontMaterial(); string is3D = dn.enable3DGame ? "3D" : ""; if(dn.enable3DGame && dn.IsMesh() && font != null && font.name + is3D != dn.editorLastFont) { dn.editorLastFont = font.name + is3D; Object[] objects = new Object[2]; objects[0] = dn; objects[1] = font; Undo.RecordObjects(objects, "Swiched shader to distance field overlay."); // Fixing the text shader if(GraphicsSettings.currentRenderPipeline != null) { string pipeline = GraphicsSettings.currentRenderPipeline.GetType().ToString(); if(pipeline.Contains("High") || pipeline.Contains("HD")) { } else { ChangeShaderToOverlay(dn); } } else { ChangeShaderToOverlay(dn); } // Fixing the sprite shader TMP_Text tmp = dn.GetTextMesh(); if (tmp.spriteAsset != null && tmp.spriteAsset.material != null) { // Sprite Shader if (tmp.spriteAsset.material.shader.name != "TextMeshPro/Sprite Overlay") { Shader spriteOverlay = Shader.Find("TextMeshPro/Sprite Overlay"); if (spriteOverlay != null) { tmp.spriteAsset.material.shader = spriteOverlay; } } } else { // Default Sprite Shader if (TMP_Settings.defaultSpriteAsset != null && TMP_Settings.defaultSpriteAsset.material != null && TMP_Settings.defaultSpriteAsset.material.shader.name != "TextMeshPro/Sprite Overlay") { Shader spriteOverlay = Shader.Find("TextMeshPro/Sprite Overlay"); if (spriteOverlay != null) { TMP_Settings.defaultSpriteAsset.material.shader = spriteOverlay; } } } } } TextSettings FixTextSettings(TextSettings ts) { ts.horizontal = Mathf.Max(0, ts.horizontal); return ts; } #endregion #region Warnings void WarningCheck(bool isMesh) { // 3D Game and no 3D enabled bool gameIs3DWarning = false; if(isMesh) { Camera camera = Camera.main; if (camera != null) { if (camera.orthographic == false) { foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { if (!dn.enable3DGame) { gameIs3DWarning = true; break; } } } } } if(gameIs3DWarning) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(new Color(1, 1f, 0.8f)); GUI.color = new Color(1, 1, 0.8f, 0.7f); DNPEditorInternal.ScalingLabel("Your main camera seems to be perspective (3D).",298); DNPEditorInternal.ScalingLabel("Go to the Main tab and enable 3D Game.",256); DNPEditorInternal.CloseBox(new Color(1, 1f, 0.7f)); } // 3D but UI Warning if(isMesh == false) { foreach(DamageNumber dn in DNPEditorInternal.damageNumbers) { if(dn.enable3DGame) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(new Color(1, 1f, 0.8f)); GUI.color = new Color(1, 1, 0.8f, 0.7f); DNPEditorInternal.ScalingLabel("You have 3D Game enabled on the GUI version.", 298); DNPEditorInternal.ScalingLabel("This component is for spawning prefabs in a GUI canvas.", 298); DNPEditorInternal.CloseBox(new Color(1, 1f, 0.7f)); } } } // Pooling and Runtime Prefab Edits bool runtimePoolingWarning = false; if (Application.isPlaying) { foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { if (dn.enablePooling) { runtimePoolingWarning = true; break; } } } if (runtimePoolingWarning) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(new Color(1, 1f, 0.8f)); GUI.color = new Color(1, 1, 0.8f, 0.7f); DNPEditorInternal.ScalingLabel("You are editing this prefab at runtime with pooling enabled.",361); DNPEditorInternal.ScalingLabel("Prefab changes will not affect pooled damage numbers.",343); DNPEditorInternal.CloseBox(new Color(1, 1f, 0.7f)); } // Scale By Number but no Numbers bool scaleByNumbersWarning = false; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { if (dn.enableScaleByNumber && !dn.enableNumber) { scaleByNumbersWarning = true; break; } } if (scaleByNumbersWarning) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(new Color(1, 1f, 0.8f)); GUI.color = new Color(1, 1, 0.8f, 0.7f); DNPEditorInternal.ScalingLabel("Scale By Number will not work if Number is disabled.",327); DNPEditorInternal.CloseBox(new Color(1, 1f, 0.7f)); } // Color By Number but no Numbers bool colorByNumbersWarning = false; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { if (dn.enableColorByNumber && !dn.enableNumber) { colorByNumbersWarning = true; break; } } if (colorByNumbersWarning) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(new Color(1, 1f, 0.8f)); GUI.color = new Color(1, 1, 0.8f, 0.7f); DNPEditorInternal.ScalingLabel("Color By Number will not work if Number is disabled.", 327); DNPEditorInternal.CloseBox(new Color(1, 1f, 0.7f)); } // Collision but no Lerp bool collisionWarning = false; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { if (dn.enableCollision && !dn.enableLerp) { collisionWarning = true; break; } } if (collisionWarning) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(new Color(1, 1f, 0.8f)); GUI.color = new Color(1, 1, 0.8f, 0.7f); DNPEditorInternal.ScalingLabel("Collision will not work if Lerp movement is disabled.",317); DNPEditorInternal.CloseBox(new Color(1, 1f, 0.7f)); } // Push but no Lerp bool pushWarning = false; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { if (dn.enablePush && !dn.enableLerp) { pushWarning = true; break; } } if (pushWarning) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(new Color(1, 1f, 0.8f)); GUI.color = new Color(1, 1, 0.8f, 0.7f); DNPEditorInternal.ScalingLabel("Push will not work if Lerp movement is disabled.",298); DNPEditorInternal.CloseBox(new Color(1, 1f, 0.7f)); } } #endregion #region Properties void DisplayFeature(string togglePropertyName, string featureTitle = "", string displayedTitle = "") { // Create title if needed if (featureTitle == "") { featureTitle = togglePropertyName.Replace("enable", ""); } if(displayedTitle == "") { displayedTitle = featureTitle; } EditorGUILayout.Space(2); // Get Toggle Property SerializedProperty toggleProperty = serializedObject.FindProperty(togglePropertyName); // Start Box DNPEditorInternal.StartBox(toggleProperty.hasMultipleDifferentValues || toggleProperty.boolValue); // Top EditorGUILayout.BeginHorizontal(); bool showProperties = FeatureButton(toggleProperty, displayedTitle); EditorGUILayout.LabelField("", GUILayout.MinWidth(0)); // Extra Buttons #region Text Position if(showProperties) { switch (togglePropertyName) { case ("enableLeftText"): int leftTextPosition = TextPosition(0); if (leftTextPosition != 0) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; // Unselect Fields foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { bool originalTextEnabled = dn.enableLeftText; string originalTextString = dn.leftText; TextSettings originalTextSettings = dn.leftTextSettings; switch (leftTextPosition) { case (1): dn.enableLeftText = dn.enableRightText; dn.leftText = dn.rightText; dn.leftTextSettings = dn.rightTextSettings; dn.enableRightText = originalTextEnabled; dn.rightText = originalTextString; dn.rightTextSettings = originalTextSettings; break; case (2): dn.enableLeftText = dn.enableTopText; dn.leftText = dn.topText; dn.leftTextSettings = dn.topTextSettings; dn.enableTopText = originalTextEnabled; dn.topText = originalTextString; dn.topTextSettings = originalTextSettings; break; case (3): dn.enableLeftText = dn.enableBottomText; dn.leftText = dn.bottomText; dn.leftTextSettings = dn.bottomTextSettings; dn.enableBottomText = originalTextEnabled; dn.bottomText = originalTextString; dn.bottomTextSettings = originalTextSettings; break; } } } break; case ("enableRightText"): int rightTextPosition = TextPosition(1); if (rightTextPosition != 1) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; // Unselect Fields foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { bool originalTextEnabled = dn.enableRightText; string originalTextString = dn.rightText; TextSettings originalTextSettings = dn.rightTextSettings; switch (rightTextPosition) { case (0): dn.enableRightText = dn.enableLeftText; dn.rightText = dn.leftText; dn.rightTextSettings = dn.leftTextSettings; dn.enableLeftText = originalTextEnabled; dn.leftText = originalTextString; dn.leftTextSettings = originalTextSettings; break; case (2): dn.enableRightText = dn.enableTopText; dn.rightText = dn.topText; dn.rightTextSettings = dn.topTextSettings; dn.enableTopText = originalTextEnabled; dn.topText = originalTextString; dn.topTextSettings = originalTextSettings; break; case (3): dn.enableRightText = dn.enableBottomText; dn.rightText = dn.bottomText; dn.rightTextSettings = dn.bottomTextSettings; dn.enableBottomText = originalTextEnabled; dn.bottomText = originalTextString; dn.bottomTextSettings = originalTextSettings; break; } } } break; case ("enableTopText"): int topTextPosition = TextPosition(2); if (topTextPosition != 2) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; // Unselect Fields foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { bool originalTextEnabled = dn.enableTopText; string originalTextString = dn.topText; TextSettings originalTextSettings = dn.topTextSettings; switch (topTextPosition) { case (0): dn.enableTopText = dn.enableLeftText; dn.topText = dn.leftText; dn.topTextSettings = dn.leftTextSettings; dn.enableLeftText = originalTextEnabled; dn.leftText = originalTextString; dn.leftTextSettings = originalTextSettings; break; case (1): dn.enableTopText = dn.enableRightText; dn.topText = dn.rightText; dn.topTextSettings = dn.rightTextSettings; dn.enableRightText = originalTextEnabled; dn.rightText = originalTextString; dn.rightTextSettings = originalTextSettings; break; case (3): dn.enableTopText = dn.enableBottomText; dn.topText = dn.bottomText; dn.topTextSettings = dn.bottomTextSettings; dn.enableBottomText = originalTextEnabled; dn.bottomText = originalTextString; dn.bottomTextSettings = originalTextSettings; break; } } } break; case ("enableBottomText"): int bottomTextPosition = TextPosition(3); if (bottomTextPosition != 3) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; // Unselect Fields foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { bool originalTextEnabled = dn.enableBottomText; string originalTextString = dn.bottomText; TextSettings originalTextSettings = dn.bottomTextSettings; switch (bottomTextPosition) { case (0): dn.enableBottomText = dn.enableLeftText; dn.bottomText = dn.leftText; dn.bottomTextSettings = dn.leftTextSettings; dn.enableLeftText = originalTextEnabled; dn.leftText = originalTextString; dn.leftTextSettings = originalTextSettings; break; case (1): dn.enableBottomText = dn.enableRightText; dn.bottomText = dn.rightText; dn.bottomTextSettings = dn.rightTextSettings; dn.enableRightText = originalTextEnabled; dn.rightText = originalTextString; dn.rightTextSettings = originalTextSettings; break; case (2): dn.enableBottomText = dn.enableTopText; dn.bottomText = dn.topText; dn.bottomTextSettings = dn.topTextSettings; dn.enableTopText = originalTextEnabled; dn.topText = originalTextString; dn.topTextSettings = originalTextSettings; break; } } } break; } } #endregion if (showProperties) { ResetButton(featureTitle); } bool showHints = DNPEditorInternal.HintButton(featureTitle); EditorGUILayout.EndHorizontal(); // Hints if(showHints) { DNPEditorInternal.Lines(); GUI.color = new Color(1, 1, 1, 0.7f); switch(featureTitle) { // Main case ("3D Game"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Handles facing the camera."); DNPEditorInternal.Label("- Handles screen size over distance."); DNPEditorInternal.Label("- Can handle rendering through walls."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Enable this feature in 3D projects."); break; // Text Content case ("Number"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Displays a number."); DNPEditorInternal.Label("- Has several text formatting options."); DNPEditorInternal.Label("- Number can be displayed as an integer or in decimals."); DNPEditorInternal.Label("- Large numbers can be dot separated or suffix shortened."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- If you want text-only simply disable this and enable Left Text."); DNPEditorInternal.Label("- Text positions are relative to the number."); DNPEditorInternal.Label("- Numbers will be added up if Combination is enabled."); DNPEditorInternal.Label("- Numbers will be used by Scale by Number."); break; case ("Left Text"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Displays text on the left side."); DNPEditorInternal.Label("- Has several text formatting options."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- If number is disabled this will be centered."); DNPEditorInternal.Label("- You can use the arrow buttons to swap the position."); DNPEditorInternal.Label("- The Spawn(...) function has overrides which set this text."); break; case ("Right Text"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Displays text on the right side."); DNPEditorInternal.Label("- Has several text formatting options."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- If number is disabled this will be centered."); DNPEditorInternal.Label("- You can use the arrow buttons to swap the position."); break; case ("Top Text"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Displays text on the top side."); DNPEditorInternal.Label("- Has several text formatting options."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- You can use the arrow buttons to swap the position."); break; case ("Bottom Text"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Displays text on the bottom side."); DNPEditorInternal.Label("- Has several text formatting options."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- You can use the arrow buttons to swap the position."); break; case ("Color By Number"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Changes the color based on the number."); DNPEditorInternal.Label("- Larger and smaller numbers can have different tints."); break; // Movement case ("Lerp"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Moves towards a random offset."); DNPEditorInternal.Label("- Slows down as it gets closer to it's target position."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- This is the most popular and readable option."); DNPEditorInternal.Label("- Some features require this and warn you if Lerp is disabled."); DNPEditorInternal.Label("- Offset is relative to view direction."); break; case ("Velocity"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Moves at a random velocity."); DNPEditorInternal.Label("- Has drag and gravity options."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Movement is relative to view direction."); break; case ("Shaking"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Moves back and forth."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Can be used for shaking or vibration effects."); break; case ("Following"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Follows the target transform."); DNPEditorInternal.Label("- Maintains relative position to target."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Lower speeds are more smooth."); DNPEditorInternal.Label("- Higher speeds are more static."); DNPEditorInternal.Label("- Drag can be used to fade out the following."); break; // Fade In case ("Offset In"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Moves 2 meshs together from a offset."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Creates a fusion-like effect."); break; case ("Scale In"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Fades in from a customizable scale."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Is used for shrinking or growing when fading in."); break; case ("Cross Scale In"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Scales one mesh and divides the scale of the other."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Inverse scales one mesh and normally scales the other."); break; case ("Shake In"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Shakes as it fades in."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Used for vibration or motion when fading in."); break; // Fade Out case ("Offset Out"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Moves 2 meshs apart to a offset."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Creates a diffusion-like effect."); break; case ("Scale Out"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Fades out to a customizable scale."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Is used for shrinking or growing when fading out."); break; case ("Cross Scale Out"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Scales one mesh and divides the scale of the other."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Inverse scales one mesh and normally scales the other."); break; case ("Shake Out"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Shakes as it fades out."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Used for vibration or motion when fading out."); break; // Rotation & Scale case ("Start Rotation"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Spawns at a random rotation."); break; case ("Rotate Over Time"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Rotates at a random rotation speed over time."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Speed over time can be customized in a curve."); break; case ("Scale By Number"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Scales based on the number's size."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Bigger numbers are larger."); DNPEditorInternal.Label("- Will also work with Combination."); break; case ("Scale Over Time"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Changes scale over time."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Scale over time can be customized in a curve."); break; case ("Orthographic Scaling"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Scales the popup to keep it's screen size consistent, when zooming in 2D projects."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Scale is based on the camera's orthographic size."); break; // Spam Control case ("Combination"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Combines with other damage numbers within range."); DNPEditorInternal.Label("- Adds up the combined numbers."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- ABSORB_NEW makes the oldest damage number absorb new ones."); DNPEditorInternal.Label("- REPLACE_OLD makes the newest damage number absorb older ones."); DNPEditorInternal.Label("- Animation can be customized using curves."); DNPEditorInternal.Label("- Absorber can get a scale up upon absorbing a damage number."); break; case ("Destruction"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Destroys older damage numbers."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Has a custom fade out animation for destroyed damage numbers."); break; case ("Collision"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Collides with other damage numbers to spread out."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- If desired direction is set to something like (0,10,0) they will spread up."); break; case ("Push"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Simply moves damage numbers by a custom offset within range."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- This is a more efficient version of Collision."); DNPEditorInternal.Label("- Use this on closely spawned damage numbers only."); break; // Performance case ("Pooling"): DNPEditorInternal.Label("Function:"); DNPEditorInternal.Label("- Improves spawn performance by recycling damage numbers."); DNPEditorInternal.Label(""); DNPEditorInternal.Label("Information:"); DNPEditorInternal.Label("- Pool size should be higher if you spawn more damage numbers per second."); DNPEditorInternal.Label("- New damage numbers are added to the pool if it's not full yet."); DNPEditorInternal.Label("- Each prefab has it's own pool."); DNPEditorInternal.Label("- Use PrewarmPool() on a prefab to prepare it's pool."); break; } GUI.color = Color.white; } // Properties if(showProperties) { DNPEditorInternal.Lines(); switch (featureTitle) { // Main case ("3D Game"): SerializedProperty faceCameraView = serializedObject.FindProperty("faceCameraView"); EditorGUILayout.PropertyField(faceCameraView); if(faceCameraView.boolValue || faceCameraView.hasMultipleDifferentValues) { SerializedProperty lookAtCamera = serializedObject.FindProperty("lookAtCamera"); EditorGUILayout.PropertyField(lookAtCamera, new GUIContent("Look At (For VR)")); if(lookAtCamera.boolValue || lookAtCamera.hasMultipleDifferentValues) { GUI.color = new Color(1, 1, 1, 0.7f); DNPEditorInternal.Label("- Costs more performance and should only be used in VR."); GUI.color = Color.white; } } DNPEditorInternal.Lines(); // Check Materials bool hasOverlayMaterials = false; bool hasBadMaterials = false; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { dn.GetReferencesIfNecessary(); Material[] materials = dn.GetSharedMaterials(); if(materials != null) { foreach (Material mat in materials) { if(mat != null && mat.shader.name.EndsWith("verlay")) { hasOverlayMaterials = true; } else { hasBadMaterials = true; } } } } if(hasOverlayMaterials && !hasBadMaterials) { GUI.enabled = false; } SerializedProperty renderThroughWalls = serializedObject.FindProperty("renderThroughWalls"); EditorGUILayout.PropertyField(renderThroughWalls); if (hasOverlayMaterials && !hasBadMaterials) { GUI.enabled = true; renderThroughWalls.boolValue = false; PropertyOverlay(DNPEditorInternal.CheckmarkString(true) + " Overlay Shader."); }else { if(DNPEditorInternal.currentWidth < 344) { if (DNPEditorInternal.currentWidth < 277) { PropertyOverlay(DNPEditorInternal.CheckmarkString(false) + " Shader"); } else { PropertyOverlay(DNPEditorInternal.CheckmarkString(false) + " Overlay Shader"); } } else { PropertyOverlay(DNPEditorInternal.CheckmarkString(false) + " Not using overlay shader."); } } if(renderThroughWalls.boolValue || renderThroughWalls.hasMultipleDifferentValues) { GUI.color = new Color(1, 1, 1, 0.7f); EditorGUILayout.Space(); DNPEditorInternal.ScalingLabel("This option exists in-case the overlay shader does not work.", 371); DNPEditorInternal.ScalingLabel("Make sure to try the 'Distance Field Overlay' shader first.",354); DNPEditorInternal.ScalingLabel("It's better for performance to use the shader instead.",330); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); DNPEditorInternal.ScalingLabel("Go to the material or use the button.",333); GUI.color = Color.white; bool buttonPressed = false; if(DNPEditorInternal.currentWidth < 283) { buttonPressed = GUILayout.Button("Try"); } else { buttonPressed = GUILayout.Button("Try Shader"); } if (buttonPressed) { foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { ChangeShaderToOverlay(dn); } } EditorGUILayout.EndHorizontal(); } DNPEditorInternal.Lines(); SerializedProperty consistentScale = serializedObject.FindProperty("consistentScreenSize"); EditorGUILayout.PropertyField(consistentScale); GUI.enabled = consistentScale.boolValue || consistentScale.hasMultipleDifferentValues; EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("distanceScalingSettings")); EditorGUILayout.EndHorizontal(); GUI.enabled = true; DNPEditorInternal.Lines(); SerializedProperty scaleWithFOV = serializedObject.FindProperty("scaleWithFov"); EditorGUILayout.PropertyField(scaleWithFOV); if (scaleWithFOV.boolValue || scaleWithFOV.hasMultipleDifferentValues) { EditorGUILayout.PropertyField(serializedObject.FindProperty("defaultFov")); EditorGUILayout.PropertyField(serializedObject.FindProperty("fovCamera")); bool noFovCameraOverride = true; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { if (dn.fovCamera != null) { noFovCameraOverride = false; break; } } if (noFovCameraOverride) { string overlayString = "Main Camera"; if (DNPEditorInternal.currentWidth < 404) { overlayString = "Main Camera"; if (DNPEditorInternal.currentWidth < 389) { overlayString = ""; } } if (DNPEditorInternal.currentWidth > 293) { PropertyOverlay(DNPEditorInternal.CheckmarkString(true) + " " + overlayString + " "); } } else { GUI.color = new Color(1, 1, 1, 0.7f); DNPEditorInternal.ScalingLabel("Only required if your main camera is not the FOV camera.", 362); GUI.color = Color.white; } } DNPEditorInternal.Lines(); EditorGUILayout.PropertyField(serializedObject.FindProperty("cameraOverride")); bool noCameraOverride = true; foreach(DamageNumber dn in DNPEditorInternal.damageNumbers) { if(dn.cameraOverride != null) { noCameraOverride = false; break; } } if(noCameraOverride) { string overlayString = "Main Camera"; if (DNPEditorInternal.currentWidth < 404) { overlayString = "Main Camera"; if(DNPEditorInternal.currentWidth < 389) { overlayString = ""; } } if(DNPEditorInternal.currentWidth > 293) { PropertyOverlay(DNPEditorInternal.CheckmarkString(true) + " " + overlayString + " "); } } else { GUI.color = new Color(1, 1, 1, 0.7f); DNPEditorInternal.ScalingLabel("Only required if your main camera is not the target camera.", 362); GUI.color = Color.white; } break; // Text Content case ("Number"): EditorGUILayout.PropertyField(serializedObject.FindProperty("number")); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("numberSettings")); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("digitSettings")); EditorGUILayout.EndHorizontal(); break; case ("Left Text"): HandleTextProperty(serializedObject.FindProperty("leftText")); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("leftTextSettings")); EditorGUILayout.EndHorizontal(); break; case ("Right Text"): HandleTextProperty(serializedObject.FindProperty("rightText")); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("rightTextSettings")); EditorGUILayout.EndHorizontal(); break; case ("Top Text"): HandleTextProperty(serializedObject.FindProperty("topText")); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("topTextSettings")); EditorGUILayout.EndHorizontal(); break; case ("Bottom Text"): HandleTextProperty(serializedObject.FindProperty("bottomText")); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("bottomTextSettings")); EditorGUILayout.EndHorizontal(); break; case ("Color By Number"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("colorByNumberSettings")); EditorGUILayout.EndHorizontal(); break; // Movement case ("Lerp"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("lerpSettings")); EditorGUILayout.EndHorizontal(); break; case ("Velocity"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("velocitySettings")); EditorGUILayout.EndHorizontal(); break; case ("Shaking"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("shakeSettings")); EditorGUILayout.EndHorizontal(); break; case ("Following"): EditorGUILayout.PropertyField(serializedObject.FindProperty("followedTarget")); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("followSettings")); EditorGUILayout.EndHorizontal(); break; // Fade In case ("Offset In"): EditorGUILayout.PropertyField(serializedObject.FindProperty("offsetFadeIn"), new GUIContent("Offset")); break; case ("Scale In"): EditorGUILayout.PropertyField(serializedObject.FindProperty("scaleFadeIn"), new GUIContent("Scale")); break; case ("Cross Scale In"): EditorGUILayout.PropertyField(serializedObject.FindProperty("crossScaleFadeIn"), new GUIContent("Cross Scale")); break; case ("Shake In"): EditorGUILayout.PropertyField(serializedObject.FindProperty("shakeOffsetFadeIn"), new GUIContent("Shake Offset")); EditorGUILayout.PropertyField(serializedObject.FindProperty("shakeFrequencyFadeIn"), new GUIContent("Shake Frequency")); break; // Fade Out case ("Offset Out"): EditorGUILayout.PropertyField(serializedObject.FindProperty("offsetFadeOut"), new GUIContent("Offset")); break; case ("Scale Out"): EditorGUILayout.PropertyField(serializedObject.FindProperty("scaleFadeOut"), new GUIContent("Scale")); break; case ("Cross Scale Out"): EditorGUILayout.PropertyField(serializedObject.FindProperty("crossScaleFadeOut"), new GUIContent("Cross Scale")); break; case ("Shake Out"): EditorGUILayout.PropertyField(serializedObject.FindProperty("shakeOffsetFadeOut"), new GUIContent("Shake Offset")); EditorGUILayout.PropertyField(serializedObject.FindProperty("shakeFrequencyFadeOut"), new GUIContent("Shake Frequency")); break; // Rotation & Scale case ("Start Rotation"): EditorGUILayout.PropertyField(serializedObject.FindProperty("minRotation")); EditorGUILayout.PropertyField(serializedObject.FindProperty("maxRotation")); EditorGUILayout.PropertyField(serializedObject.FindProperty("rotationRandomFlip"), new GUIContent("Random Flip", "Randomly flips the Rotation.\nUseful for avoiding small rotations.\nSet Min and Max to a positive value.")); break; case ("Rotate Over Time"): EditorGUILayout.PropertyField(serializedObject.FindProperty("minRotationSpeed")); EditorGUILayout.PropertyField(serializedObject.FindProperty("maxRotationSpeed")); EditorGUILayout.PropertyField(serializedObject.FindProperty("rotationSpeedRandomFlip"), new GUIContent("Random Flip", "Randomly flips the Rotation Speed.\nUseful for avoiding small rotation speeds.\nSet Min and Max to a positive value.")); SerializedProperty rotateOverTimeProperty = serializedObject.FindProperty("rotateOverTime"); Color rotateOverTimeColor = Color.Lerp(Color.red, Color.green, rotateOverTimeProperty.animationCurveValue.Evaluate(1)); EditorGUILayout.CurveField(rotateOverTimeProperty, rotateOverTimeColor, new Rect(0, 0, 1, 1)); break; case ("Scale By Number"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("scaleByNumberSettings")); EditorGUILayout.EndHorizontal(); break; case ("Scale Over Time"): SerializedProperty scaleOverTimeProperty = serializedObject.FindProperty("scaleOverTime"); Color scaleOverTimeColor = Color.Lerp(Color.red, Color.green, scaleOverTimeProperty.animationCurveValue.Evaluate(1)); EditorGUILayout.CurveField(scaleOverTimeProperty, scaleOverTimeColor, new Rect(0, 0, 1, 5f)); break; case ("Orthographic Scaling"): EditorGUILayout.PropertyField(serializedObject.FindProperty("defaultOrthographicSize")); EditorGUILayout.PropertyField(serializedObject.FindProperty("maxOrthographicSize")); EditorGUILayout.PropertyField(serializedObject.FindProperty("orthographicCamera")); bool noOrthographicCameraOverride = true; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { if (dn.orthographicCamera != null) { noOrthographicCameraOverride = false; break; } } if (noOrthographicCameraOverride) { string overlayString = "Main Camera"; if (DNPEditorInternal.currentWidth < 404) { overlayString = "Main Camera"; if (DNPEditorInternal.currentWidth < 389) { overlayString = ""; } } if (DNPEditorInternal.currentWidth > 293) { PropertyOverlay(DNPEditorInternal.CheckmarkString(true) + " " + overlayString + " "); } } else { GUI.color = new Color(1, 1, 1, 0.7f); DNPEditorInternal.ScalingLabel("Only required if your main camera is not the orthographic camera.", 362); GUI.color = Color.white; } break; // Spam Control case ("Combination"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(" ", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("combinationSettings")); EditorGUILayout.EndHorizontal(); break; case ("Destruction"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(" ", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("destructionSettings")); EditorGUILayout.EndHorizontal(); break; case ("Collision"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(" ", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("collisionSettings")); EditorGUILayout.EndHorizontal(); break; case ("Push"): EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField(" ", GUILayout.Width(9)); EditorGUILayout.PropertyField(serializedObject.FindProperty("pushSettings")); EditorGUILayout.EndHorizontal(); break; // Performance case ("Pooling"): EditorGUILayout.PropertyField(serializedObject.FindProperty("poolSize")); EditorGUILayout.PropertyField(serializedObject.FindProperty("disableOnSceneLoad")); break; } } // Close Box DNPEditorInternal.CloseBox(showProperties); } void HandleTextProperty(SerializedProperty textField) { EditorGUI.BeginChangeCheck(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(textField); if (textField.stringValue.Length > 5) { char[] chars = textField.stringValue.ToCharArray(); bool unicodeCheck = false; int unicodeIndex = 0; for (int i = 0; i < chars.Length; i++) { char c = chars[i]; if (c == '\\') { // Check if there is a unicode sequence unicodeCheck = true; unicodeIndex = i; } else { if (unicodeCheck) { if (i == unicodeIndex + 1) { if (char.ToLower(c) != 'u') { unicodeCheck = false; } } else if (i < unicodeIndex + 6) { int cInt = (int)c; if (!char.IsNumber(c) && !(cInt > 96 && cInt < 103)) { unicodeCheck = false; } } } } } if(unicodeCheck && unicodeIndex < chars.Length - 5) { if(GUILayout.Button("Unicode", GUILayout.Width(60))) { // Get hex code string unicodeHex = ""; for (int i = unicodeIndex + 2; i < unicodeIndex + 6; i++) { unicodeHex += chars[i]; } int hexCode = int.Parse(unicodeHex, System.Globalization.NumberStyles.HexNumber); // Get unicode string unicode = char.ConvertFromUtf32(hexCode); // Combine string newString = ""; for(int i = 0; i < unicodeIndex; i++) { newString += chars[i]; } newString += unicode; for (int i = unicodeIndex + 6; i < chars.Length; i++) { newString += chars[i]; } // Assign textField.stringValue = newString; } } } EditorGUILayout.EndHorizontal(); } public static void ChangeShaderToOverlay(DamageNumber damageNumber) { damageNumber.GetReferencesIfNecessary(); Material[] materials = damageNumber.GetSharedMaterials(); if (materials != null) { foreach (Material mat in materials) { if (!mat.shader.name.EndsWith("verlay")) { Shader shader = Shader.Find(mat.shader.name + " Overlay"); if (shader == null) { shader = Shader.Find("TextMeshPro/Distance Field - Overlay"); } if (shader == null) { shader = Shader.Find("TextMeshPro/Distance Field (Overlay)"); } if (shader == null) { shader = Shader.Find("TextMeshPro/Distance Field Overlay"); } mat.shader = shader; damageNumber.renderThroughWalls = false; } } } } bool FeatureButton(SerializedProperty property, string featureTitle) { // Get name for toggle button string buttonName = property.hasMultipleDifferentValues ? "− − −" : (property.boolValue ? " " + featureTitle + "" : featureTitle); bool toggled = GUILayout.Button(buttonName, DNPEditorInternal.buttonStyle, GUILayout.Width(140)); if (toggled) { // Record changes List objectsList = new List(); foreach(Object targetObject in targets) { objectsList.Add(targetObject); } foreach (DamageNumber damageNumber in DNPEditorInternal.damageNumbers) { if(damageNumber != null) { damageNumber.GetReferencesIfNecessary(); foreach (TMP_Text tmpText in damageNumber.GetTextMeshs()) { if(tmpText != null) { objectsList.Add(tmpText); } } } } Object[] objectsArray = new Object[objectsList.Count]; for(int i = 0; i < objectsList.Count; i++) { objectsArray[i] = objectsList[i]; } Undo.RecordObjects(objectsArray, "Toggled " + featureTitle); // Toggle feature property.boolValue = !property.boolValue; // Avoid Conflicts if(property.boolValue) { switch (property.name) { case ("enableDestruction"): serializedObject.FindProperty("enableCombination").boolValue = false; break; case ("enableCombination"): serializedObject.FindProperty("enableDestruction").boolValue = false; break; } } } if (property.boolValue || property.hasMultipleDifferentValues) { GUI.color = new Color(1, 1, 1, 0.8f); GUI.Toolbar(GUILayoutUtility.GetLastRect(), 0, new string[] { buttonName }, DNPEditorInternal.buttonStyle); GUI.color = new Color(1, 1, 1, 1f); return true; } return false; } void DisplayTextMain(bool isMesh) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(); bool editingPrefabPreview = DNPEditorInternal.EditingPrefabPreview(target); if (editingPrefabPreview) { GUI.enabled = false; } // Font bool mixedFontAssets = false; TMP_FontAsset fontAsset = null; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { dn.GetReferencesIfNecessary(); if(isMesh) { TMP_Text tmp = dn.GetTextMesh(); if (fontAsset != null && tmp.font != null && tmp.font != fontAsset) { mixedFontAssets = true; } else { fontAsset = tmp.font; } } else { foreach (TMP_Text tmp in dn.GetTextMeshs()) { if (fontAsset != null && tmp.font != null && tmp.font != fontAsset) { mixedFontAssets = true; } else { fontAsset = tmp.font; } } } } EditorGUI.showMixedValue = mixedFontAssets; EditorGUI.BeginChangeCheck(); TMP_FontAsset newFontAsset = (TMP_FontAsset) EditorGUILayout.ObjectField(new GUIContent("Font", "The font used by text mesh pro."), fontAsset, typeof(TMP_FontAsset), false); if(EditorGUI.EndChangeCheck()) { foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { Undo.RecordObjects(dn.GetTextMeshs(), "Changed font."); foreach (TMP_Text tmp in dn.GetTextMeshs()) { tmp.font = newFontAsset; } } DNPEditorInternal.ResetMaterials(); } EditorGUI.showMixedValue = false; // Color bool mixedColor = false; Color vertexColor = Color.white; bool firstColor = true; foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { foreach (TMP_Text tmp in dn.GetTextMeshs()) { if (firstColor) { firstColor = false; vertexColor = tmp.color; } else { if (vertexColor != tmp.color) { mixedColor = true; } } } } EditorGUI.showMixedValue = mixedColor; EditorGUI.BeginChangeCheck(); Color newColor = EditorGUILayout.ColorField(new GUIContent("Color", "The vertex color used by text mesh pro."), vertexColor); if (EditorGUI.EndChangeCheck()) { foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { Undo.RecordObjects(dn.GetTextMeshs(), "Changed color."); foreach (TMP_Text tmp in dn.GetTextMeshs()) { tmp.color = newColor; } } } GUI.enabled = true; // Info DNPEditorInternal.Lines(); GUI.color = new Color(1, 1, 1, 0.7f); if (editingPrefabPreview) { DNPEditorInternal.ScalingLabel("You need to open the prefab to access these settings.", 355); DNPEditorInternal.OpenPrefabButton(target); } else { DNPEditorInternal.ScalingLabel("Check out the TextMeshPro component for more settings.", 355); GUI.color = Color.white; } DNPEditorInternal.CloseBox(); } void DisplayMainSettings() { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(); SerializedProperty permanentProperty = serializedObject.FindProperty("permanent"); GUI.enabled = !permanentProperty.boolValue || permanentProperty.hasMultipleDifferentValues; EditorGUILayout.BeginHorizontal(); SerializedProperty lifetimeProperty = serializedObject.FindProperty("lifetime"); EditorGUILayout.PropertyField(lifetimeProperty); bool notEnoughLifetime = false; foreach(DamageNumber dn in DNPEditorInternal.damageNumbers) { if(dn.lifetime < dn.durationFadeIn) { notEnoughLifetime = true; break; } } if (notEnoughLifetime) { PropertyOverlay("Not enough time to fade in."); } else { TimePropertyOverlay(lifetimeProperty.floatValue); } ResetButton("Lifetime"); EditorGUILayout.EndHorizontal(); GUI.enabled = true; EditorGUILayout.BeginHorizontal(); SerializedProperty timescaleProperty = serializedObject.FindProperty("unscaledTime"); EditorGUILayout.PropertyField(timescaleProperty); ResetButton("UnscaledTime"); EditorGUILayout.EndHorizontal(); GUI.enabled = true; EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(permanentProperty); ResetButton("Permanent"); EditorGUILayout.EndHorizontal(); // Information DNPEditorInternal.Lines(); GUI.color = new Color(1, 1, 1, 0.7f); if (permanentProperty.boolValue) { DNPEditorInternal.Label("- Will not fade out on it's own."); } else { DNPEditorInternal.Label("- Will fade out after " + (Mathf.Round(lifetimeProperty.floatValue * 10) * 0.1f) + " seconds."); } GUI.color = Color.white; DNPEditorInternal.CloseBox(); } void DisplayFadeMain(string inOrOut) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(); EditorGUILayout.BeginHorizontal(); SerializedProperty serializedProperty = serializedObject.FindProperty("durationFade" + inOrOut); EditorGUILayout.PropertyField(serializedProperty, new GUIContent("Duration", "The duration it takes to fade " + inOrOut.ToLower() + ".")); TimePropertyOverlay(serializedProperty.floatValue); ResetButton("Fade " + inOrOut + " Main"); EditorGUILayout.EndHorizontal(); DNPEditorInternal.CloseBox(); } void DisplaySpamControlMain(bool isMesh) { EditorGUILayout.Space(2); // Check if Spam Group is required bool requiresSpamGroup = false; bool hasSpamGroup = false; SerializedProperty serializedProperty = serializedObject.FindProperty("spamGroup"); SerializedProperty combinationProperty = serializedObject.FindProperty("enableCombination"); SerializedProperty destructionProperty = serializedObject.FindProperty("enableDestruction"); SerializedProperty collisionProperty = serializedObject.FindProperty("enableCollision"); SerializedProperty pushProperty = serializedObject.FindProperty("enablePush"); if (combinationProperty.boolValue || combinationProperty.hasMultipleDifferentValues) { requiresSpamGroup = true; } if (destructionProperty.boolValue || destructionProperty.hasMultipleDifferentValues) { requiresSpamGroup = true; } if (collisionProperty.boolValue || collisionProperty.hasMultipleDifferentValues) { requiresSpamGroup = true; } if (pushProperty.boolValue || pushProperty.hasMultipleDifferentValues) { requiresSpamGroup = true; } if (requiresSpamGroup && serializedProperty.stringValue.Replace(" ", "") != "") { requiresSpamGroup = false; hasSpamGroup = true; } DNPEditorInternal.StartBox(requiresSpamGroup ? new Color(1, 1f, 0.8f) : Color.white); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(serializedProperty); if(requiresSpamGroup) { PropertyOverlay("Required"); } ResetButton("Spam Control Main"); EditorGUILayout.EndHorizontal(); if (requiresSpamGroup) { DNPEditorInternal.Lines(); GUI.color = new Color(1, 1, 1, 0.7f); DNPEditorInternal.ScalingLabel("This field is required by the features below.",272); } else if(hasSpamGroup) { DNPEditorInternal.Lines(); GUI.color = new Color(1, 1, 1, 0.7f); if(isMesh) { DNPEditorInternal.ScalingLabel("Damage numbers within the same group interact with each other.", 395); } else { DNPEditorInternal.ScalingLabel("Damage numbers with the same group & parent interact with each other.", 440); } } DNPEditorInternal.CloseBox(requiresSpamGroup ? new Color(1, 1f, 0.7f) : Color.white); } int TextPosition(int current) { // Change Position EditorGUILayout.BeginHorizontal(); GUI.color = new Color(1, 1, 1, 0.7f); GUI.color = Color.white; int swapWith = GUILayout.Toolbar(current, new GUIContent[] { new GUIContent("←", "Move this text to the left."), new GUIContent("→", "Move this text to the right."), new GUIContent("↑", "Move this text to the top."), new GUIContent("↓", "Move this text to the bottom.") }, GUILayout.Width(DNPEditorInternal.currentWidth > 330 ? 90 : 0)); GUI.color = new Color(1, 1, 1, 0.7f); GUILayout.Label(" | ", DNPEditorInternal.centerTextStyle, GUILayout.Width(10), GUILayout.Height(18)); GUI.color = Color.white; EditorGUILayout.EndHorizontal(); return swapWith; } void DisplayPerformanceMain() { EditorGUILayout.Space(4); // Delays DNPEditorInternal.StartBox(); EditorGUILayout.BeginHorizontal(); DisplayDelay("updateDelay", "Update Delay", "The delay between updates.\nGreatly affects performance."); ResetButton("Update Delay"); EditorGUILayout.EndHorizontal(); DNPEditorInternal.CloseBox(); } void DisplayPerformanceHints() { EditorGUILayout.Space(4); DNPEditorInternal.StartBox(); GUI.color = new Color(1, 1, 1, 0.7f); DNPEditorInternal.Label("Performance Hints:"); EditorGUILayout.Space(5); DNPEditorInternal.ScalingLabel("Always make sure to enable Pooling.", 1); DNPEditorInternal.ScalingLabel("You can also decrease the Update FPS.", 261); DNPEditorInternal.ScalingLabel("Enabling Combination and Destruction also boosts performance.", 398); DNPEditorInternal.ScalingLabel("You can find those features in the Spam Control section.", 350); GUI.color = Color.white; DNPEditorInternal.CloseBox(); } void DisplayMovementHints(bool isMesh) { if(!isMesh) { EditorGUILayout.Space(4); DNPEditorInternal.StartBox(); GUI.color = new Color(1, 1, 1, 0.7f); DNPEditorInternal.Label("GUI Hints:"); EditorGUILayout.Space(5); DNPEditorInternal.ScalingLabel("The GUI version handles movement in anchored position.", 363); DNPEditorInternal.ScalingLabel("An offset or velocity of 1 equals 100 in anchored space.",352f); DNPEditorInternal.ScalingLabel("This x100 conversion is for keeping values small and consistent.",399f); GUI.color = Color.white; DNPEditorInternal.CloseBox(); } } void DisplaySpamControlHints(bool isMesh) { if (!isMesh) { EditorGUILayout.Space(4); DNPEditorInternal.StartBox(); GUI.color = new Color(1, 1, 1, 0.7f); DNPEditorInternal.Label("GUI Hints:"); EditorGUILayout.Space(5); DNPEditorInternal.ScalingLabel("The GUI version handles everything in anchored position.", 363); DNPEditorInternal.ScalingLabel("A distance or radius of 1 equals 100 in anchored space.", 358f); DNPEditorInternal.ScalingLabel("This x100 conversion is for keeping values small and consistent.", 399f); GUI.color = Color.white; DNPEditorInternal.CloseBox(); } } void DisplayDelay(string propertyName, string displayName, string displayTooltip) { // Property SerializedProperty property = serializedObject.FindProperty(propertyName); // Delay EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(property, new GUIContent(displayName, displayTooltip)); // Delay Overlay string overlayContent; if (property.hasMultipleDifferentValues) { overlayContent = ""; } else { if (property.floatValue > 0) { if(DNPEditorInternal.currentWidth < 400f) { overlayContent = "s"; } else { overlayContent = "Delay"; } } else { overlayContent = "No Delay"; } } PropertyOverlay(overlayContent); GUI.color = new Color(1, 1, 1, 0.5f); EditorGUILayout.LabelField("➜", DNPEditorInternal.centerTextStyle, GUILayout.Width(DNPEditorInternal.currentWidth > 334 ? 15 : 0)); GUI.color = Color.white; if (property.hasMultipleDifferentValues) { GUI.enabled = false; GUILayout.TextField(" - - - ", GUILayout.Width(100)); GUI.enabled = true; } else { if(property.floatValue > 0.10001f) { GUI.color = new Color(1f, 1f, 0.7f, 1f); } int currentFPS = property.floatValue > 0 ? Mathf.RoundToInt(1f / property.floatValue) : 0; int fpsWidth = 90; if(DNPEditorInternal.currentWidth < 400) { fpsWidth = (int) Mathf.Clamp(DNPEditorInternal.currentWidth - 300,50,90); } int newFPS = EditorGUILayout.IntField(currentFPS, GUILayout.Width(DNPEditorInternal.currentWidth > 294 ? fpsWidth : 0)); if (currentFPS != newFPS) { if (newFPS > 0) { property.floatValue = Mathf.Round(100000f / (float)newFPS) * 0.00001f; } else if (newFPS <= 0) { property.floatValue = 0f; } } } EditorGUILayout.EndHorizontal(); // FPS Overlay GUI.color = new Color(1, 1, 1, 0.7f); if(property.hasMultipleDifferentValues) { overlayContent = ""; } else { if(property.floatValue > 0) { overlayContent = "FPS"; } else { if(DNPEditorInternal.currentWidth < 400) { overlayContent = ""; } else { overlayContent = "Every Frame"; } } } PropertyOverlay(DNPEditorInternal.currentWidth > 310 ? overlayContent : ""); } void ResetButton(string category) { GUIContent resetButton = new GUIContent(); resetButton.text = "R"; resetButton.tooltip = "Reset this feature."; if (GUILayout.Button(resetButton, GUILayout.Width(21))) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; ResetCategory(category); } } void ResetCategory(string category) { Undo.RecordObject(target, "Reset " + category + " settings."); foreach (DamageNumber dn in DNPEditorInternal.damageNumbers) { // Reset Feature switch (category) { // Main case ("Lifetime"): dn.lifetime = 2f; break; case ("Permanent"): dn.permanent = false; break; case ("UnscaledTime"): dn.unscaledTime = false; break; case ("3D Game"): dn.faceCameraView = true; dn.renderThroughWalls = true; dn.consistentScreenSize = false; dn.distanceScalingSettings = new DistanceScalingSettings(0); dn.cameraOverride = null; break; // Text Content case ("Number"): dn.number = 1; dn.numberSettings = new TextSettings(0); dn.digitSettings = new DigitSettings(0); break; case ("Left Text"): dn.leftText = ""; dn.leftTextSettings = new TextSettings(0f); break; case ("Right Text"): dn.rightText = ""; dn.rightTextSettings = new TextSettings(0f); break; case ("Top Text"): dn.topText = ""; dn.topTextSettings = new TextSettings(0f); break; case ("Bottom Text"): dn.bottomText = ""; dn.bottomTextSettings = new TextSettings(0f); break; case ("Color By Number"): dn.colorByNumberSettings = new ColorByNumberSettings(0f); break; // Movement case ("Lerp"): dn.lerpSettings = new LerpSettings(0); break; case ("Velocity"): dn.velocitySettings = new VelocitySettings(0); break; case ("Shaking"): dn.shakeSettings = new ShakeSettings(new Vector2(0.005f, 0.005f)); break; case ("Following"): dn.followedTarget = null; dn.followSettings = new FollowSettings(0); break; // Fade In case ("Fade In Main"): dn.durationFadeIn = 0.2f; break; case ("Offset In"): dn.offsetFadeIn = new Vector2(0.5f, 0); break; case ("Scale In"): dn.scaleFadeIn = new Vector2(2f, 2f); break; case ("Shake In"): dn.shakeOffsetFadeIn = new Vector2(0f, 1.5f); dn.shakeFrequencyFadeIn = 4f; break; case ("Cross Scale In"): dn.crossScaleFadeIn = new Vector2(1f, 1.5f); break; // Fade Out case ("Fade Out Main"): dn.durationFadeOut = 0.2f; break; case ("Offset Out"): dn.enableOffsetFadeOut = true; dn.offsetFadeOut = new Vector2(0.5f, 0); break; case ("Scale Out"): dn.scaleFadeOut = new Vector2(2f, 2f); break; case ("Shake Out"): dn.shakeOffsetFadeOut = new Vector2(0f, 1.5f); dn.shakeFrequencyFadeOut = 4f; break; case ("Cross Scale Out"): dn.crossScaleFadeOut = new Vector2(1f, 1.5f); break; // Rotation & Scale case ("Start Rotation"): dn.minRotation = -4; dn.maxRotation = 4; break; case ("Rotate Over Time"): dn.minRotationSpeed = -15f; dn.maxRotationSpeed = 15; dn.rotateOverTime = new AnimationCurve(new Keyframe[] { new Keyframe(0, 1), new Keyframe(0.4f, 1), new Keyframe(0.8f, 0), new Keyframe(1, 0) }); break; case ("Scale By Number"): dn.scaleByNumberSettings = new ScaleByNumberSettings(0); break; case ("Scale Over Time"): dn.scaleOverTime = new AnimationCurve(new Keyframe(0, 1), new Keyframe(1, 0.7f)); break; case ("Orthographic Scaling"): dn.defaultOrthographicSize = 5f; dn.maxOrthographicSize = 1.5f; dn.orthographicCamera = null; break; // Spam Control case ("Spam Control Main"): dn.spamGroup = ""; break; case ("Combination"): dn.combinationSettings = new CombinationSettings(0); break; case ("Destruction"): dn.destructionSettings = new DestructionSettings(0); break; case ("Collision"): dn.collisionSettings = new CollisionSettings(0); break; case ("Push"): dn.pushSettings = new PushSettings(0); break; // Performance case ("Pooling"): dn.poolSize = 50; break; case ("Update Delay"): dn.updateDelay = 0.0125f; break; } } } void TimePropertyOverlay(float seconds, string zeroString = "Instantly") { if(seconds > 0) { PropertyOverlay("Seconds"); } else { PropertyOverlay(zeroString); } } void PropertyOverlay(string text) { GUI.color = new Color(1, 1, 1, 0.7f); GUI.Label(GUILayoutUtility.GetLastRect(), text + " ", DNPEditorInternal.rightTextStyle); GUI.color = Color.white; } #endregion } } #endif