using UnityEngine; using UnityEngine.Tilemaps; namespace UnityEditor { /// /// The Editor for a HexagonalRuleTile. /// [CustomEditor(typeof(HexagonalRuleTile), true)] [CanEditMultipleObjects] public class HexagonalRuleTileEditor : RuleTileEditor { /// /// The HexagonalRuleTile being edited. /// public HexagonalRuleTile hexTile => target as HexagonalRuleTile; /// /// Gets the index for a Rule with the HexagonalRuleTile to display an arrow. /// /// The adjacent position of the arrow. /// Returns the index for a Rule with the HexagonalRuleTile to display an arrow. public override int GetArrowIndex(Vector3Int position) { if (position.y % 2 != 0) { position *= 2; position.x += 1; } if (position.x == 0) { if (position.y > 0) return hexTile.m_FlatTop ? 5 : 1; else return hexTile.m_FlatTop ? 3 : 7; } else if (position.y == 0) { if (position.x > 0) return hexTile.m_FlatTop ? 1 : 5; else return hexTile.m_FlatTop ? 7 : 3; } else { if (position.x < 0 && position.y > 0) return hexTile.m_FlatTop ? 8 : 0; else if (position.x > 0 && position.y > 0) return hexTile.m_FlatTop ? 2 : 2; else if (position.x < 0 && position.y < 0) return hexTile.m_FlatTop ? 6 : 6; else if (position.x > 0 && position.y < 0) return hexTile.m_FlatTop ? 0 : 8; } return -1; } /// /// Get the GUI bounds for a Rule. /// /// Cell bounds of the Rule. /// Rule to get GUI bounds for. /// The GUI bounds for a rule. public override BoundsInt GetRuleGUIBounds(BoundsInt bounds, RuleTile.TilingRule rule) { foreach (var n in rule.GetNeighbors()) { if (n.Key.x == bounds.xMax - 1 && n.Key.y % 2 != 0) { bounds.xMax++; break; } } return base.GetRuleGUIBounds(bounds, rule); } /// /// Gets the GUI matrix size for a Rule of a HexagonalRuleTile /// /// Cell bounds of the Rule. /// Returns the GUI matrix size for a Rule of a HexagonalRuleTile. public override Vector2 GetMatrixSize(BoundsInt bounds) { Vector2 size = base.GetMatrixSize(bounds); return hexTile.m_FlatTop ? new Vector2(size.y, size.x) : size; } /// /// Draws a Rule Matrix for the given Rule for a HexagonalRuleTile. /// /// Tile to draw rule for. /// GUI Rect to draw rule at. /// Cell bounds of the Rule. /// Rule to draw Rule Matrix for. public override void RuleMatrixOnGUI(RuleTile tile, Rect rect, BoundsInt bounds, RuleTile.TilingRule tilingRule) { bool flatTop = hexTile.m_FlatTop; Handles.color = EditorGUIUtility.isProSkin ? new Color(1f, 1f, 1f, 0.2f) : new Color(0f, 0f, 0f, 0.2f); float w = rect.width / (flatTop ? bounds.size.y : bounds.size.x); float h = rect.height / (flatTop ? bounds.size.x : bounds.size.y); // Grid if (flatTop) { for (int y = 0; y <= bounds.size.y; y++) { float left = rect.xMin + y * w; float offset = 0; if (y == 0 && bounds.yMax % 2 == 0) offset = h / 2; else if (y == bounds.size.y && bounds.yMin % 2 != 0) offset = h / 2; Handles.DrawLine(new Vector3(left, rect.yMin + offset), new Vector3(left, rect.yMax - offset)); if (y < bounds.size.y) { bool noOffset = (y + bounds.yMax) % 2 != 0; for (int x = 0; x < (noOffset ? (bounds.size.x + 1) : bounds.size.x); x++) { float top = rect.yMin + x * h + (noOffset ? 0 : h / 2); Handles.DrawLine(new Vector3(left, top), new Vector3(left + w, top)); } } } } else { for (int y = 0; y <= bounds.size.y; y++) { float top = rect.yMin + y * h; float offset = 0; if (y == 0 && bounds.yMax % 2 == 0) offset = w / 2; else if (y == bounds.size.y && bounds.yMin % 2 != 0) offset = w / 2; Handles.DrawLine(new Vector3(rect.xMin + offset, top), new Vector3(rect.xMax - offset, top)); if (y < bounds.size.y) { bool noOffset = (y + bounds.yMax) % 2 != 0; for (int x = 0; x < (noOffset ? (bounds.size.x + 1) : bounds.size.x); x++) { float left = rect.xMin + x * w + (noOffset ? 0 : w / 2); Handles.DrawLine(new Vector3(left, top), new Vector3(left, top + h)); } } } } var neighbors = tilingRule.GetNeighbors(); // Icons Handles.color = Color.white; for (int y = bounds.yMin; y < bounds.yMax; y++) { int xMax = y % 2 == 0 ? bounds.xMax : (bounds.xMax - 1); for (int x = bounds.xMin; x < xMax; x++) { Vector3Int pos = new Vector3Int(x, y, 0); Vector2 offset = new Vector2(x - bounds.xMin, -y + bounds.yMax - 1); Rect r = flatTop ? new Rect(rect.xMax - offset.y * w - w, rect.yMax - offset.x * h - h, w - 1, h - 1) : new Rect(rect.xMin + offset.x * w, rect.yMin + offset.y * h, w - 1, h - 1); if (y % 2 != 0) { if (flatTop) r.y -= h / 2; else r.x += w / 2; } RuleMatrixIconOnGUI(tilingRule, neighbors, pos, r); } } } /// /// Creates a Preview for the HexagonalRuleTile. /// protected override void CreatePreview() { base.CreatePreview(); m_PreviewGrid.cellLayout = GridLayout.CellLayout.Hexagon; m_PreviewGrid.cellSize = new Vector3(0.8659766f, 1.0f, 1.0f); m_PreviewGrid.cellSwizzle = hexTile.m_FlatTop ? GridLayout.CellSwizzle.YXZ : GridLayout.CellSwizzle.XYZ; foreach (var tilemap in m_PreviewTilemaps) { tilemap.tileAnchor = Vector3.zero; tilemap.ClearAllTiles(); } for (int x = -1; x <= 0; ++x) for (int y = -1; y <= 1; ++y) m_PreviewTilemaps[0].SetTile(new Vector3Int(x, y, 0), tile); m_PreviewTilemaps[1].SetTile(new Vector3Int(1, -1, 0), tile); m_PreviewTilemaps[1].SetTile(new Vector3Int(2, 0, 0), tile); m_PreviewTilemaps[1].SetTile(new Vector3Int(2, 1, 0), tile); for (int x = -1; x <= 1; x++) m_PreviewTilemaps[2].SetTile(new Vector3Int(x, -2, 0), tile); m_PreviewTilemaps[3].SetTile(new Vector3Int(1, 1, 0), tile); foreach (var tilemapRenderer in m_PreviewTilemapRenderers) tilemapRenderer.sortOrder = TilemapRenderer.SortOrder.TopRight; m_PreviewTilemapRenderers[0].sortingOrder = 0; m_PreviewTilemapRenderers[1].sortingOrder = -1; m_PreviewTilemapRenderers[2].sortingOrder = 1; m_PreviewTilemapRenderers[3].sortingOrder = 0; } } }