From 9c5041099efca6cfb9d92284e4e71673bc97f534 Mon Sep 17 00:00:00 2001 From: skner <151752367+skner-dev@users.noreply.github.com> Date: Sun, 5 Jan 2025 17:02:39 +0000 Subject: [PATCH] Improved DualGridRuleTile inspector behaviour --- Editor/Editors/DualGridRuleTileEditor.cs | 118 +++++++++++++++++- Editor/Extensions.meta | 8 ++ .../Extensions/DualGridRuleTileExtensions.cs | 86 +++++++++++++ .../DualGridRuleTileExtensions.cs.meta | 11 ++ Editor/Menus/DualGridRuleTileMenu.cs | 34 ++--- Runtime/Components/DualGridRuleTile.cs | 6 + .../Tiles/ExampleDualGridRuleTile.asset | 1 + .../Tiles/ExampleRoundDualGridRuleTile.asset | 1 + 8 files changed, 233 insertions(+), 32 deletions(-) create mode 100644 Editor/Extensions.meta create mode 100644 Editor/Extensions/DualGridRuleTileExtensions.cs create mode 100644 Editor/Extensions/DualGridRuleTileExtensions.cs.meta diff --git a/Editor/Editors/DualGridRuleTileEditor.cs b/Editor/Editors/DualGridRuleTileEditor.cs index 7e0f02a..90670d3 100644 --- a/Editor/Editors/DualGridRuleTileEditor.cs +++ b/Editor/Editors/DualGridRuleTileEditor.cs @@ -1,3 +1,4 @@ +using skner.DualGrid.Editor.Extensions; using UnityEditor; using UnityEngine; @@ -7,15 +8,111 @@ namespace skner.DualGrid.Editor public class DualGridRuleTileEditor : RuleTileEditor { - public override BoundsInt GetRuleGUIBounds(BoundsInt bounds, RuleTile.TilingRule rule) + private DualGridRuleTile _targetDualGridRuleTile; + + public override void OnEnable() { - return new BoundsInt(-1, -1, 0, 2, 2, 0); + _targetDualGridRuleTile = (DualGridRuleTile)target; + + base.OnEnable(); } - public override Vector2 GetMatrixSize(BoundsInt bounds) + public override void OnInspectorGUI() { - float matrixCellSize = 27; - return new Vector2(bounds.size.x * matrixCellSize, bounds.size.y * matrixCellSize); + EditorGUILayout.LabelField("Dual Grid Settings", EditorStyles.boldLabel); + + EditorGUI.BeginChangeCheck(); + + if (_targetDualGridRuleTile.OriginalTexture == null && _targetDualGridRuleTile.m_TilingRules.Count == 0) + { + DrawDragAndDropArea(); + } + + EditorGUI.BeginChangeCheck(); + Texture2D appliedTexture = (Texture2D)EditorGUILayout.ObjectField("Original Texture", _targetDualGridRuleTile.OriginalTexture, typeof(Texture2D), false); + if (EditorGUI.EndChangeCheck()) + { + _targetDualGridRuleTile.TryApplyTexture2D(appliedTexture); + } + + if (_targetDualGridRuleTile.OriginalTexture == null) return; + + if (appliedTexture.GetSplitSpritesFromTexture().Count != 16) + { + EditorGUILayout.HelpBox("Selected texture is not split in exactly 16 sprites.\nPlease provide a valid texture.", MessageType.Error); + return; + } + + GUILayout.Space(10); + + if (GUILayout.Button("Apply Default GameObject to all Tile Rules")) + { + _targetDualGridRuleTile.m_TilingRules.ForEach(tilingRule => tilingRule.m_GameObject = _targetDualGridRuleTile.m_DefaultGameObject); + } + + if (GUILayout.Button("Apply Default Collider to all Tile Rules")) + { + _targetDualGridRuleTile.m_TilingRules.ForEach(tilingRule => tilingRule.m_ColliderType = _targetDualGridRuleTile.m_DefaultColliderType); + } + + if (GUILayout.Button("Refresh Rule Tiles in use")) + { + var dualGridModules = Object.FindObjectsByType(FindObjectsSortMode.None); + foreach (var dualGridModule in dualGridModules) + { + if (dualGridModule.Tile == _targetDualGridRuleTile) dualGridModule.RefreshRenderTiles(); + } + } + + GUILayout.Space(10); + + if (GUILayout.Button("Apply Automatic Rule Tiling")) + { + _targetDualGridRuleTile.TryApplyTexture2D(_targetDualGridRuleTile.OriginalTexture, ignoreAutoSlicePrompt: true); + AutoDualGridRuleTileProvider.ApplyConfigurationPreset(ref _targetDualGridRuleTile); + } + + GUILayout.Space(5); + + EditorGUILayout.LabelField("Rule Tile Settings", EditorStyles.boldLabel); + + if (EditorGUI.EndChangeCheck()) + { + EditorUtility.SetDirty(_targetDualGridRuleTile); + } + + base.OnInspectorGUI(); + } + + private void DrawDragAndDropArea() + { + Rect dropArea = GUILayoutUtility.GetRect(0, 100, GUILayout.ExpandWidth(true)); + GUI.Box(dropArea, "", EditorStyles.helpBox); + GUI.Box(dropArea, "Drag and drop a texture\nto start creating this Dual Grid Rule Tile", EditorStyles.centeredGreyMiniLabel); + + Event evt = Event.current; + if (evt.type == EventType.DragUpdated || evt.type == EventType.DragPerform) + { + if (dropArea.Contains(evt.mousePosition)) + { + DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + + if (evt.type == EventType.DragPerform) + { + DragAndDrop.AcceptDrag(); + + foreach (Object draggedObject in DragAndDrop.objectReferences) + { + if (draggedObject is Texture2D texture) + { + _targetDualGridRuleTile.TryApplyTexture2D(texture); + Repaint(); + break; + } + } + } + } + } } public override void RuleMatrixOnGUI(RuleTile tile, Rect rect, BoundsInt bounds, RuleTile.TilingRule tilingRule) @@ -55,6 +152,17 @@ public override void RuleMatrixOnGUI(RuleTile tile, Rect rect, BoundsInt bounds, } } + public override BoundsInt GetRuleGUIBounds(BoundsInt bounds, RuleTile.TilingRule rule) + { + return new BoundsInt(-1, -1, 0, 2, 2, 0); + } + + public override Vector2 GetMatrixSize(BoundsInt bounds) + { + float matrixCellSize = 27; + return new Vector2(bounds.size.x * matrixCellSize, bounds.size.y * matrixCellSize); + } + } } diff --git a/Editor/Extensions.meta b/Editor/Extensions.meta new file mode 100644 index 0000000..6e7102d --- /dev/null +++ b/Editor/Extensions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 474ac59f0860a4d45a32a1c6ddd96977 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Extensions/DualGridRuleTileExtensions.cs b/Editor/Extensions/DualGridRuleTileExtensions.cs new file mode 100644 index 0000000..951ca89 --- /dev/null +++ b/Editor/Extensions/DualGridRuleTileExtensions.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +namespace skner.DualGrid.Editor.Extensions +{ + public static class DualGridRuleTileExtensions + { + + /// + /// Applies the provided to the . + /// + /// If the texture is split in 16x sprites, an automatic rule tiling prompt will follow. + /// + /// Otherwise, the texture is incompatible and will not be applied, displaying a warning popup. + /// + /// + /// + /// + /// if the texture was applied, otherwise. + public static bool TryApplyTexture2D(this DualGridRuleTile dualGridRuleTile, Texture2D texture, bool ignoreAutoSlicePrompt = false) + { + List sprites = texture.GetSplitSpritesFromTexture().OrderBy(sprite => + { + var exception = new InvalidOperationException($"Cannot perform automatic tiling because sprite name '{sprite.name}' is not standardized. It must end with a '_' and a number. Example: 'tile_9'"); + + var spriteNumberString = sprite.name.Split("_").LastOrDefault() ?? throw exception; + bool wasParseSuccessful = int.TryParse(spriteNumberString, out int spriteNumber); + + if (wasParseSuccessful) return spriteNumber; + else throw exception; + }).ToList(); + + bool isTextureSlicedIn16Pieces = sprites.Count == 16; + + if (isTextureSlicedIn16Pieces) + { + bool shouldAutoSlice = ignoreAutoSlicePrompt || EditorUtility.DisplayDialog("16x Sliced Texture Detected", + "The selected texture is sliced in 16 pieces. Perform automatic rule tiling?", "Yes", "No"); + + dualGridRuleTile.OriginalTexture = texture; + ApplySprites(ref dualGridRuleTile, sprites); + + if (shouldAutoSlice) + AutoDualGridRuleTileProvider.ApplyConfigurationPreset(ref dualGridRuleTile); + + return true; + } + else + { + EditorUtility.DisplayDialog("Incompatible Texture Detected", "The selected texture is not sliced in 16 pieces.\nTexture will not be applied.", "Ok"); + return false; + } + } + + private static void ApplySprites(ref DualGridRuleTile dualGridRuleTile, List sprites) + { + dualGridRuleTile.m_DefaultSprite = sprites.FirstOrDefault(); + dualGridRuleTile.m_TilingRules.Clear(); + + foreach (Sprite sprite in sprites) + { + AddNewTilingRuleFromSprite(ref dualGridRuleTile, sprite); + } + } + + private static void AddNewTilingRuleFromSprite(ref DualGridRuleTile tile, Sprite sprite) + { + tile.m_TilingRules.Add(new DualGridRuleTile.TilingRule() { m_Sprites = new Sprite[] { sprite } }); + } + + /// + /// Returns a sorted list of s from a provided . + /// + /// + /// + public static List GetSplitSpritesFromTexture(this Texture2D texture) + { + string path = AssetDatabase.GetAssetPath(texture); + return AssetDatabase.LoadAllAssetsAtPath(path).OfType().ToList(); + } + + } +} diff --git a/Editor/Extensions/DualGridRuleTileExtensions.cs.meta b/Editor/Extensions/DualGridRuleTileExtensions.cs.meta new file mode 100644 index 0000000..b6896ee --- /dev/null +++ b/Editor/Extensions/DualGridRuleTileExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 83a2b3632e145394ba70bc4fb1a7fb47 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Menus/DualGridRuleTileMenu.cs b/Editor/Menus/DualGridRuleTileMenu.cs index 208c0f8..50f3e61 100644 --- a/Editor/Menus/DualGridRuleTileMenu.cs +++ b/Editor/Menus/DualGridRuleTileMenu.cs @@ -1,7 +1,9 @@ -using System.Collections.Generic; +using skner.DualGrid.Editor.Extensions; +using System.Collections.Generic; using System.IO; using System.Linq; using UnityEditor; +using UnityEditor.ProjectWindowCallback; using UnityEngine; namespace skner.DualGrid.Editor @@ -18,21 +20,8 @@ private static void CreateDualGridRuleTile() if (isSelectedObjectTexture2d) { - List sprites = GetSpritesFromTexture(selectedTexture); - - newRuleTile.m_DefaultSprite = sprites.FirstOrDefault(); - sprites.ForEach(sprite => AddTileRuleFromSprite(newRuleTile, sprite)); - - bool isTextureSlicedIn16Pieces = sprites.Count == 16; - - if (isTextureSlicedIn16Pieces) - { - bool shouldAutoSlice = EditorUtility.DisplayDialog("16x Sliced Texture Detected", - "The selected texture is sliced in 16 pieces. Perform automatic rule tiling?", "Yes", "No"); - - if(shouldAutoSlice) - AutoDualGridRuleTileProvider.ApplyConfigurationPreset(ref newRuleTile); - } + bool wasTextureApplied = newRuleTile.TryApplyTexture2D(selectedTexture); + if (!wasTextureApplied) return; } string activeAssetPath = AssetDatabase.GetAssetPath(Selection.activeObject); @@ -42,6 +31,8 @@ private static void CreateDualGridRuleTile() AssetDatabase.CreateAsset(newRuleTile, AssetDatabase.GenerateUniqueAssetPath(assetPath)); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); + + Selection.activeObject = newRuleTile; } private static bool TryGetSelectedTexture2D(out Texture2D selectedTexture2d) @@ -58,16 +49,5 @@ private static bool TryGetSelectedTexture2D(out Texture2D selectedTexture2d) } } - private static List GetSpritesFromTexture(Texture2D texture) - { - string path = AssetDatabase.GetAssetPath(texture); - return AssetDatabase.LoadAllAssetsAtPath(path).OfType().ToList(); - } - - private static void AddTileRuleFromSprite(DualGridRuleTile tile, Sprite sprite) - { - tile.m_TilingRules.Add(new DualGridRuleTile.TilingRule() { m_Sprites = new Sprite[] { sprite } }); - } - } } diff --git a/Runtime/Components/DualGridRuleTile.cs b/Runtime/Components/DualGridRuleTile.cs index 5244af7..9abd10f 100644 --- a/Runtime/Components/DualGridRuleTile.cs +++ b/Runtime/Components/DualGridRuleTile.cs @@ -1,5 +1,6 @@ using skner.DualGrid.Extensions; using skner.DualGrid.Utils; +using System; using UnityEngine; using UnityEngine.Tilemaps; using static skner.DualGrid.DualGridRuleTile; @@ -12,10 +13,15 @@ namespace skner.DualGrid /// /// Avoid using this tile in a palette, as any other data tile can be used. /// + [Serializable] [CreateAssetMenu(fileName = "DualGridRuleTile", menuName = "Scriptable Objects/DualGridRuleTile")] public class DualGridRuleTile : RuleTile { + [SerializeField] + private Texture2D _originalTexture; + public Texture2D OriginalTexture { get { return _originalTexture; } internal set { _originalTexture = value; } } + private DualGridTilemapModule _dualGridTilemapModule; private Tilemap _dataTilemap; diff --git a/Samples~/ExampleUsage/Resources/Tiles/ExampleDualGridRuleTile.asset b/Samples~/ExampleUsage/Resources/Tiles/ExampleDualGridRuleTile.asset index 3e53654..c22d4b2 100644 --- a/Samples~/ExampleUsage/Resources/Tiles/ExampleDualGridRuleTile.asset +++ b/Samples~/ExampleUsage/Resources/Tiles/ExampleDualGridRuleTile.asset @@ -288,3 +288,4 @@ MonoBehaviour: - {x: -1, y: -1, z: 0} - {x: 1, y: -1, z: 0} m_RuleTransform: 0 + _originalTexture: {fileID: 2800000, guid: c227d9b18c54c4c4e8383fae0fb4c724, type: 3} diff --git a/Samples~/ExampleUsage/Resources/Tiles/ExampleRoundDualGridRuleTile.asset b/Samples~/ExampleUsage/Resources/Tiles/ExampleRoundDualGridRuleTile.asset index fcfdb31..39a8e55 100644 --- a/Samples~/ExampleUsage/Resources/Tiles/ExampleRoundDualGridRuleTile.asset +++ b/Samples~/ExampleUsage/Resources/Tiles/ExampleRoundDualGridRuleTile.asset @@ -288,3 +288,4 @@ MonoBehaviour: - {x: -1, y: -1, z: 0} - {x: 1, y: -1, z: 0} m_RuleTransform: 0 + _originalTexture: {fileID: 2800000, guid: 2a438bbc707e5a74f9bb17899d4888ac, type: 3}