484 lines
16 KiB
C#
484 lines
16 KiB
C#
using UnityEngine;
|
|
using AibisDream.Kit;
|
|
using AibisDream.Utility;
|
|
using System.Linq;
|
|
using System.Collections;
|
|
using AibisDream.Framework;
|
|
using AibisDream.FixSystem;
|
|
using UnityEngine.EventSystems;
|
|
|
|
namespace AibisDream
|
|
{
|
|
public class BlockPuzzleSystem : MonoBehaviour
|
|
{
|
|
[Header("物体索引")]
|
|
// 物体索引
|
|
[SerializeField] public BlockPuzzleGrid grid;
|
|
[SerializeField] private Transform shapeRoot;
|
|
[SerializeField] private ShapeRecycleSlot shapeRecycleSlot;
|
|
|
|
private BlockPuzzlePanel blockPuzzlePanel;
|
|
|
|
[Header("数据")]
|
|
[SerializeField] private BlockPuzzleData puzzleData;
|
|
[SerializeField] private bool initializeOnStart = true;
|
|
|
|
private BlockPuzzleValidator validator;
|
|
private ShapeFactory shapeFactory;
|
|
|
|
// 锁定状态
|
|
public bool IsLocked { get; private set; }
|
|
|
|
// 缓存当前的吸附结果(由DragUpdate更新)
|
|
private SnapResult _currentSnapResult;
|
|
|
|
private void Start()
|
|
{
|
|
FixSystemCenter.SystemDic.Register(this);
|
|
RepairSystemManager.Register(this);
|
|
blockPuzzlePanel = FixPanelSystem.GetRepairPanel<BlockPuzzlePanel>();
|
|
|
|
if (initializeOnStart)
|
|
{
|
|
Initialize();
|
|
}
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
FixSystemCenter.SystemDic.Unregister<BlockPuzzleSystem>();
|
|
}
|
|
|
|
public void Initialize(string puzzleName)
|
|
{
|
|
if (BlockPuzzleKit.TryLoadBlockPuzzleData(puzzleName, out var blockPuzzleData))
|
|
{
|
|
Initialize(blockPuzzleData);
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError($"加载 BlockPuzzleData 失败: {puzzleName}");
|
|
}
|
|
}
|
|
|
|
public void Initialize(BlockPuzzleData puzzleData)
|
|
{
|
|
this.puzzleData = puzzleData;
|
|
ClearGame();
|
|
Initialize();
|
|
}
|
|
|
|
public void Initialize()
|
|
{
|
|
float startTime = Time.realtimeSinceStartup;
|
|
|
|
// 初始化网格
|
|
grid.Initialize(puzzleData.gridWidth, puzzleData.gridHeight, puzzleData.cellSize);
|
|
|
|
// 批量预加载所有需要的BlockShapeData,避免循环中重复读取JSON文件
|
|
var shapeKeys = puzzleData.gridShapeDataInfos.Select(s => s.shapeKey).Distinct().ToArray();
|
|
var shapeDataDict = BlockPuzzleKit.LoadBlockShapeDataBatch(shapeKeys);
|
|
|
|
// 初始化网格上图形
|
|
shapeFactory = new ShapeFactory(shapeRoot);
|
|
foreach (var shapeData in puzzleData.gridShapeDataInfos)
|
|
{
|
|
// 使用预加载的数据创建形状,避免重复读取JSON
|
|
if (shapeDataDict.TryGetValue(shapeData.shapeKey, out var blockShapeData))
|
|
{
|
|
var shape = shapeFactory.CreateBlockShape(blockShapeData);
|
|
shape.Rotate(shapeData.rotationAngle);
|
|
grid.TrySnapToGrid(shape, shapeData.rootCell);
|
|
shape.ShapeDragger.InteractionMode = InteractionMode.Click;
|
|
}
|
|
}
|
|
grid.GridVisualizer.UpdateAllCellsVisual();
|
|
|
|
// 加载验证器
|
|
validator = ResourceKit.LoadAssetSync<BlockPuzzleValidator>(puzzleData.validatorName);
|
|
blockPuzzlePanel.SetProgressMaxValue(validator.CollectThresholds());
|
|
|
|
// 初始化侧边栏
|
|
var deviceDatas = BlockPuzzleKit.LoadBlockShapeDataBatch(puzzleData.shapeInRack);
|
|
blockPuzzlePanel.DeviceButtonDatas = deviceDatas.Values.ToArray();
|
|
|
|
|
|
// 组装事件逻辑
|
|
AssembleEventLogic();
|
|
|
|
// 初始化时验证一次
|
|
validator.Validate(grid.GetShapes());
|
|
|
|
// 确保交互状态正确
|
|
UpdateInteractionState();
|
|
}
|
|
|
|
private void SubmitGameResult()
|
|
{
|
|
// 检查系统是否锁定
|
|
if (IsLocked)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var validateResult = validator.Validate(grid.GetShapes());
|
|
var shapesInGrid = grid.GetShapes().Select(s => s.BlockShapeData.blockShapeInfo.shapeName).ToArray();
|
|
YarnVariableStorage.Instance.SetValue("$shapesInGrid", string.Join(",", shapesInGrid));
|
|
|
|
// 如果验证通过, 则设置变量并弹出对话
|
|
if (validateResult.isPass)
|
|
{
|
|
SingleCastEventSystem.Global.Trigger(DialogEventEnum.StartNode, "BlockPuzzlePass");
|
|
}
|
|
}
|
|
|
|
public void ClearGame()
|
|
{
|
|
grid.Clear();
|
|
shapeRoot.DestroyAllChildren();
|
|
// 重置锁定状态
|
|
SetLocked(false);
|
|
}
|
|
|
|
// --------------------- 锁定状态管理 -------------------
|
|
|
|
/// <summary>
|
|
/// 设置系统锁定状态
|
|
/// </summary>
|
|
/// <param name="locked">是否锁定</param>
|
|
public void SetLocked(bool locked)
|
|
{
|
|
IsLocked = locked;
|
|
UpdateInteractionState();
|
|
}
|
|
|
|
public IEnumerator LockSystem()
|
|
{
|
|
SetLocked(true);
|
|
yield return TimelineCenter.Instance.PlayTimelineAsync("卡扣/卡扣锁定");
|
|
}
|
|
|
|
public IEnumerator UnlockSystem()
|
|
{
|
|
yield return TimelineCenter.Instance.PlayTimelineAsync("卡扣/卡扣解锁");
|
|
SetLocked(false);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 更新所有交互组件的状态
|
|
/// </summary>
|
|
private void UpdateInteractionState()
|
|
{
|
|
// 更新所有形状的拖拽状态
|
|
if (shapeFactory != null)
|
|
{
|
|
shapeFactory.SetAllShapesInteractable(!IsLocked);
|
|
}
|
|
|
|
// 更新按钮的交互状态
|
|
if (blockPuzzlePanel != null)
|
|
{
|
|
if (blockPuzzlePanel.LockButton != null)
|
|
{
|
|
blockPuzzlePanel.LockButton.GetComponent<BlockSubmitHander>().SetLockedState(IsLocked);
|
|
}
|
|
if (blockPuzzlePanel.PopUpButton != null)
|
|
{
|
|
blockPuzzlePanel.PopUpButton.interactable = !IsLocked;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void EnableDrag()
|
|
{
|
|
shapeFactory.SetAllShapesInteractionMode(InteractionMode.Drag);
|
|
}
|
|
|
|
public void LoadShapeRack()
|
|
{
|
|
blockPuzzlePanel.LoadBackupDevices();
|
|
}
|
|
|
|
// --------------------- 维修面板同步 -------------------
|
|
|
|
private string selectedShapeName;
|
|
|
|
/// <summary>
|
|
/// 组装各系统之间相互逻辑
|
|
/// </summary>
|
|
private void AssembleEventLogic()
|
|
{
|
|
// 由面板触发
|
|
blockPuzzlePanel.OnDeviceSelected += OnPanelShapeSelected;
|
|
blockPuzzlePanel.OnSubmit.AddListener(SubmitGameResult);
|
|
blockPuzzlePanel.OnPopUp.AddListener(PopUpShape);
|
|
|
|
// 由Shape触发 - 使用新的事件系统
|
|
shapeFactory.OnDragStartDetailed += OnShapeDragStartDetailed;
|
|
shapeFactory.OnDragEndDetailed += OnShapeDragEndDetailed;
|
|
shapeFactory.OnDragUpdateDetailed += OnShapeDragUpdateDetailed;
|
|
shapeFactory.OnClick += OnShapeClick;
|
|
|
|
// 由系统触发
|
|
validator.OnValidate.AddListener(blockPuzzlePanel.SetVaildState);
|
|
validator.OnValidate.AddListener(blockPuzzlePanel.OnProgressChanged);
|
|
}
|
|
|
|
private void OnPanelShapeSelected(BlockShapeInfo shapeData)
|
|
{
|
|
// 在屏幕上更新选中的图形
|
|
selectedShapeName = shapeData.shapeName;
|
|
blockPuzzlePanel.ShowShapeInScreen(shapeData);
|
|
}
|
|
|
|
public void OnShapeClick(BlockShape blockShape)
|
|
{
|
|
// 点击形状
|
|
blockPuzzlePanel.ShowShapeInScreen(blockShape.BlockShapeData.blockShapeInfo);
|
|
// 播放事件节点
|
|
YarnVariableStorage.Instance.SetValue("$selectedShape", blockShape.BlockShapeData.blockShapeInfo.shapeName);
|
|
SingleCastEventSystem.Global.Trigger(DialogEventEnum.StartNode, "ShapeSelected");
|
|
}
|
|
|
|
#region 新的事件驱动处理器
|
|
|
|
private void OnShapeDragStartDetailed(object sender, DragStartEventArgs args)
|
|
{
|
|
var blockShape = args.Shape;
|
|
|
|
// 如果原本就在网格中,则先移除
|
|
grid.TryRemoveShapeFromGrid(blockShape);
|
|
grid.ResetPreviewGrid();
|
|
|
|
// 显示网格
|
|
grid.GridVisualizer.SetGridVisible(true);
|
|
|
|
// 显示Info
|
|
if (blockShape?.BlockShapeData.blockShapeInfo.shapeName != null)
|
|
{
|
|
blockPuzzlePanel.ShowShapeInScreen(blockShape.BlockShapeData.blockShapeInfo);
|
|
EventSystem.current.SetSelectedGameObject(null);
|
|
selectedShapeName = null;
|
|
}
|
|
|
|
// 回收抽屉高亮,半开
|
|
shapeRecycleSlot.PreRecycle();
|
|
shapeRecycleSlot.SetRecycleAvaliable(true);
|
|
|
|
// 每次拿起时也要校验
|
|
validator.Validate(grid.GetShapes());
|
|
}
|
|
|
|
private void OnShapeDragUpdateDetailed(object sender, DragUpdateEventArgs args)
|
|
{
|
|
var blockShape = args.Shape;
|
|
|
|
// 进行Snap检查并缓存结果
|
|
_currentSnapResult = grid.CheckSnapToGrid(blockShape);
|
|
args.CurrentSnapResult = _currentSnapResult;
|
|
|
|
// 在网格显示预览
|
|
grid.ShowSnapPreview(_currentSnapResult);
|
|
|
|
// 更新回收槽状态
|
|
shapeRecycleSlot.UpdateSlotState(blockShape);
|
|
}
|
|
|
|
private void OnShapeDragEndDetailed(object sender, DragEndEventArgs args)
|
|
{
|
|
// 隐藏网格
|
|
grid.GridVisualizer.SetGridVisible(false);
|
|
|
|
// 1. 首先尝试回收
|
|
if (TryHandleRecycle(args))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 2. 然后尝试吸附到网格
|
|
if (TryHandleGridSnap(args))
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 3. 都未处理,保持未处理状态
|
|
args.IsHandled = false;
|
|
args.ResultType = DragEndResultType.Dropped;
|
|
|
|
// 重置预览网格
|
|
grid.ResetPreviewGrid();
|
|
grid.GridVisualizer.UpdateAllCellsVisual();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 处理回收逻辑
|
|
/// </summary>
|
|
private bool TryHandleRecycle(DragEndEventArgs args)
|
|
{
|
|
if (shapeRecycleSlot.CurrentState != PositionState.Open)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 执行回收
|
|
shapeRecycleSlot.RecycleShape(args.Shape);
|
|
|
|
// 清空屏幕并切换回LogScreen
|
|
blockPuzzlePanel.ClearShapeInScreen();
|
|
blockPuzzlePanel.SwitchToLogScreen();
|
|
|
|
// 获取 Shape 名称
|
|
string shapeName = args.Shape.ShapeName;
|
|
|
|
// 检查是否在不添加按钮的列表中
|
|
bool shouldAddButton = puzzleData.recycleNoButtonShapes == null ||
|
|
!puzzleData.recycleNoButtonShapes.Contains(shapeName);
|
|
|
|
if (shouldAddButton)
|
|
{
|
|
// 向面板添加回收的形状
|
|
blockPuzzlePanel.OnDeviceRecycle(args.Shape);
|
|
}
|
|
else
|
|
{
|
|
SingleCastEventSystem.Global.Trigger(DialogEventEnum.StartNode, "ShapeRecycled");
|
|
}
|
|
|
|
// 更新事件参数 args.IsHandled = true;
|
|
args.FinalState = DragState.Idle;
|
|
args.ResultType = DragEndResultType.Recycled;
|
|
|
|
// 延时后进行销毁
|
|
ActionKit.Delay(1.0f, () => {
|
|
shapeFactory.RecycleBlockShape(args.Shape);
|
|
}).Start(this);
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 处理网格吸附逻辑
|
|
/// </summary>
|
|
private bool TryHandleGridSnap(DragEndEventArgs args)
|
|
{
|
|
// 使用缓存的snap结果或重新检测
|
|
var snapResult = _currentSnapResult;
|
|
if (!snapResult.canSnap)
|
|
{
|
|
snapResult = grid.CheckSnapToGrid(args.Shape);
|
|
}
|
|
|
|
if (!snapResult.canSnap)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// 执行网格吸附
|
|
grid.ResetPreviewGrid();
|
|
|
|
// 设置形状位置和状态
|
|
args.Shape.transform.position = grid.GridToWorld(snapResult.RootCell.x, snapResult.RootCell.y);
|
|
args.Shape.transform.localScale = Vector3.one;
|
|
|
|
// 更新网格状态
|
|
grid.TrySnapToGrid(args.Shape, snapResult.RootCell);
|
|
|
|
// 更新事件参数
|
|
args.IsHandled = true;
|
|
args.FinalState = DragState.Placed;
|
|
args.ResultType = DragEndResultType.SnappedToGrid;
|
|
|
|
// 验证放置
|
|
validator.Validate(grid.GetShapes());
|
|
|
|
// 处理Cursor
|
|
var eventTrigger = args.Shape.GetComponent<EventTriggerEx>();
|
|
eventTrigger?.OnPointerUp(null);
|
|
|
|
return true;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void PopUpShape()
|
|
{
|
|
// 检查系统是否锁定
|
|
if (IsLocked)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (selectedShapeName == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// 弹出形状
|
|
var blockShape = shapeFactory.CreateBlockShape(selectedShapeName);
|
|
shapeRecycleSlot.PopUpShape(blockShape);
|
|
blockShape.GetComponent<ShapeDragger>().CurrentState = DragState.Idle;
|
|
|
|
// 删除按钮
|
|
blockPuzzlePanel.RemoveDeviceButton(selectedShapeName);
|
|
selectedShapeName = null;
|
|
}
|
|
|
|
// ---------------- 编辑器状态逻辑 ----------------
|
|
|
|
/// <summary>
|
|
/// 仅加载配置项,不应用到游戏
|
|
/// </summary>
|
|
public void LoadConfig()
|
|
{
|
|
if (BlockPuzzleKit.TryLoadBlockPuzzleData(puzzleData.puzzleName, out var blockPuzzleData))
|
|
{
|
|
puzzleData = blockPuzzleData;
|
|
Debug.Log("加载配置项成功");
|
|
}
|
|
else
|
|
{
|
|
Debug.Log("加载配置项失败");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将配置项应用到编辑器
|
|
/// </summary>
|
|
public void ApplyConfig()
|
|
{
|
|
ClearGame();
|
|
|
|
shapeFactory = new ShapeFactory(shapeRoot);
|
|
grid.InitializeInEditor(puzzleData.gridWidth, puzzleData.gridHeight, puzzleData.cellSize);
|
|
// shapeRack.InitInEditor(puzzleData.shapeRackDataInfos);
|
|
|
|
foreach (var shapeData in puzzleData.gridShapeDataInfos)
|
|
{
|
|
var shape = shapeFactory.CreateBlockShape(shapeData.shapeKey);
|
|
shape.Rotate(shapeData.rotationAngle);
|
|
grid.TrySnapToGrid(shape, shapeData.rootCell);
|
|
}
|
|
}
|
|
|
|
public void SaveConfig()
|
|
{
|
|
var gridShapeDataInfos = grid.ShapeDict?.Values.ToArray();
|
|
// var shapeRackDataInfos = shapeRack.blockShapeDataList?.ToArray();
|
|
|
|
puzzleData.gridShapeDataInfos = gridShapeDataInfos;
|
|
// puzzleData.shapeRackDataInfos = shapeRackDataInfos;
|
|
|
|
BlockPuzzleKit.SaveBlockPuzzleData(puzzleData, puzzleData.puzzleName);
|
|
}
|
|
|
|
public void CreateShapeInEditor(string shapeKey)
|
|
{
|
|
if (shapeFactory == null)
|
|
{
|
|
shapeFactory = new ShapeFactory(shapeRoot);
|
|
}
|
|
shapeFactory.CreateBlockShape(shapeKey);
|
|
}
|
|
}
|
|
}
|