using System.Collections.Generic; using UnityEngine; namespace AibisDream { /// /// 网格可视化组件 /// 负责在Unity场景中可视化显示网格和单元格状态 /// public class GridVisualizer : MonoBehaviour { [Header("网格配置")] [SerializeField] private BlockPuzzleGrid grid; private IBlockPuzzleGrid _grid; [Header("可视化设置")] [SerializeField] private bool showGridLines = true; [SerializeField] private bool showCellSprites = true; [SerializeField] private Color emptyCellColor = new Color(0.9f, 0.9f, 0.9f, 0.3f); [SerializeField] private Color occupiedCellColor = new Color(0.2f, 0.6f, 1f, 1f); [SerializeField] private Color previewValidCellColor = new Color(0.2f, 1f, 0.2f, 1f); [SerializeField] private Color previewInvalidCellColor = new Color(1f, 0.2f, 0.2f, 1f); [SerializeField] private Color gridLineColor = new Color(0.5f, 0.5f, 0.5f, 0.5f); [SerializeField] private float gridLineWidth = 0.02f; [Header("预制体(可选)")] [SerializeField] private Sprite cellSprite; [SerializeField] private Material cellMaterial; [SerializeField] private int sortingLayer; [SerializeField] private int sortingOrder; // 单元格可视化对象池 private Dictionary<(int x, int y), GameObject> _cellObjects = new Dictionary<(int x, int y), GameObject>(); private GameObject _gridLinesParent; private GameObject _cellsParent; private void Awake() { // 创建父对象用于组织层级 _gridLinesParent = new GameObject("GridLines"); _gridLinesParent.transform.SetParent(transform); _gridLinesParent.transform.localPosition = Vector3.zero; _cellsParent = new GameObject("Cells"); _cellsParent.transform.SetParent(transform); _cellsParent.transform.localPosition = Vector3.zero; } /// /// 设置网格引用 /// public void Init(IBlockPuzzleGrid grid) { _grid = grid; ClearVisualization(); CreateVisualization(); SetGridVisible(false); } /// /// 设置网格显示/隐藏 /// public void SetGridVisible(bool visible) { if (_gridLinesParent != null) _gridLinesParent.SetActive(visible); if (_cellsParent != null) _cellsParent.SetActive(visible); } /// /// 创建可视化 /// private void CreateVisualization() { if (_grid == null) return; if (showGridLines) { DrawGridLines(); } if (showCellSprites) { CreateCellSprites(); } } /// /// 绘制网格线 /// private void DrawGridLines() { // 清除旧的网格线 foreach (Transform child in _gridLinesParent.transform) { if (Application.isPlaying) { Destroy(child.gameObject); } else { DestroyImmediate(child.gameObject); } } // 创建网格线(使用LineRenderer或简单的Quad) for (int x = 0; x <= _grid.Width; x++) { CreateLine( _grid.GridVerticesToWorld(x, 0)[0], _grid.GridVerticesToWorld(x, _grid.Height)[0], gridLineWidth, gridLineColor ); } for (int y = 0; y <= _grid.Height; y++) { CreateLine( _grid.GridVerticesToWorld(0, y)[0], _grid.GridVerticesToWorld(_grid.Width, y)[0], gridLineWidth, gridLineColor ); } } /// /// 创建一条线 /// private void CreateLine(Vector3 start, Vector3 end, float width, Color color) { GameObject lineObj = new GameObject("GridLine"); lineObj.transform.SetParent(_gridLinesParent.transform); lineObj.transform.localPosition = Vector3.zero; LineRenderer lineRenderer = lineObj.AddComponent(); lineRenderer.sortingLayerID = sortingLayer; lineRenderer.sortingOrder = sortingOrder; lineRenderer.useWorldSpace = true; lineRenderer.positionCount = 2; lineRenderer.SetPosition(0, start); lineRenderer.SetPosition(1, end); lineRenderer.startWidth = width; lineRenderer.endWidth = width; lineRenderer.material = new Material(Shader.Find("Sprites/Default")); lineRenderer.startColor = color; lineRenderer.endColor = color; lineRenderer.sortingLayerID = sortingLayer; lineRenderer.sortingOrder = sortingOrder; } /// /// 创建单元格精灵 /// private void CreateCellSprites() { // 清除旧的单元格 ClearCellSprites(); // 为每个单元格创建可视化对象 for (int x = 0; x < _grid.Width; x++) { for (int y = 0; y < _grid.Height; y++) { CreateCellSprite(x, y); } } } /// /// 创建单个单元格精灵 /// private void CreateCellSprite(int x, int y) { GameObject cellObj = new GameObject($"Cell_{x}_{y}"); cellObj.transform.SetParent(_cellsParent.transform); cellObj.transform.position = _grid.GridToWorld(x, y); SpriteRenderer spriteRenderer = cellObj.AddComponent(); spriteRenderer.sortingLayerID = sortingLayer; spriteRenderer.sortingOrder = sortingOrder; // 如果没有指定Sprite,创建一个简单的白色Sprite if (cellSprite == null) { cellSprite = CreateDefaultSprite(); } spriteRenderer.sprite = cellSprite; spriteRenderer.color = emptyCellColor; spriteRenderer.sortingLayerID = sortingLayer; spriteRenderer.sortingOrder = sortingOrder; // 设置大小 float spriteSize = _grid.CellSize * 0.9f; // 稍微小一点,留出网格线空间 cellObj.transform.localScale = new Vector3(spriteSize, spriteSize, 1f); // 如果有材质,应用材质 if (cellMaterial != null) { spriteRenderer.material = cellMaterial; } _cellObjects[(x, y)] = cellObj; } /// /// 创建默认的白色Sprite /// private Sprite CreateDefaultSprite() { Texture2D texture = new Texture2D(1, 1); texture.SetPixel(0, 0, Color.white); texture.Apply(); return Sprite.Create(texture, new Rect(0, 0, 1, 1), new Vector2(0.5f, 0.5f), 1f); } /// /// 更新单元格可视化状态 /// public void UpdateCellVisual(int x, int y) { if (!_cellObjects.TryGetValue((x, y), out GameObject cellObj)) { return; } SpriteRenderer spriteRenderer = cellObj.GetComponent(); if (spriteRenderer == null) return; GridCellState gridstate = _grid.GetCellState(x, y); GridCellState previewState = _grid.GetPreviewCellState(x, y); spriteRenderer.color = GetCellColor(gridstate, previewState); } private Color GetCellColor(GridCellState gridCellState, GridCellState previewCellState) { if (gridCellState == GridCellState.Occupied) { return occupiedCellColor; } else if (previewCellState == GridCellState.PreviewInvalid) { return previewInvalidCellColor; } else if (previewCellState == GridCellState.PreviewVaild) { return previewValidCellColor; } else { return emptyCellColor; } } /// /// 更新所有单元格可视化 /// public void UpdateAllCellsVisual() { if (_grid == null) return; for (int x = 0; x < _grid.Width; x++) { for (int y = 0; y < _grid.Height; y++) { UpdateCellVisual(x, y); } } } /// /// 清除单元格精灵 /// private void ClearCellSprites() { foreach (var kvp in _cellObjects) { if (Application.isPlaying) { Destroy(kvp.Value); } else { DestroyImmediate(kvp.Value); } } _cellObjects.Clear(); } /// /// 清除所有可视化 /// private void ClearVisualization() { ClearCellSprites(); foreach (Transform child in _gridLinesParent.transform) { if (Application.isPlaying) { Destroy(child.gameObject); } else { DestroyImmediate(child.gameObject); } } } private void OnDestroy() { ClearVisualization(); } // ============================================ 绘制预览 ============================================ /// /// 在编辑器中绘制网格预览 /// private void OnDrawGizmos() { if (grid == null) return; // 使用当前Inspector中的参数或已初始化的参数 int drawWidth = grid.width; int drawHeight = grid.height; float drawCellSize = grid.cellSize; Vector3 drawOrigin = transform.position; if (drawWidth <= 0 || drawHeight <= 0 || drawCellSize <= 0) return; // 绘制网格线 Gizmos.color = gridLineColor; for (int x = 0; x <= drawWidth; x++) { Vector3 start = drawOrigin + new Vector3(x * drawCellSize, 0, 0); Vector3 end = drawOrigin + new Vector3(x * drawCellSize, drawHeight * drawCellSize, 0); Gizmos.DrawLine(start, end); } for (int y = 0; y <= drawHeight; y++) { Vector3 start = drawOrigin + new Vector3(0, y * drawCellSize, 0); Vector3 end = drawOrigin + new Vector3(drawWidth * drawCellSize, y * drawCellSize, 0); Gizmos.DrawLine(start, end); } // 绘制单元格状态(如果已初始化且启用) if (_grid != null) { float cellDisplaySize = drawCellSize * 0.9f; // 稍微小一点,留出网格线空间 Vector3 cellSizeVec = new Vector3(cellDisplaySize, cellDisplaySize, 0.01f); for (int x = 0; x < drawWidth; x++) { for (int y = 0; y < drawHeight; y++) { if (grid.IsValidPosition(x, y)) { Vector3 cellCenter = grid.GridToWorld(x, y); GridCellState state = grid.GetCellState(x, y); Gizmos.color = state == GridCellState.Occupied ? occupiedCellColor : emptyCellColor; Gizmos.DrawCube(cellCenter, cellSizeVec); } } } } } /// /// 选中时绘制更明显的网格边界 /// private void OnDrawGizmosSelected() { if (grid == null) return; // 使用当前Inspector中的参数或已初始化的参数 int drawWidth = grid.width; int drawHeight = grid.height; float drawCellSize = grid.cellSize; Vector3 drawOrigin = transform.position; if (drawWidth <= 0 || drawHeight <= 0 || drawCellSize <= 0) return; // 绘制网格边界(更粗的线) Gizmos.color = new Color(gridLineColor.r, gridLineColor.g, gridLineColor.b, 1f); Vector3 bottomLeft = drawOrigin; Vector3 bottomRight = drawOrigin + new Vector3(drawWidth * drawCellSize, 0, 0); Vector3 topLeft = drawOrigin + new Vector3(0, drawHeight * drawCellSize, 0); Vector3 topRight = drawOrigin + new Vector3(drawWidth * drawCellSize, drawHeight * drawCellSize, 0); // 绘制边界框 Gizmos.DrawLine(bottomLeft, bottomRight); Gizmos.DrawLine(bottomRight, topRight); Gizmos.DrawLine(topRight, topLeft); Gizmos.DrawLine(topLeft, bottomLeft); // 绘制原点标记 Gizmos.color = Color.yellow; Gizmos.DrawWireSphere(drawOrigin, 0.1f); } } }