A game about forced loneliness, made by TACStudios
1using UnityEngine;
2using UnityEngine.Tilemaps;
3using Object = UnityEngine.Object;
4
5namespace UnityEditor.Tilemaps
6{
7 /// <summary>
8 /// Utility Class for creating Palettes
9 /// </summary>
10 public static class GridPaletteUtility
11 {
12 internal enum GridPaletteType
13 {
14 Rectangle,
15 HexagonalPointTop,
16 HexagonalFlatTop,
17 Isometric,
18 IsometricZAsY,
19 };
20
21 internal static readonly Vector3 defaultSortAxis = new Vector3(0f, 0f, 1f);
22
23 internal static GridLayout.CellLayout GetCellLayoutFromGridPaletteType(GridPaletteType paletteType)
24 {
25 switch (paletteType)
26 {
27 case GridPaletteType.HexagonalPointTop:
28 case GridPaletteType.HexagonalFlatTop:
29 {
30 return GridLayout.CellLayout.Hexagon;
31 }
32 case GridPaletteType.Isometric:
33 {
34 return GridLayout.CellLayout.Isometric;
35 }
36 case GridPaletteType.IsometricZAsY:
37 {
38 return GridLayout.CellLayout.IsometricZAsY;
39 }
40 }
41 return GridLayout.CellLayout.Rectangle;
42 }
43
44 internal static RectInt GetBounds(GameObject palette)
45 {
46 if (palette == null)
47 return new RectInt();
48
49 Vector2Int min = new Vector2Int(int.MaxValue, int.MaxValue);
50 Vector2Int max = new Vector2Int(int.MinValue, int.MinValue);
51
52 foreach (var tilemap in palette.GetComponentsInChildren<Tilemap>())
53 {
54 Vector3Int p1 = tilemap.editorPreviewOrigin;
55 Vector3Int p2 = p1 + tilemap.editorPreviewSize;
56 Vector2Int tilemapMin = new Vector2Int(Mathf.Min(p1.x, p2.x), Mathf.Min(p1.y, p2.y));
57 Vector2Int tilemapMax = new Vector2Int(Mathf.Max(p1.x, p2.x), Mathf.Max(p1.y, p2.y));
58 min = new Vector2Int(Mathf.Min(min.x, tilemapMin.x), Mathf.Min(min.y, tilemapMin.y));
59 max = new Vector2Int(Mathf.Max(max.x, tilemapMax.x), Mathf.Max(max.y, tilemapMax.y));
60 }
61
62 return GridEditorUtility.GetMarqueeRect(min, max);
63 }
64
65 /// <summary>
66 /// Creates a Palette Asset at the current selected folder path. This will show a popup allowing you to choose
67 /// a different folder path for saving the Palette Asset if required.
68 /// </summary>
69 /// <param name="name">Name of the Palette Asset.</param>
70 /// <param name="layout">Grid Layout of the Palette Asset.</param>
71 /// <param name="cellSizing">Cell Sizing of the Palette Asset.</param>
72 /// <param name="cellSize">Cell Size of the Palette Asset.</param>
73 /// <param name="swizzle">Cell Swizzle of the Palette.</param>
74 /// <returns>The created Palette Asset if successful.</returns>
75 public static GameObject CreateNewPaletteAtCurrentFolder(string name, GridLayout.CellLayout layout, GridPalette.CellSizing cellSizing, Vector3 cellSize, GridLayout.CellSwizzle swizzle)
76 {
77 return CreateNewPaletteAtCurrentFolder(name, layout, cellSizing, cellSize, swizzle
78 , TransparencySortMode.Default, defaultSortAxis);
79 }
80
81 /// <summary>
82 /// Creates a Palette Asset at the current selected folder path. This will show a popup allowing you to choose
83 /// a different folder path for saving the Palette Asset if required.
84 /// </summary>
85 /// <param name="name">Name of the Palette Asset.</param>
86 /// <param name="layout">Grid Layout of the Palette Asset.</param>
87 /// <param name="cellSizing">Cell Sizing of the Palette Asset.</param>
88 /// <param name="cellSize">Cell Size of the Palette Asset.</param>
89 /// <param name="swizzle">Cell Swizzle of the Palette.</param>
90 /// <param name="sortMode">Transparency Sort Mode for the Palette</param>
91 /// <param name="sortAxis">Transparency Sort Axis for the Palette</param>
92 /// <returns>The created Palette Asset if successful.</returns>
93 public static GameObject CreateNewPaletteAtCurrentFolder(string name
94 , GridLayout.CellLayout layout
95 , GridPalette.CellSizing cellSizing
96 , Vector3 cellSize
97 , GridLayout.CellSwizzle swizzle
98 , TransparencySortMode sortMode
99 , Vector3 sortAxis)
100 {
101 string defaultPath = ProjectBrowser.s_LastInteractedProjectBrowser ? ProjectBrowser.s_LastInteractedProjectBrowser.GetActiveFolderPath() : "Assets";
102 string folderPath = EditorUtility.SaveFolderPanel("Create palette into folder ", defaultPath, "");
103 folderPath = FileUtil.GetProjectRelativePath(folderPath);
104 if (!TilePaletteSaveUtility.ValidateSaveFolder(folderPath))
105 return null;
106 return CreateNewPalette(folderPath, name, layout, cellSizing, cellSize, swizzle, sortMode, sortAxis);
107 }
108
109 /// <summary>
110 /// Creates a Palette Asset at the given folder path.
111 /// </summary>
112 /// <param name="folderPath">Folder Path of the Palette Asset.</param>
113 /// <param name="name">Name of the Palette Asset.</param>
114 /// <param name="layout">Grid Layout of the Palette Asset.</param>
115 /// <param name="cellSizing">Cell Sizing of the Palette Asset.</param>
116 /// <param name="cellSize">Cell Size of the Palette Asset.</param>
117 /// <param name="swizzle">Cell Swizzle of the Palette.</param>
118 /// <returns>The created Palette Asset if successful.</returns>
119 public static GameObject CreateNewPalette(string folderPath
120 , string name
121 , GridLayout.CellLayout layout
122 , GridPalette.CellSizing cellSizing
123 , Vector3 cellSize
124 , GridLayout.CellSwizzle swizzle)
125 {
126 return CreateNewPalette(folderPath, name, layout, cellSizing, cellSize, swizzle,
127 TransparencySortMode.Default, defaultSortAxis);
128 }
129
130 /// <summary>
131 /// Creates a Palette Asset at the given folder path.
132 /// </summary>
133 /// <param name="folderPath">Folder Path of the Palette Asset.</param>
134 /// <param name="name">Name of the Palette Asset.</param>
135 /// <param name="layout">Grid Layout of the Palette Asset.</param>
136 /// <param name="cellSizing">Cell Sizing of the Palette Asset.</param>
137 /// <param name="cellSize">Cell Size of the Palette Asset.</param>
138 /// <param name="swizzle">Cell Swizzle of the Palette.</param>
139 /// <param name="sortMode">Transparency Sort Mode for the Palette</param>
140 /// <param name="sortAxis">Transparency Sort Axis for the Palette</param>
141 /// <returns>The created Palette Asset if successful.</returns>
142 public static GameObject CreateNewPalette(string folderPath
143 , string name
144 , GridLayout.CellLayout layout
145 , GridPalette.CellSizing cellSizing
146 , Vector3 cellSize
147 , GridLayout.CellSwizzle swizzle
148 , TransparencySortMode sortMode
149 , Vector3 sortAxis)
150 {
151 GameObject temporaryGO = new GameObject(name);
152 Grid grid = temporaryGO.AddComponent<Grid>();
153
154 // We set size to kEpsilon to mark this as new uninitialized palette
155 // Nice default size can be decided when first asset is dragged in
156 grid.cellSize = cellSize;
157 grid.cellLayout = layout;
158 grid.cellSwizzle = swizzle;
159 CreateNewLayer(temporaryGO, "Layer1", layout);
160
161 string path = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + name + ".prefab");
162
163 Object prefab = PrefabUtility.SaveAsPrefabAssetAndConnect(temporaryGO, path, InteractionMode.AutomatedAction);
164 GridPalette palette = CreateGridPalette(cellSizing, sortMode, sortAxis);
165 AssetDatabase.AddObjectToAsset(palette, prefab);
166 PrefabUtility.ApplyPrefabInstance(temporaryGO, InteractionMode.AutomatedAction);
167 AssetDatabase.Refresh();
168
169 Object.DestroyImmediate(temporaryGO);
170 return AssetDatabase.LoadAssetAtPath<GameObject>(path);
171 }
172
173 private static GameObject CreateNewLayer(GameObject paletteGO, string name, GridLayout.CellLayout layout)
174 {
175 GameObject newLayerGO = new GameObject(name);
176 var tilemap = newLayerGO.AddComponent<Tilemap>();
177 var renderer = newLayerGO.AddComponent<TilemapRenderer>();
178 newLayerGO.transform.parent = paletteGO.transform;
179 newLayerGO.layer = paletteGO.layer;
180
181 // Set defaults for certain layouts
182 switch (layout)
183 {
184 case GridLayout.CellLayout.Hexagon:
185 {
186 tilemap.tileAnchor = Vector3.zero;
187 break;
188 }
189 case GridLayout.CellLayout.Isometric:
190 {
191 renderer.sortOrder = TilemapRenderer.SortOrder.TopRight;
192 break;
193 }
194 case GridLayout.CellLayout.IsometricZAsY:
195 {
196 renderer.sortOrder = TilemapRenderer.SortOrder.TopRight;
197 renderer.mode = TilemapRenderer.Mode.Individual;
198 break;
199 }
200 }
201
202 return newLayerGO;
203 }
204
205 internal static GridPalette GetGridPaletteFromPaletteAsset(Object palette)
206 {
207 string assetPath = AssetDatabase.GetAssetPath(palette);
208 GridPalette paletteAsset = AssetDatabase.LoadAssetAtPath<GridPalette>(assetPath);
209 return paletteAsset;
210 }
211
212 internal static GridPalette CreateGridPalette(GridPalette.CellSizing cellSizing)
213 {
214 return CreateGridPalette(cellSizing, TransparencySortMode.Default, defaultSortAxis);
215 }
216
217 internal static GridPalette CreateGridPalette(GridPalette.CellSizing cellSizing
218 , TransparencySortMode sortMode
219 , Vector3 sortAxis
220 )
221 {
222 var palette = ScriptableObject.CreateInstance<GridPalette>();
223 palette.name = "Palette Settings";
224 palette.cellSizing = cellSizing;
225 palette.transparencySortMode = sortMode;
226 palette.transparencySortAxis = sortAxis;
227 return palette;
228 }
229
230 internal static Vector3 CalculateAutoCellSize(Grid grid, Vector3 defaultValue)
231 {
232 Tilemap[] tilemaps = grid.GetComponentsInChildren<Tilemap>();
233 Sprite[] sprites = null;
234 var maxSize = Vector2.negativeInfinity;
235 var minSize = Vector2.positiveInfinity;
236
237 // Get minimum and maximum sizes for Sprites
238 foreach (var tilemap in tilemaps)
239 {
240 var spriteCount = tilemap.GetUsedSpritesCount();
241 if (sprites == null || sprites.Length < spriteCount)
242 sprites = new Sprite[spriteCount];
243 tilemap.GetUsedSpritesNonAlloc(sprites);
244 for (int i = 0; i < spriteCount; ++i)
245 {
246 Sprite sprite = sprites[i];
247 if (sprite != null)
248 {
249 var cellSize = new Vector3(sprite.rect.width, sprite.rect.height, 0f) / sprite.pixelsPerUnit;
250 if (tilemap.cellSwizzle == GridLayout.CellSwizzle.YXZ)
251 {
252 var swap = cellSize.x;
253 cellSize.x = cellSize.y;
254 cellSize.y = swap;
255 }
256 minSize.x = Mathf.Min(cellSize.x, minSize.x);
257 minSize.y = Mathf.Min(cellSize.y, minSize.y);
258 maxSize.x = Mathf.Max(cellSize.x, maxSize.x);
259 maxSize.y = Mathf.Max(cellSize.y, maxSize.y);
260 }
261 }
262 }
263 // Validate that Sprites are in multiples of sizes
264 foreach (var tilemap in tilemaps)
265 {
266 var spriteCount = tilemap.GetUsedSpritesCount();
267 if (sprites == null || sprites.Length < spriteCount)
268 sprites = new Sprite[spriteCount];
269 tilemap.GetUsedSpritesNonAlloc(sprites);
270 for (int i = 0; i < spriteCount; ++i)
271 {
272 Sprite sprite = sprites[i];
273 if (sprite != null)
274 {
275 var cellSize = new Vector3(sprite.rect.width, sprite.rect.height, 0f) / sprite.pixelsPerUnit;
276 if (tilemap.cellSwizzle == GridLayout.CellSwizzle.YXZ)
277 {
278 var swap = cellSize.x;
279 cellSize.x = cellSize.y;
280 cellSize.y = swap;
281 }
282 // Return maximum size if sprites are not multiples of the smallest size
283 if (cellSize.x % minSize.x > 0)
284 return maxSize.x * maxSize.y <= 0f ? defaultValue : new Vector3(maxSize.x, maxSize.y, 0f);
285 if (cellSize.y % minSize.y > 0)
286 return maxSize.x * maxSize.y <= 0f ? defaultValue : new Vector3(maxSize.x, maxSize.y, 0f);
287 }
288 }
289 }
290 return minSize.x * minSize.y <= 0f || minSize == Vector2.positiveInfinity ? defaultValue : new Vector3(minSize.x, minSize.y, 0f);
291 }
292 }
293}