方块拼图

This commit is contained in:
2025-11-27 18:14:24 +08:00
parent 76809a829e
commit 06a68cda8e
31 changed files with 2262 additions and 44 deletions
@@ -0,0 +1,139 @@
using System;
namespace AibisDream
{
/// <summary>
/// 游戏状态
/// </summary>
public enum GameState
{
NotStarted, // 未开始
Playing, // 游戏中
Paused, // 暂停
GameOver // 游戏结束
}
/// <summary>
/// 游戏逻辑接口
/// 负责管理游戏的整体流程和状态
/// </summary>
public interface IBlockPuzzleGameLogic
{
/// <summary>
/// 当前游戏状态
/// </summary>
GameState CurrentState { get; }
/// <summary>
/// 当前分数(已放置的格子数量)
/// </summary>
int Score { get; }
/// <summary>
/// 当前选中的形状
/// </summary>
IBlockShape CurrentShape { get; }
/// <summary>
/// 网格系统
/// </summary>
IBlockPuzzleGrid Grid { get; }
/// <summary>
/// 放置验证器
/// </summary>
IPlacementValidator Validator { get; }
/// <summary>
/// 游戏开始事件
/// </summary>
event Action OnGameStart;
/// <summary>
/// 游戏结束事件
/// </summary>
event Action OnGameOver;
/// <summary>
/// 形状放置成功事件
/// </summary>
event Action<IBlockShape, int, int> OnShapePlaced;
/// <summary>
/// 形状放置失败事件
/// </summary>
event Action<IBlockShape, PlacementResult> OnShapePlaceFailed;
/// <summary>
/// 分数变化事件
/// </summary>
event Action<int> OnScoreChanged;
/// <summary>
/// 初始化游戏
/// </summary>
/// <param name="gridWidth">网格宽度</param>
/// <param name="gridHeight">网格高度</param>
void InitializeGame(int gridWidth, int gridHeight);
/// <summary>
/// 开始游戏
/// </summary>
void StartGame();
/// <summary>
/// 暂停游戏
/// </summary>
void PauseGame();
/// <summary>
/// 继续游戏
/// </summary>
void ResumeGame();
/// <summary>
/// 结束游戏
/// </summary>
void EndGame();
/// <summary>
/// 重置游戏
/// </summary>
void ResetGame();
/// <summary>
/// 选择形状
/// </summary>
/// <param name="shape">要选择的形状</param>
void SelectShape(IBlockShape shape);
/// <summary>
/// 尝试放置当前选中的形状到指定位置
/// </summary>
/// <param name="gridX">网格X坐标</param>
/// <param name="gridY">网格Y坐标</param>
/// <returns>是否放置成功</returns>
bool TryPlaceShape(int gridX, int gridY);
/// <summary>
/// 旋转当前选中的形状
/// </summary>
/// <param name="angle">旋转角度</param>
void RotateCurrentShape(RotationAngle angle);
/// <summary>
/// 检查是否还有可放置的形状
/// </summary>
/// <param name="availableShapes">可用的形状列表</param>
/// <returns>是否还有可放置的形状</returns>
bool HasPlaceableShapes(IBlockShape[] availableShapes);
/// <summary>
/// 获取下一个可用的形状
/// </summary>
/// <param name="shapePool">形状池</param>
/// <returns>下一个形状,如果没有则返回null</returns>
IBlockShape GetNextShape(IBlockShape[] shapePool);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4603b37a885792d4b85d6d5d392d4862
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,128 @@
using UnityEngine;
namespace AibisDream
{
/// <summary>
/// 网格单元格状态
/// </summary>
public enum GridCellState
{
Empty = 0, // 空
Occupied = 1 // 已占用
}
/// <summary>
/// 游戏网格系统接口(整个网格)
/// 负责管理整个游戏网格的状态和操作,包括:
/// - 网格的整体尺寸和配置
/// - 所有单元格的状态管理
/// - 坐标转换(世界坐标 ↔ 网格坐标)
/// - 网格级别的操作(清空、统计等)
///
/// 注意:单个单元格(Cell)通过坐标访问,没有独立接口
/// </summary>
public interface IBlockPuzzleGrid
{
/// <summary>
/// 网格宽度
/// </summary>
int Width { get; }
/// <summary>
/// 网格高度
/// </summary>
int Height { get; }
/// <summary>
/// 网格单元格大小(世界单位)
/// </summary>
float CellSize { get; }
/// <summary>
/// 网格原点位置(世界坐标)
/// </summary>
Vector3 Origin { get; }
/// <summary>
/// 初始化网格
/// </summary>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <param name="cellSize">单元格大小</param>
/// <param name="origin">原点位置</param>
void Initialize(int width, int height, float cellSize, Vector3 origin);
/// <summary>
/// 获取指定位置的单元格状态
/// </summary>
/// <param name="x">网格X坐标</param>
/// <param name="y">网格Y坐标</param>
/// <returns>单元格状态</returns>
GridCellState GetCellState(int x, int y);
/// <summary>
/// 设置指定位置的单元格状态
/// </summary>
/// <param name="x">网格X坐标</param>
/// <param name="y">网格Y坐标</param>
/// <param name="state">单元格状态</param>
void SetCellState(int x, int y, GridCellState state);
/// <summary>
/// 检查指定位置是否在网格范围内
/// </summary>
/// <param name="x">网格X坐标</param>
/// <param name="y">网格Y坐标</param>
/// <returns>是否在范围内</returns>
bool IsValidPosition(int x, int y);
/// <summary>
/// 检查指定位置是否为空
/// </summary>
/// <param name="x">网格X坐标</param>
/// <param name="y">网格Y坐标</param>
/// <returns>是否为空</returns>
bool IsCellEmpty(int x, int y);
/// <summary>
/// 世界坐标转换为网格坐标
/// </summary>
/// <param name="worldPos">世界坐标</param>
/// <param name="gridX">输出的网格X坐标</param>
/// <param name="gridY">输出的网格Y坐标</param>
/// <returns>是否转换成功</returns>
bool WorldToGrid(Vector3 worldPos, out int gridX, out int gridY);
/// <summary>
/// 网格坐标转换为世界坐标
/// </summary>
/// <param name="gridX">网格X坐标</param>
/// <param name="gridY">网格Y坐标</param>
/// <returns>世界坐标</returns>
Vector3 GridToWorld(int gridX, int gridY);
/// <summary>
/// 清空整个网格
/// </summary>
void Clear();
/// <summary>
/// 获取已占用的单元格数量
/// </summary>
/// <returns>已占用的单元格数量</returns>
int GetOccupiedCount();
/// <summary>
/// 获取总单元格数量
/// </summary>
/// <returns>总单元格数量</returns>
int GetTotalCellCount();
/// <summary>
/// 获取网格顶点信息
/// </summary>
/// <returns>网格四个顶点位置</returns>
Vector3[] GridVerticesToWorld(int x, int y);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 44bbdf523b438ef4aa34868e92b91aed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,106 @@
using UnityEngine;
namespace AibisDream
{
/// <summary>
/// 形状旋转角度
/// </summary>
public enum RotationAngle
{
Rotate0 = 0, // 0度
Rotate90 = 90, // 90度
Rotate180 = 180, // 180度
Rotate270 = 270 // 270度
}
/// <summary>
/// 形状块接口
/// 负责管理形状的数据和操作
/// </summary>
public interface IBlockShape
{
/// <summary>
/// 形状的唯一ID
/// </summary>
int ShapeId { get; }
/// <summary>
/// 形状名称
/// </summary>
string ShapeName { get; }
/// <summary>
/// 当前旋转角度
/// </summary>
RotationAngle CurrentRotation { get; }
/// <summary>
/// 获取当前形状的宽度(考虑旋转)
/// </summary>
int Width { get; }
/// <summary>
/// 获取当前形状的高度(考虑旋转)
/// </summary>
int Height { get; }
/// <summary>
/// 获取形状占用的格子数量
/// </summary>
int BlockCount { get; }
/// <summary>
/// 获取原始形状模式(未旋转)
/// </summary>
/// <returns>二维数组,1表示有格子,0表示空</returns>
int[,] GetOriginalPattern();
/// <summary>
/// 获取当前形状模式(考虑旋转)
/// </summary>
/// <returns>二维数组,1表示有格子,0表示空</returns>
int[,] GetCurrentPattern();
/// <summary>
/// 旋转形状
/// </summary>
/// <param name="angle">旋转角度</param>
void Rotate(RotationAngle angle);
/// <summary>
/// 顺时针旋转90度
/// </summary>
void RotateClockwise();
/// <summary>
/// 逆时针旋转90度
/// </summary>
void RotateCounterClockwise();
/// <summary>
/// 重置旋转角度为0
/// </summary>
void ResetRotation();
/// <summary>
/// 检查指定位置是否有格子
/// </summary>
/// <param name="x">形状内的X坐标(相对坐标)</param>
/// <param name="y">形状内的Y坐标(相对坐标)</param>
/// <returns>是否有格子</returns>
bool HasBlockAt(int x, int y);
/// <summary>
/// 获取形状的所有格子位置(相对坐标)
/// </summary>
/// <returns>格子位置列表</returns>
Vector2Int[] GetBlockPositions();
/// <summary>
/// 创建形状的副本
/// </summary>
/// <returns>形状副本</returns>
// IBlockShape Clone();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b3b17304622be4e46b270e3d475b1300
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,105 @@
using UnityEngine;
using System;
namespace AibisDream
{
/// <summary>
/// 拖拽状态
/// </summary>
public enum DragState
{
Idle, // 空闲
Dragging, // 拖拽中
Snapping, // 吸附中
Placed // 已放置
}
/// <summary>
/// 形状拖拽接口
/// 负责处理形状的拖拽、吸附和放置逻辑
/// </summary>
public interface IBlockShapeDragger
{
/// <summary>
/// 当前拖拽状态
/// </summary>
DragState CurrentState { get; }
/// <summary>
/// 是否可拖拽
/// </summary>
bool IsDraggable { get; set; }
/// <summary>
/// 目标网格
/// </summary>
IBlockPuzzleGrid TargetGrid { get; set; }
/// <summary>
/// 吸附距离阈值
/// </summary>
float SnapDistance { get; set; }
/// <summary>
/// 拖拽开始事件
/// </summary>
event Action<IBlockShape> OnDragStart;
/// <summary>
/// 拖拽更新事件
/// </summary>
event Action<IBlockShape, Vector3> OnDragUpdate;
/// <summary>
/// 拖拽结束事件
/// </summary>
event Action<IBlockShape, bool> OnDragEnd; // bool表示是否成功放置
/// <summary>
/// 吸附事件
/// </summary>
event Action<IBlockShape, Vector3, int, int> OnSnap; // 形状, 位置, 网格X, 网格Y
/// <summary>
/// 取消吸附事件
/// </summary>
event Action<IBlockShape> OnUnsnap;
/// <summary>
/// 开始拖拽
/// </summary>
void StartDrag();
/// <summary>
/// 更新拖拽位置
/// </summary>
void UpdateDrag();
/// <summary>
/// 结束拖拽
/// </summary>
void EndDrag();
/// <summary>
/// 取消拖拽(返回原位置)
/// </summary>
void CancelDrag();
/// <summary>
/// 检查是否可以放置到指定位置
/// </summary>
/// <param name="gridX">网格X坐标</param>
/// <param name="gridY">网格Y坐标</param>
/// <returns>是否可以放置</returns>
bool CanPlaceAt(int gridX, int gridY);
/// <summary>
/// 获取当前吸附的网格坐标
/// </summary>
/// <param name="gridX">输出的网格X坐标</param>
/// <param name="gridY">输出的网格Y坐标</param>
/// <returns>是否正在吸附</returns>
bool GetSnapGridPosition(out int gridX, out int gridY);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5b2cbf04f1d9ef6448d01501a7861a46
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,57 @@
namespace AibisDream
{
/// <summary>
/// 形状工厂接口
/// 负责创建和管理形状对象
/// </summary>
public interface IBlockShapeFactory
{
/// <summary>
/// 创建指定ID的形状
/// </summary>
/// <param name="shapeId">形状ID</param>
/// <returns>形状对象,如果ID不存在则返回null</returns>
IBlockShape CreateShape(int shapeId);
/// <summary>
/// 创建指定名称的形状
/// </summary>
/// <param name="shapeName">形状名称</param>
/// <returns>形状对象,如果名称不存在则返回null</returns>
IBlockShape CreateShape(string shapeName);
/// <summary>
/// 创建随机形状
/// </summary>
/// <returns>随机形状对象</returns>
IBlockShape CreateRandomShape();
/// <summary>
/// 获取所有可用的形状ID列表
/// </summary>
/// <returns>形状ID数组</returns>
int[] GetAllShapeIds();
/// <summary>
/// 获取所有可用的形状名称列表
/// </summary>
/// <returns>形状名称数组</returns>
string[] GetAllShapeNames();
/// <summary>
/// 注册新形状
/// </summary>
/// <param name="shapeId">形状ID</param>
/// <param name="shapeName">形状名称</param>
/// <param name="pattern">形状模式(二维数组)</param>
void RegisterShape(int shapeId, string shapeName, int[,] pattern);
/// <summary>
/// 检查形状ID是否存在
/// </summary>
/// <param name="shapeId">形状ID</param>
/// <returns>是否存在</returns>
bool HasShape(int shapeId);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 735c986ae1357ab489f5a5951ffb4bde
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,50 @@
namespace AibisDream
{
/// <summary>
/// 放置验证结果
/// </summary>
public enum PlacementResult
{
Success, // 可以放置
OutOfBounds, // 超出边界
Overlap, // 与已有块重叠
InvalidPosition // 无效位置
}
/// <summary>
/// 放置检测接口
/// 负责验证形状是否可以放置在指定位置
/// </summary>
public interface IPlacementValidator
{
/// <summary>
/// 检查形状是否可以放置在指定位置
/// </summary>
/// <param name="grid">网格系统</param>
/// <param name="shape">要放置的形状</param>
/// <param name="gridX">网格X坐标(形状左下角位置)</param>
/// <param name="gridY">网格Y坐标(形状左下角位置)</param>
/// <returns>放置验证结果</returns>
PlacementResult CanPlace(IBlockPuzzleGrid grid, IBlockShape shape, int gridX, int gridY);
/// <summary>
/// 检查形状是否可以放置在指定位置(详细版本)
/// </summary>
/// <param name="grid">网格系统</param>
/// <param name="shape">要放置的形状</param>
/// <param name="gridX">网格X坐标(形状左下角位置)</param>
/// <param name="gridY">网格Y坐标(形状左下角位置)</param>
/// <param name="failureReason">失败原因(如果返回false</param>
/// <returns>是否可以放置</returns>
bool CanPlaceDetailed(IBlockPuzzleGrid grid, IBlockShape shape, int gridX, int gridY, out PlacementResult failureReason);
/// <summary>
/// 获取形状在指定位置的所有占用格子坐标
/// </summary>
/// <param name="shape">形状</param>
/// <param name="gridX">网格X坐标(形状左下角位置)</param>
/// <param name="gridY">网格Y坐标(形状左下角位置)</param>
/// <returns>占用格子的网格坐标数组</returns>
(int x, int y)[] GetOccupiedCells(IBlockShape shape, int gridX, int gridY);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e4ebc4e9f404ead41ac713a7a31fe330
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: