using UnityEngine; using UnityEngine.Tilemaps; using UnityEditorInternal; using System.Collections.Generic; namespace UnityEditor { /// <summary> /// The Editor for an AdvancedRuleOverrideTileEditor. /// </summary> [CustomEditor(typeof(AdvancedRuleOverrideTile))] public class AdvancedRuleOverrideTileEditor : RuleOverrideTileEditor { private static class Styles { public static readonly GUIContent defaultSprite = EditorGUIUtility.TrTextContent("Default Sprite" , "Overrides the default Sprite for the original Rule Tile."); public static readonly GUIContent defaultGameObject = EditorGUIUtility.TrTextContent("Default GameObject" , "Overrides the default GameObject for the original Rule Tile."); public static readonly GUIContent defaultCollider = EditorGUIUtility.TrTextContent("Default Collider" , "Overrides the default Collider for the original Rule Tile."); } /// <summary> /// The AdvancedRuleOverrideTile being edited. /// </summary> public new AdvancedRuleOverrideTile overrideTile => target as AdvancedRuleOverrideTile; List<KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRuleOutput>> m_Rules = new List<KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRuleOutput>>(); private ReorderableList m_RuleList; private int m_MissingOriginalRuleIndex; private HashSet<int> m_UniqueIds = new HashSet<int>(); static float k_DefaultElementHeight { get { return RuleTileEditor.k_DefaultElementHeight; } } static float k_SingleLineHeight { get { return RuleTileEditor.k_SingleLineHeight; } } /// <summary> /// OnEnable for the AdvancedRuleOverrideTileEditor /// </summary> public override void OnEnable() { if (m_RuleList == null) { m_RuleList = new ReorderableList(m_Rules, typeof(KeyValuePair<RuleTile.TilingRule, RuleTile.TilingRule>), false, true, false, false); m_RuleList.drawHeaderCallback = DrawRulesHeader; m_RuleList.drawElementCallback = DrawRuleElement; m_RuleList.elementHeightCallback = GetRuleElementHeight; } } /// <summary> /// Draws the Inspector GUI for the AdvancedRuleOverrideTileEditor /// </summary> public override void OnInspectorGUI() { serializedObject.UpdateIfRequiredOrScript(); DrawTileField(); EditorGUI.BeginChangeCheck(); overrideTile.m_DefaultSprite = EditorGUILayout.ObjectField(Styles.defaultSprite, overrideTile.m_DefaultSprite, typeof(Sprite), false) as Sprite; overrideTile.m_DefaultGameObject = EditorGUILayout.ObjectField(Styles.defaultGameObject, overrideTile.m_DefaultGameObject, typeof(GameObject), false) as GameObject; overrideTile.m_DefaultColliderType = (Tile.ColliderType)EditorGUILayout.EnumPopup(Styles.defaultCollider, overrideTile.m_DefaultColliderType); if (EditorGUI.EndChangeCheck()) SaveTile(); DrawCustomFields(); if (overrideTile.m_Tile) { ValidateRuleTile(overrideTile.m_Tile); overrideTile.GetOverrides(m_Rules, ref m_MissingOriginalRuleIndex); } m_RuleList.DoLayoutList(); } private void ValidateRuleTile(RuleTile ruleTile) { // Ensure that each Tiling Rule in the RuleTile has a unique ID m_UniqueIds.Clear(); var startId = 0; foreach (var rule in ruleTile.m_TilingRules) { if (m_UniqueIds.Contains(rule.m_Id)) { do { rule.m_Id = startId++; } while (m_UniqueIds.Contains(rule.m_Id)); EditorUtility.SetDirty(ruleTile); } m_UniqueIds.Add(rule.m_Id); startId++; } } /// <summary> /// Draws the Header for the Rule list /// </summary> /// <param name="rect">Rect to draw the header in</param> public void DrawRulesHeader(Rect rect) { GUI.Label(rect, "Tiling Rules", EditorStyles.label); } /// <summary> /// Draws the Rule element for the Rule list /// </summary> /// <param name="rect">Rect to draw the Rule Element in</param> /// <param name="index">Index of the Rule Element to draw</param> /// <param name="active">Whether the Rule Element is active</param> /// <param name="focused">Whether the Rule Element is focused</param> public void DrawRuleElement(Rect rect, int index, bool active, bool focused) { RuleTile.TilingRule originalRule = m_Rules[index].Key; if (originalRule == null) return; RuleTile.TilingRuleOutput overrideRule = m_Rules[index].Value; bool isMissing = index >= m_MissingOriginalRuleIndex; DrawToggleInternal(new Rect(rect.xMin, rect.yMin, 16, rect.height)); DrawRuleInternal(new Rect(rect.xMin + 16, rect.yMin, rect.width - 16, rect.height)); void DrawToggleInternal(Rect r) { EditorGUI.BeginChangeCheck(); bool enabled = EditorGUI.Toggle(new Rect(r.xMin, r.yMin, r.width, k_SingleLineHeight), overrideRule != null); if (EditorGUI.EndChangeCheck()) { if (enabled) overrideTile[originalRule] = originalRule; else overrideTile[originalRule] = null; SaveTile(); } } void DrawRuleInternal(Rect r) { EditorGUI.BeginChangeCheck(); DrawRule(r, overrideRule ?? originalRule, overrideRule != null, originalRule, isMissing); if (EditorGUI.EndChangeCheck()) SaveTile(); } } /// <summary> /// Draw a Rule Override for the AdvancedRuleOverrideTileEditor /// </summary> /// <param name="rect">Rect to draw the Rule in</param> /// <param name="rule">The Rule Override to draw</param> /// <param name="isOverride">Whether the original Rule is being overridden</param> /// <param name="originalRule">Original Rule to override</param> /// <param name="isMissing">Whether the original Rule is missing</param> public void DrawRule(Rect rect, RuleTile.TilingRuleOutput rule, bool isOverride, RuleTile.TilingRule originalRule, bool isMissing) { if (isMissing) { EditorGUI.HelpBox(new Rect(rect.xMin, rect.yMin, rect.width, 16), "Original Tiling Rule missing", MessageType.Warning); rect.yMin += 16; } using (new EditorGUI.DisabledScope(!isOverride)) { float yPos = rect.yMin + 2f; float height = rect.height - k_PaddingBetweenRules; float matrixWidth = k_DefaultElementHeight; BoundsInt ruleBounds = originalRule.GetBounds(); BoundsInt ruleGuiBounds = ruleTileEditor.GetRuleGUIBounds(ruleBounds, originalRule); Vector2 matrixSize = ruleTileEditor.GetMatrixSize(ruleGuiBounds); Vector2 matrixSizeRate = matrixSize / Mathf.Max(matrixSize.x, matrixSize.y); Vector2 matrixRectSize = new Vector2(matrixWidth * matrixSizeRate.x, k_DefaultElementHeight * matrixSizeRate.y); Vector2 matrixRectPosition = new Vector2(rect.xMax - matrixWidth * 2f - 10f, yPos); matrixRectPosition.x += (matrixWidth - matrixRectSize.x) * 0.5f; matrixRectPosition.y += (k_DefaultElementHeight - matrixRectSize.y) * 0.5f; Rect inspectorRect = new Rect(rect.xMin, yPos, rect.width - matrixWidth * 2f - 20f, height); Rect matrixRect = new Rect(matrixRectPosition, matrixRectSize); Rect spriteRect = new Rect(rect.xMax - matrixWidth - 5f, yPos, matrixWidth, k_DefaultElementHeight); ruleTileEditor.RuleInspectorOnGUI(inspectorRect, rule); ruleTileEditor.SpriteOnGUI(spriteRect, rule); if (!isMissing) using (new EditorGUI.DisabledScope(true)) ruleTileEditor.RuleMatrixOnGUI(overrideTile.m_InstanceTile, matrixRect, ruleGuiBounds, originalRule); } } /// <summary> /// Returns the height for an indexed Rule Element /// </summary> /// <param name="index">Index of the Rule Element</param> /// <returns>Height of the indexed Rule Element</returns> public float GetRuleElementHeight(int index) { var originalRule = m_Rules[index].Key; var overrideRule = m_Rules[index].Value; float height = overrideRule != null ? ruleTileEditor.GetElementHeight(overrideRule) : ruleTileEditor.GetElementHeight(originalRule); bool isMissing = index >= m_MissingOriginalRuleIndex; if (isMissing) height += 16; return height; } } }