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);
}
}
}