#if UNITY_EDITOR using System.Collections.Generic; using System.Globalization; using DamageNumbersPro.Internal; using TMPro; using UnityEditor; using UnityEditorInternal; using UnityEngine; using UnityEngine.Rendering; namespace DamageNumbersPro { [CustomEditor(typeof(DamageNumber), true)] [CanEditMultipleObjects] public class DamageNumberEditor : Editor { public static string version = "4.51"; private void OnEnable() { DNPEditorInternal.PrepareInspector(this); } public override void OnInspectorGUI() { // For some operations var 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 (var dn in DNPEditorInternal.damageNumbers) FixAllVariables(dn); // Apply Properties serializedObject.ApplyModifiedProperties(); // Update Text if (!Application.isPlaying) foreach (var 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 Warnings private void WarningCheck(bool isMesh) { // 3D Game and no 3D enabled var gameIs3DWarning = false; if (isMesh) { var camera = Camera.main; if (camera != null) if (!camera.orthographic) foreach (var 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) foreach (var 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 var runtimePoolingWarning = false; if (Application.isPlaying) foreach (var 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 var scaleByNumbersWarning = false; foreach (var 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 var colorByNumbersWarning = false; foreach (var 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 var collisionWarning = false; foreach (var 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 var pushWarning = false; foreach (var 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 Editor Menus [MenuItem("GameObject/Damage Numbers Pro/Damage Number (Mesh)", priority = 1)] public static void CreateDamageNumberMesh(MenuCommand menuCommand) { // Create GameObject var 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 var 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 var 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 var 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 (var selected in Selection.gameObjects) { var oldComponent = selected.GetComponent(); Undo.RecordObject(oldComponent.gameObject, "Switched " + oldComponent.name); if (oldComponent != null) { // Get TMP Settings var fontAsset = oldComponent.GetFontMaterial(); var tmpColor = oldComponent.GetTextMesh().color; var colorGradient = oldComponent.GetTextMesh().colorGradient; var enableGradient = oldComponent.GetTextMesh().enableVertexGradient; // Clear Children while (oldComponent.transform.childCount > 0) DestroyImmediate(oldComponent.transform.GetChild(0).gameObject); // Add GUI Component var newComponent = oldComponent.gameObject.AddComponent(); ComponentUtility.MoveComponentUp(newComponent); ComponentUtility.MoveComponentUp(newComponent); ComponentUtility.MoveComponentUp(newComponent); ComponentUtility.MoveComponentUp(newComponent); ComponentUtility.MoveComponentUp(newComponent); DNPEditorInternal.PrepareGUIStructure(selected); // TMP Settings newComponent.SetFontMaterial(fontAsset); foreach (var tmp in newComponent.GetTextMeshs()) { tmp.color = tmpColor; tmp.enableVertexGradient = enableGradient; tmp.colorGradient = colorGradient; } // Settings foreach (var propA in oldComponent.GetType().GetFields()) { var 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 (var selected in Selection.gameObjects) { var previousComponent = selected.GetComponent(); Undo.RecordObject(previousComponent.gameObject, "Switched " + previousComponent.name); if (previousComponent != null) { // Get TMP Settings var fontAsset = previousComponent.GetFontMaterial(); var tmpColor = previousComponent.GetTextMesh().color; var colorGradient = previousComponent.GetTextMesh().colorGradient; var enableGradient = previousComponent.GetTextMesh().enableVertexGradient; // Clear Children while (previousComponent.transform.childCount > 0) DestroyImmediate(previousComponent.transform.GetChild(0).gameObject); // Add GUI Component var newComponent = previousComponent.gameObject.AddComponent(); ComponentUtility.MoveComponentUp(newComponent); ComponentUtility.MoveComponentUp(newComponent); ComponentUtility.MoveComponentUp(newComponent); ComponentUtility.MoveComponentUp(newComponent); ComponentUtility.MoveComponentUp(newComponent); DNPEditorInternal.PrepareMeshStructure(selected); // TMP Settings newComponent.SetFontMaterial(fontAsset); foreach (var tmp in newComponent.GetTextMeshs()) { tmp.color = tmpColor; tmp.enableVertexGradient = enableGradient; tmp.colorGradient = colorGradient; } // Settings foreach (var propA in previousComponent.GetType().GetFields()) { var 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); var rectComponent = selected.GetComponent(); if (rectComponent != null) Debug.Log("Please rightclick on the RectTransform component and select 'Remove Component'."); } } } #endregion #region Fixing Variables private 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 var font = dn.GetFontMaterial(); var is3D = dn.enable3DGame ? "3D" : ""; if (dn.enable3DGame && dn.IsMesh() && font != null && font.name + is3D != dn.editorLastFont) { // Cache last font to only check once dn.editorLastFont = font.name + is3D; // Check if font is from the asset var path = AssetDatabase.GetAssetPath(font); if (path != null && path.Contains("DamageNumbers")) { // Undo record var objects = new Object[3]; objects[0] = dn; objects[1] = font; objects[2] = font.material; Undo.RecordObjects(objects, "Swiched shader to distance field overlay."); // Fixing the text shader if (GraphicsSettings.currentRenderPipeline != null) { var pipeline = GraphicsSettings.currentRenderPipeline.GetType().ToString(); if (pipeline.Contains("High") || pipeline.Contains("HD")) { } else { ChangeShaderToOverlay(dn); } } else { ChangeShaderToOverlay(dn); } // Fixing the sprite shader var tmp = dn.GetTextMesh(); if (tmp.spriteAsset != null && tmp.spriteAsset.material != null) { // Sprite Shader if (tmp.spriteAsset.material.shader.name != "TextMeshPro/Sprite Overlay") { var 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") { var spriteOverlay = Shader.Find("TextMeshPro/Sprite Overlay"); if (spriteOverlay != null) TMP_Settings.defaultSpriteAsset.material.shader = spriteOverlay; } } } } } private TextSettings FixTextSettings(TextSettings ts) { ts.horizontal = Mathf.Max(0, ts.horizontal); return ts; } #endregion #region Properties private 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 var toggleProperty = serializedObject.FindProperty(togglePropertyName); // Start Box DNPEditorInternal.StartBox(toggleProperty.hasMultipleDifferentValues || toggleProperty.boolValue); // Top EditorGUILayout.BeginHorizontal(); var showProperties = FeatureButton(toggleProperty, displayedTitle); EditorGUILayout.LabelField("", GUILayout.MinWidth(0)); // Extra Buttons #region Text Position if (showProperties) switch (togglePropertyName) { case "enableLeftText": var leftTextPosition = TextPosition(0); if (leftTextPosition != 0) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; // Unselect Fields foreach (var dn in DNPEditorInternal.damageNumbers) { var originalTextEnabled = dn.enableLeftText; var originalTextString = dn.leftText; var 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": var rightTextPosition = TextPosition(1); if (rightTextPosition != 1) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; // Unselect Fields foreach (var dn in DNPEditorInternal.damageNumbers) { var originalTextEnabled = dn.enableRightText; var originalTextString = dn.rightText; var 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": var topTextPosition = TextPosition(2); if (topTextPosition != 2) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; // Unselect Fields foreach (var dn in DNPEditorInternal.damageNumbers) { var originalTextEnabled = dn.enableTopText; var originalTextString = dn.topText; var 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": var bottomTextPosition = TextPosition(3); if (bottomTextPosition != 3) { EditorGUIUtility.keyboardControl = EditorGUIUtility.hotControl = 0; // Unselect Fields foreach (var dn in DNPEditorInternal.damageNumbers) { var originalTextEnabled = dn.enableBottomText; var originalTextString = dn.bottomText; var 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); var 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": var faceCameraView = serializedObject.FindProperty("faceCameraView"); EditorGUILayout.PropertyField(faceCameraView); if (faceCameraView.boolValue || faceCameraView.hasMultipleDifferentValues) { var 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 var hasOverlayMaterials = false; var hasBadMaterials = false; foreach (var dn in DNPEditorInternal.damageNumbers) { dn.GetReferencesIfNecessary(); var materials = dn.GetSharedMaterials(); if (materials != null) foreach (var mat in materials) if (mat != null && mat.shader.name.EndsWith("verlay")) hasOverlayMaterials = true; else hasBadMaterials = true; } if (hasOverlayMaterials && !hasBadMaterials) GUI.enabled = false; var 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 overlay shader.", 330); DNPEditorInternal.ScalingLabel( "Keep in mind that the shader does not support UI masking though.", 410); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); DNPEditorInternal.ScalingLabel("Go to the material tab or use the button.", 333); GUI.color = Color.white; var buttonPressed = false; if (DNPEditorInternal.currentWidth < 283) buttonPressed = GUILayout.Button("Try"); else buttonPressed = GUILayout.Button("Try Shader"); if (buttonPressed) foreach (var dn in DNPEditorInternal.damageNumbers) ChangeShaderToOverlay(dn); EditorGUILayout.EndHorizontal(); } DNPEditorInternal.Lines(); var 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(); var scaleWithFOV = serializedObject.FindProperty("scaleWithFov"); EditorGUILayout.PropertyField(scaleWithFOV); if (scaleWithFOV.boolValue || scaleWithFOV.hasMultipleDifferentValues) { EditorGUILayout.PropertyField(serializedObject.FindProperty("defaultFov")); EditorGUILayout.PropertyField(serializedObject.FindProperty("fovCamera")); var noFovCameraOverride = true; foreach (var dn in DNPEditorInternal.damageNumbers) if (dn.fovCamera != null) { noFovCameraOverride = false; break; } if (noFovCameraOverride) { var 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")); var noCameraOverride = true; foreach (var dn in DNPEditorInternal.damageNumbers) if (dn.cameraOverride != null) { noCameraOverride = false; break; } if (noCameraOverride) { var 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.")); var rotateOverTimeProperty = serializedObject.FindProperty("rotateOverTime"); var 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": var scaleOverTimeProperty = serializedObject.FindProperty("scaleOverTime"); var 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")); var noOrthographicCameraOverride = true; foreach (var dn in DNPEditorInternal.damageNumbers) if (dn.orthographicCamera != null) { noOrthographicCameraOverride = false; break; } if (noOrthographicCameraOverride) { var 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); } private void HandleTextProperty(SerializedProperty textField) { EditorGUI.BeginChangeCheck(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.PropertyField(textField); if (textField.stringValue.Length > 5) { var chars = textField.stringValue.ToCharArray(); var unicodeCheck = false; var unicodeIndex = 0; for (var i = 0; i < chars.Length; i++) { var 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) { var 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 var unicodeHex = ""; for (var i = unicodeIndex + 2; i < unicodeIndex + 6; i++) unicodeHex += chars[i]; var hexCode = int.Parse(unicodeHex, NumberStyles.HexNumber); // Get unicode var unicode = char.ConvertFromUtf32(hexCode); // Combine var newString = ""; for (var i = 0; i < unicodeIndex; i++) newString += chars[i]; newString += unicode; for (var i = unicodeIndex + 6; i < chars.Length; i++) newString += chars[i]; // Assign textField.stringValue = newString; } } EditorGUILayout.EndHorizontal(); } public static void ChangeShaderToOverlay(DamageNumber damageNumber) { damageNumber.GetReferencesIfNecessary(); var materials = damageNumber.GetSharedMaterials(); if (materials != null) foreach (var mat in materials) if (!mat.shader.name.EndsWith("verlay")) { var 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; } } private bool FeatureButton(SerializedProperty property, string featureTitle) { // Get name for toggle button var buttonName = property.hasMultipleDifferentValues ? "− − −" : property.boolValue ? " " + featureTitle + "" : featureTitle; var toggled = GUILayout.Button(buttonName, DNPEditorInternal.buttonStyle, GUILayout.Width(140)); if (toggled) { // Record changes var objectsList = new List(); foreach (var targetObject in targets) objectsList.Add(targetObject); foreach (var damageNumber in DNPEditorInternal.damageNumbers) if (damageNumber != null) { damageNumber.GetReferencesIfNecessary(); foreach (var tmpText in damageNumber.GetTextMeshs()) if (tmpText != null) objectsList.Add(tmpText); } var objectsArray = new Object[objectsList.Count]; for (var 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[] { buttonName }, DNPEditorInternal.buttonStyle); GUI.color = new Color(1, 1, 1, 1f); return true; } return false; } private void DisplayTextMain(bool isMesh) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(); var editingPrefabPreview = DNPEditorInternal.EditingPrefabPreview(target); if (editingPrefabPreview) GUI.enabled = false; // Font var mixedFontAssets = false; TMP_FontAsset fontAsset = null; foreach (var dn in DNPEditorInternal.damageNumbers) { dn.GetReferencesIfNecessary(); if (isMesh) { var tmp = dn.GetTextMesh(); if (fontAsset != null && tmp.font != null && tmp.font != fontAsset) mixedFontAssets = true; else fontAsset = tmp.font; } else { foreach (var tmp in dn.GetTextMeshs()) if (fontAsset != null && tmp.font != null && tmp.font != fontAsset) mixedFontAssets = true; else fontAsset = tmp.font; } } EditorGUI.showMixedValue = mixedFontAssets; EditorGUI.BeginChangeCheck(); var newFontAsset = (TMP_FontAsset)EditorGUILayout.ObjectField( new GUIContent("Font", "The font used by text mesh pro."), fontAsset, typeof(TMP_FontAsset), false); if (EditorGUI.EndChangeCheck()) { foreach (var dn in DNPEditorInternal.damageNumbers) { Undo.RecordObjects(dn.GetTextMeshs(), "Changed font."); foreach (var tmp in dn.GetTextMeshs()) tmp.font = newFontAsset; } DNPEditorInternal.ResetMaterials(); } EditorGUI.showMixedValue = false; // Color var mixedColor = false; var vertexColor = Color.white; var firstColor = true; foreach (var dn in DNPEditorInternal.damageNumbers) foreach (var tmp in dn.GetTextMeshs()) if (firstColor) { firstColor = false; vertexColor = tmp.color; } else { if (vertexColor != tmp.color) mixedColor = true; } EditorGUI.showMixedValue = mixedColor; EditorGUI.BeginChangeCheck(); var newColor = EditorGUILayout.ColorField(new GUIContent("Color", "The vertex color used by text mesh pro."), vertexColor); if (EditorGUI.EndChangeCheck()) foreach (var dn in DNPEditorInternal.damageNumbers) { Undo.RecordObjects(dn.GetTextMeshs(), "Changed color."); foreach (var 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(); } private void DisplayMainSettings() { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(); var permanentProperty = serializedObject.FindProperty("permanent"); GUI.enabled = !permanentProperty.boolValue || permanentProperty.hasMultipleDifferentValues; EditorGUILayout.BeginHorizontal(); var lifetimeProperty = serializedObject.FindProperty("lifetime"); EditorGUILayout.PropertyField(lifetimeProperty); var notEnoughLifetime = false; foreach (var 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(); var 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(); } private void DisplayFadeMain(string inOrOut) { EditorGUILayout.Space(2); DNPEditorInternal.StartBox(); EditorGUILayout.BeginHorizontal(); var 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(); } private void DisplaySpamControlMain(bool isMesh) { EditorGUILayout.Space(2); // Check if Spam Group is required var requiresSpamGroup = false; var hasSpamGroup = false; var serializedProperty = serializedObject.FindProperty("spamGroup"); var combinationProperty = serializedObject.FindProperty("enableCombination"); var destructionProperty = serializedObject.FindProperty("enableDestruction"); var collisionProperty = serializedObject.FindProperty("enableCollision"); var 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); } private int TextPosition(int current) { // Change Position EditorGUILayout.BeginHorizontal(); GUI.color = new Color(1, 1, 1, 0.7f); GUI.color = Color.white; var swapWith = GUILayout.Toolbar(current, new[] { 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; } private 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(); } private 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(); } private 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(); } } private 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(); } } private void DisplayDelay(string propertyName, string displayName, string displayTooltip) { // Property var 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); var currentFPS = property.floatValue > 0 ? Mathf.RoundToInt(1f / property.floatValue) : 0; var fpsWidth = 90; if (DNPEditorInternal.currentWidth < 400) fpsWidth = (int)Mathf.Clamp(DNPEditorInternal.currentWidth - 300, 50, 90); var newFPS = EditorGUILayout.IntField(currentFPS, GUILayout.Width(DNPEditorInternal.currentWidth > 294 ? fpsWidth : 0)); if (currentFPS != newFPS) { if (newFPS > 0) property.floatValue = Mathf.Round(100000f / 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 : ""); } private void ResetButton(string category) { var 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); } } private void ResetCategory(string category) { Undo.RecordObject(target, "Reset " + category + " settings."); foreach (var 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(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; } } private void TimePropertyOverlay(float seconds, string zeroString = "Instantly") { if (seconds > 0) PropertyOverlay("Seconds"); else PropertyOverlay(zeroString); } private 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