Skip to content

Commit

Permalink
Improved DualGridRuleTile inspector behaviour
Browse files Browse the repository at this point in the history
  • Loading branch information
skner-dev committed Jan 5, 2025
1 parent 7a98fe8 commit 9c50410
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 32 deletions.
118 changes: 113 additions & 5 deletions Editor/Editors/DualGridRuleTileEditor.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using skner.DualGrid.Editor.Extensions;
using UnityEditor;
using UnityEngine;

Expand All @@ -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<DualGridTilemapModule>(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)
Expand Down Expand Up @@ -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);
}

}

}
Expand Down
8 changes: 8 additions & 0 deletions Editor/Extensions.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

86 changes: 86 additions & 0 deletions Editor/Extensions/DualGridRuleTileExtensions.cs
Original file line number Diff line number Diff line change
@@ -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
{

/// <summary>
/// Applies the provided <paramref name="texture"/> to the <paramref name="dualGridRuleTile"/>.
/// <para></para>
/// If the texture is split in 16x sprites, an automatic rule tiling prompt will follow.
/// <para></para>
/// Otherwise, the texture is incompatible and will not be applied, displaying a warning popup.
/// </summary>
/// <param name="dualGridRuleTile"></param>
/// <param name="texture"></param>
/// <param name="ignoreAutoSlicePrompt"></param>
/// <returns><see langword="true"/> if the texture was applied, <see langword="false"/> otherwise.</returns>
public static bool TryApplyTexture2D(this DualGridRuleTile dualGridRuleTile, Texture2D texture, bool ignoreAutoSlicePrompt = false)
{
List<Sprite> 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<Sprite> 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 } });
}

/// <summary>
/// Returns a sorted list of <see cref="Sprite"/>s from a provided <paramref name="texture"/>.
/// </summary>
/// <param name="texture"></param>
/// <returns></returns>
public static List<Sprite> GetSplitSpritesFromTexture(this Texture2D texture)
{
string path = AssetDatabase.GetAssetPath(texture);
return AssetDatabase.LoadAllAssetsAtPath(path).OfType<Sprite>().ToList();
}

}
}
11 changes: 11 additions & 0 deletions Editor/Extensions/DualGridRuleTileExtensions.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 7 additions & 27 deletions Editor/Menus/DualGridRuleTileMenu.cs
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -18,21 +20,8 @@ private static void CreateDualGridRuleTile()

if (isSelectedObjectTexture2d)
{
List<Sprite> 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);
Expand All @@ -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)
Expand All @@ -58,16 +49,5 @@ private static bool TryGetSelectedTexture2D(out Texture2D selectedTexture2d)
}
}

private static List<Sprite> GetSpritesFromTexture(Texture2D texture)
{
string path = AssetDatabase.GetAssetPath(texture);
return AssetDatabase.LoadAllAssetsAtPath(path).OfType<Sprite>().ToList();
}

private static void AddTileRuleFromSprite(DualGridRuleTile tile, Sprite sprite)
{
tile.m_TilingRules.Add(new DualGridRuleTile.TilingRule() { m_Sprites = new Sprite[] { sprite } });
}

}
}
6 changes: 6 additions & 0 deletions Runtime/Components/DualGridRuleTile.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using skner.DualGrid.Extensions;
using skner.DualGrid.Utils;
using System;
using UnityEngine;
using UnityEngine.Tilemaps;
using static skner.DualGrid.DualGridRuleTile;
Expand All @@ -12,10 +13,15 @@ namespace skner.DualGrid
/// <remarks>
/// Avoid using this tile in a palette, as any other data tile can be used.
/// </remarks>
[Serializable]
[CreateAssetMenu(fileName = "DualGridRuleTile", menuName = "Scriptable Objects/DualGridRuleTile")]
public class DualGridRuleTile : RuleTile<DualGridNeighbor>
{

[SerializeField]
private Texture2D _originalTexture;
public Texture2D OriginalTexture { get { return _originalTexture; } internal set { _originalTexture = value; } }

private DualGridTilemapModule _dualGridTilemapModule;

private Tilemap _dataTilemap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Original file line number Diff line number Diff line change
Expand Up @@ -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}

0 comments on commit 9c50410

Please sign in to comment.