方块系统
This commit is contained in:
@@ -129,6 +129,26 @@ namespace AibisDream
|
||||
return IsValidPosition(x, y) && GetCellState(x, y) == GridCellState.Empty;
|
||||
}
|
||||
|
||||
public bool CanPlace(Vector2Int[] gridCells, out bool[] results)
|
||||
{
|
||||
results = new bool[gridCells.Length];
|
||||
for (int i = 0; i < gridCells.Length; i++)
|
||||
{
|
||||
// 先验证是否在有效范围内
|
||||
if (!IsValidPosition(gridCells[i].x, gridCells[i].y)) results[i] = false;
|
||||
// 再验证是否为空
|
||||
else if (GetCellState(gridCells[i].x, gridCells[i].y) == GridCellState.Occupied) results[i] = false;
|
||||
else results[i] = true;
|
||||
}
|
||||
|
||||
// 如果所有位置都可以放置,则返回true
|
||||
for (int i = 0; i < results.Length; i++)
|
||||
{
|
||||
if (!results[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool WorldToGrid(Vector3 worldPos, out int gridX, out int gridY)
|
||||
{
|
||||
if (!_isInitialized)
|
||||
@@ -142,11 +162,11 @@ namespace AibisDream
|
||||
gridX = Mathf.FloorToInt(localPos.x / CellSize);
|
||||
gridY = Mathf.FloorToInt(localPos.y / CellSize);
|
||||
|
||||
// 检查是否在有效范围内
|
||||
if (!IsValidPosition(gridX, gridY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// TODO: 不检查是否在有效范围内,留给后续检查
|
||||
// if (!IsValidPosition(gridX, gridY))
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public static class BlockPuzzleGridEx
|
||||
{
|
||||
public static SnapResult TrySnapToGrid(this IBlockPuzzleGrid grid, BlockShape shape)
|
||||
{
|
||||
// 预制错误结果作为返回值
|
||||
SnapResult result = new SnapResult
|
||||
{
|
||||
canSnap = false,
|
||||
snapPosition = shape.transform.position,
|
||||
gridX = 0,
|
||||
gridY = 0,
|
||||
distance = float.MaxValue
|
||||
};
|
||||
|
||||
// 将Shape的世界坐标转换为网格坐标(可以是虚拟坐标)
|
||||
bool inGrid = grid.WorldToGrid(shape.transform.position, out int gridX, out int gridY);
|
||||
if (!inGrid) return result;
|
||||
|
||||
// 将形状的所有格子转换为网格坐标
|
||||
// gridX, gridY 是形状的 (0, 0) 点在网格中的位置
|
||||
Vector2Int[] gridCells = ConvertShapeToGridCells(shape, gridX, gridY);
|
||||
result.gridX = gridX;
|
||||
result.gridY = gridY;
|
||||
result.snapPosition = grid.GridToWorld(gridX, gridY);
|
||||
|
||||
// 逐个坐标验证是否可以放置
|
||||
var canPlace = grid.CanPlace(gridCells, out bool[] results);
|
||||
if (!canPlace) return result;
|
||||
result.canSnap = true;
|
||||
result.distance = Vector3.Distance(shape.transform.position, result.snapPosition);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将形状的相对坐标转换为网格坐标
|
||||
/// 已知形状的 (0, 0) 点在网格中的位置为 (gridX, gridY),将形状的其他格子坐标转换为网格坐标
|
||||
/// </summary>
|
||||
/// <param name="shape">形状</param>
|
||||
/// <param name="gridX">网格X坐标(形状左下角位置,即形状的 (0, 0) 点对应的网格坐标)</param>
|
||||
/// <param name="gridY">网格Y坐标(形状左下角位置,即形状的 (0, 0) 点对应的网格坐标)</param>
|
||||
/// <returns>形状所有格子在网格中的坐标数组</returns>
|
||||
public static Vector2Int[] ConvertShapeToGridCells(IBlockShape shape, int gridX, int gridY)
|
||||
{
|
||||
if (shape == null)
|
||||
{
|
||||
return new Vector2Int[0];
|
||||
}
|
||||
|
||||
Vector2Int[] blockPositions = shape.GetBlockPositions();
|
||||
if (blockPositions == null || blockPositions.Length == 0)
|
||||
{
|
||||
return new Vector2Int[0];
|
||||
}
|
||||
|
||||
Vector2Int[] gridCells = new Vector2Int[blockPositions.Length];
|
||||
|
||||
for (int i = 0; i < blockPositions.Length; i++)
|
||||
{
|
||||
// 将形状的相对坐标转换为网格坐标
|
||||
// 形状的 (0, 0) 对应网格的 (gridX, gridY)
|
||||
// 形状的 (blockPos.x, blockPos.y) 对应网格的 (gridX + blockPos.x, gridY + blockPos.y)
|
||||
gridCells[i] = new Vector2Int(
|
||||
gridX + blockPositions[i].x,
|
||||
gridY + blockPositions[i].y
|
||||
);
|
||||
}
|
||||
|
||||
return gridCells;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab4b77b210903a6428113bbc4e0fac09
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -127,39 +127,18 @@ namespace AibisDream
|
||||
Vector3 mouseWorldPos = GetMouseWorldPosition(Input.mousePosition);
|
||||
Vector3 targetPosition = mouseWorldPos + _dragOffset;
|
||||
|
||||
// 检测是否靠近网格
|
||||
if (targetGrid != null)
|
||||
{
|
||||
bool canSnap = CheckSnapToGrid(targetPosition, out Vector3 snapPos, out int gridX, out int gridY);
|
||||
|
||||
if (canSnap)
|
||||
// 检查吸附可能
|
||||
var snapResult = targetGrid.TrySnapToGrid(_blockShape);
|
||||
if (snapResult.canSnap)
|
||||
{
|
||||
// 吸附到网格
|
||||
transform.position = snapPos;
|
||||
_isSnapping = true;
|
||||
_snapGridX = gridX;
|
||||
_snapGridY = gridY;
|
||||
_currentState = DragState.Snapping;
|
||||
|
||||
// 重要:更新拖拽偏移量,使鼠标继续移动时能正确计算位置
|
||||
_dragOffset = snapPos - mouseWorldPos;
|
||||
|
||||
// 检查是否可以放置
|
||||
bool canPlace = CanPlaceAt(gridX, gridY);
|
||||
ShowSnapPreview(true, canPlace);
|
||||
|
||||
OnSnap?.Invoke(_blockShape, snapPos, gridX, gridY);
|
||||
// 可以吸附,保存吸附内容
|
||||
}
|
||||
else
|
||||
{
|
||||
// 自由拖拽
|
||||
// 没有吸附,自由拖拽
|
||||
transform.position = targetPosition;
|
||||
if (_isSnapping)
|
||||
{
|
||||
_isSnapping = false;
|
||||
ShowSnapPreview(false, false);
|
||||
OnUnsnap?.Invoke(_blockShape);
|
||||
}
|
||||
_currentState = DragState.Dragging;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,17 +109,19 @@ namespace AibisDream
|
||||
|
||||
return occupiedCells.ToArray();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 吸附检测结果
|
||||
/// 将形状的单个相对坐标转换为网格坐标
|
||||
/// </summary>
|
||||
public struct SnapResult
|
||||
/// <param name="shapeLocalX">形状内的X坐标(相对坐标,相对于形状左下角)</param>
|
||||
/// <param name="shapeLocalY">形状内的Y坐标(相对坐标,相对于形状左下角)</param>
|
||||
/// <param name="gridX">网格X坐标(形状左下角位置)</param>
|
||||
/// <param name="gridY">网格Y坐标(形状左下角位置)</param>
|
||||
/// <returns>对应的网格坐标</returns>
|
||||
public static Vector2Int ConvertShapeLocalToGrid(int shapeLocalX, int shapeLocalY, int gridX, int gridY)
|
||||
{
|
||||
public bool canSnap; // 是否可以吸附
|
||||
public Vector3 snapPosition; // 吸附后的世界坐标位置
|
||||
public int gridX; // 吸附到的网格X坐标(形状左下角位置)
|
||||
public int gridY; // 吸附到的网格Y坐标(形状左下角位置)
|
||||
public float distance; // 到网格单元格的距离
|
||||
return new Vector2Int(gridX + shapeLocalX, gridY + shapeLocalY);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -297,5 +299,17 @@ namespace AibisDream
|
||||
Overlap, // 与已有块重叠
|
||||
InvalidPosition // 无效位置
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 吸附检测结果
|
||||
/// </summary>
|
||||
public struct SnapResult
|
||||
{
|
||||
public bool canSnap; // 是否可以吸附
|
||||
public Vector3 snapPosition; // 吸附后的世界坐标位置
|
||||
public int gridX; // 吸附到的网格X坐标(形状左下角位置)
|
||||
public int gridY; // 吸附到的网格Y坐标(形状左下角位置)
|
||||
public float distance; // 到网格单元格的距离
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -84,6 +84,14 @@ namespace AibisDream
|
||||
/// <returns>是否为空</returns>
|
||||
bool IsCellEmpty(int x, int y);
|
||||
|
||||
/// <summary>
|
||||
/// 检查指定位置是否可以放置
|
||||
/// </summary>
|
||||
/// <param name="gridCells">网格坐标数组</param>
|
||||
/// <param name="results">结果集合</param>
|
||||
/// <returns>是否可以放置</returns>
|
||||
bool CanPlace(Vector2Int[] gridCells, out bool[] results);
|
||||
|
||||
/// <summary>
|
||||
/// 世界坐标转换为网格坐标
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user