361 lines
12 KiB
C#
361 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace AibisDream
|
|
{
|
|
/// <summary>
|
|
/// BlockPuzzle网格组件
|
|
/// 实现IBlockPuzzleGrid接口,管理整个游戏网格的状态和操作
|
|
/// </summary>
|
|
public class BlockPuzzleGrid : MonoBehaviour, IBlockPuzzleGrid
|
|
{
|
|
[Header("网格设置")]
|
|
[SerializeField] private int width = 10;
|
|
[SerializeField] private int height = 10;
|
|
[SerializeField] private float cellSize = 1f;
|
|
[SerializeField] private bool initializeOnStart = true;
|
|
|
|
[Header("编辑器预览设置")]
|
|
[SerializeField] private bool showGizmos = true;
|
|
[SerializeField] private Color gridLineColor = new Color(0.5f, 0.5f, 0.5f, 0.8f);
|
|
[SerializeField] private Color emptyCellColor = new Color(0.9f, 0.9f, 0.9f, 0.2f);
|
|
[SerializeField] private Color occupiedCellColor = new Color(0.2f, 0.6f, 1f, 0.5f);
|
|
[SerializeField] private bool showCellStates = true;
|
|
|
|
private GridCellState[,] _grid;
|
|
private bool _isInitialized = false;
|
|
|
|
// IBlockPuzzleGrid 接口实现
|
|
public int Width { get; private set; }
|
|
public int Height { get; private set; }
|
|
public float CellSize { get; private set; }
|
|
public Vector3 Origin { get; private set; }
|
|
public Dictionary<BlockShape, Vector2Int> ShapeDict { get; private set; }
|
|
|
|
public event Action OnShapePlaced;
|
|
|
|
private void Start()
|
|
{
|
|
if (initializeOnStart)
|
|
{
|
|
Initialize(width, height, cellSize, transform.position);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 初始化网格
|
|
/// </summary>
|
|
public void Initialize(int width, int height, float cellSize, Vector3 origin)
|
|
{
|
|
if (width <= 0 || height <= 0)
|
|
{
|
|
Debug.LogError($"BlockPuzzleGridComponent: 无效的网格尺寸 {width}x{height}");
|
|
return;
|
|
}
|
|
|
|
if (cellSize <= 0)
|
|
{
|
|
Debug.LogError($"BlockPuzzleGridComponent: 无效的单元格大小 {cellSize}");
|
|
return;
|
|
}
|
|
|
|
this.width = width;
|
|
this.height = height;
|
|
this.cellSize = cellSize;
|
|
|
|
Width = width;
|
|
Height = height;
|
|
CellSize = cellSize;
|
|
Origin = origin;
|
|
_grid = new GridCellState[width, height];
|
|
_isInitialized = true;
|
|
|
|
ShapeDict = new Dictionary<BlockShape, Vector2Int>();
|
|
|
|
Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 使用Inspector中的参数初始化网格
|
|
/// </summary>
|
|
public void Initialize()
|
|
{
|
|
Initialize(width, height, cellSize, transform.position);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 重新初始化网格(使用新的参数)
|
|
/// </summary>
|
|
public void Reinitialize(int newWidth, int newHeight, float newCellSize)
|
|
{
|
|
Initialize(newWidth, newHeight, newCellSize, transform.position);
|
|
}
|
|
|
|
public GridCellState GetCellState(int x, int y)
|
|
{
|
|
if (!_isInitialized)
|
|
{
|
|
Debug.LogWarning("BlockPuzzleGridComponent: 网格未初始化");
|
|
return GridCellState.Empty;
|
|
}
|
|
|
|
if (!IsValidPosition(x, y))
|
|
{
|
|
Debug.LogWarning($"BlockPuzzleGridComponent: 尝试访问无效位置 ({x}, {y})");
|
|
return GridCellState.OutOfBounds;
|
|
}
|
|
|
|
return _grid[x, y];
|
|
}
|
|
|
|
public void SetCellState(int x, int y, GridCellState state)
|
|
{
|
|
if (!_isInitialized)
|
|
{
|
|
Debug.LogWarning("BlockPuzzleGridComponent: 网格未初始化");
|
|
return;
|
|
}
|
|
|
|
if (!IsValidPosition(x, y))
|
|
{
|
|
Debug.LogWarning($"BlockPuzzleGridComponent: 尝试设置无效位置 ({x}, {y})");
|
|
return;
|
|
}
|
|
|
|
_grid[x, y] = state;
|
|
}
|
|
|
|
public bool IsValidPosition(int x, int y)
|
|
{
|
|
return _isInitialized && x >= 0 && x < Width && y >= 0 && y < Height;
|
|
}
|
|
|
|
public bool IsCellEmpty(int x, int y)
|
|
{
|
|
return IsValidPosition(x, y) && GetCellState(x, y) == GridCellState.Empty;
|
|
}
|
|
|
|
public bool CanPlace(Vector2Int[] gridCells)
|
|
{
|
|
for (int i = 0; i < gridCells.Length; i++)
|
|
{
|
|
// 先验证是否在有效范围内
|
|
if (!IsValidPosition(gridCells[i].x, gridCells[i].y))
|
|
{
|
|
return false;
|
|
}
|
|
// 再验证是否为空
|
|
else if (GetCellState(gridCells[i].x, gridCells[i].y) == GridCellState.Occupied)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public bool WorldToGrid(Vector3 worldPos, out int gridX, out int gridY)
|
|
{
|
|
if (!_isInitialized)
|
|
{
|
|
gridX = 0;
|
|
gridY = 0;
|
|
return false;
|
|
}
|
|
|
|
Vector3 localPos = worldPos - Origin;
|
|
gridX = Mathf.FloorToInt(localPos.x / CellSize);
|
|
gridY = Mathf.FloorToInt(localPos.y / CellSize);
|
|
|
|
return true;
|
|
}
|
|
|
|
public Vector3 GridToWorld(int gridX, int gridY)
|
|
{
|
|
if (!_isInitialized)
|
|
{
|
|
return transform.position;
|
|
}
|
|
|
|
// 返回单元格中心的世界坐标
|
|
float worldX = Origin.x + (gridX + 0.5f) * CellSize;
|
|
float worldY = Origin.y + (gridY + 0.5f) * CellSize;
|
|
return new Vector3(worldX, worldY, Origin.z);
|
|
}
|
|
|
|
public Vector3[] GridVerticesToWorld(int x, int y)
|
|
{
|
|
if (!_isInitialized)
|
|
{
|
|
return new Vector3[4];
|
|
}
|
|
|
|
// 先获取网格中心位置
|
|
Vector3 center = GridToWorld(x, y);
|
|
// 然后获取网格四个顶点位置
|
|
Vector3[] vertices = new Vector3[4];
|
|
vertices[0] = center + new Vector3(-CellSize / 2, -CellSize / 2, 0);
|
|
vertices[1] = center + new Vector3(CellSize / 2, -CellSize / 2, 0);
|
|
vertices[2] = center + new Vector3(CellSize / 2, CellSize / 2, 0);
|
|
vertices[3] = center + new Vector3(-CellSize / 2, CellSize / 2, 0);
|
|
return vertices;
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
if (!_isInitialized || _grid == null) return;
|
|
|
|
for (int x = 0; x < Width; x++)
|
|
{
|
|
for (int y = 0; y < Height; y++)
|
|
{
|
|
_grid[x, y] = GridCellState.Empty;
|
|
}
|
|
}
|
|
}
|
|
|
|
public int GetOccupiedCount()
|
|
{
|
|
if (!_isInitialized || _grid == null) return 0;
|
|
|
|
int count = 0;
|
|
for (int x = 0; x < Width; x++)
|
|
{
|
|
for (int y = 0; y < Height; y++)
|
|
{
|
|
if (_grid[x, y] == GridCellState.Occupied)
|
|
{
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
public int GetTotalCellCount()
|
|
{
|
|
return Width * Height;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检查网格是否已初始化
|
|
/// </summary>
|
|
public bool IsInitialized()
|
|
{
|
|
return _isInitialized;
|
|
}
|
|
|
|
private void OnValidate()
|
|
{
|
|
// 确保参数有效
|
|
width = Mathf.Max(1, width);
|
|
height = Mathf.Max(1, height);
|
|
cellSize = Mathf.Max(0.1f, cellSize);
|
|
}
|
|
|
|
public List<BlockShape> GetShapes()
|
|
{
|
|
return ShapeDict.Keys.ToList();
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
OnShapePlaced = null;
|
|
}
|
|
|
|
|
|
// ============================================ 绘制预览 ============================================
|
|
|
|
|
|
/// <summary>
|
|
/// 在编辑器中绘制网格预览
|
|
/// </summary>
|
|
private void OnDrawGizmos()
|
|
{
|
|
if (!showGizmos) return;
|
|
|
|
// 使用当前Inspector中的参数或已初始化的参数
|
|
int drawWidth = _isInitialized ? Width : width;
|
|
int drawHeight = _isInitialized ? Height : height;
|
|
float drawCellSize = _isInitialized ? CellSize : cellSize;
|
|
Vector3 drawOrigin = _isInitialized ? Origin : 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 (showCellStates && _isInitialized && _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 (IsValidPosition(x, y))
|
|
{
|
|
Vector3 cellCenter = GridToWorld(x, y);
|
|
GridCellState state = GetCellState(x, y);
|
|
|
|
Gizmos.color = state == GridCellState.Occupied ? occupiedCellColor : emptyCellColor;
|
|
Gizmos.DrawCube(cellCenter, cellSizeVec);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 选中时绘制更明显的网格边界
|
|
/// </summary>
|
|
private void OnDrawGizmosSelected()
|
|
{
|
|
if (!showGizmos) return;
|
|
|
|
// 使用当前Inspector中的参数或已初始化的参数
|
|
int drawWidth = _isInitialized ? Width : width;
|
|
int drawHeight = _isInitialized ? Height : height;
|
|
float drawCellSize = _isInitialized ? CellSize : cellSize;
|
|
Vector3 drawOrigin = _isInitialized ? Origin : 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);
|
|
}
|
|
}
|
|
}
|
|
|