Files
aibis-dream/Assets/Scripts/MiniGame/BlockPuzzle/Class/ShapeDragger.cs
T

191 lines
5.9 KiB
C#

using System;
using AibisDream.Framework;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Rendering;
namespace AibisDream
{
public class ShapeDragger : MonoBehaviour, IBlockShapeDragger, IInteraction
{
#region 编辑器字段
[SerializeField] private bool isDraggable = true;
[SerializeField] private int dragLayerId;
[SerializeField] private int dragLayerOrder;
[SerializeField] private int idleLayerId;
[SerializeField] private int idleLayerOrder;
#endregion
// 拖拽状态
private DragState _currentState = DragState.Placed;
public DragState CurrentState
{
get => _currentState;
set
{
if (value == _currentState) return;
// 处理状态切换
HandleStateChange(value);
_currentState = value;
}
}
private SnapResult _snapResult;
// 组件引用
private BlockShape _blockShape;
private EventTriggerEx _eventTrigger;
public bool IsDraggable { get => isDraggable; set => isDraggable = value; }
public IBlockPuzzleGrid TargetGrid => BlockPuzzleSystem.Instance.grid;
public IBlockShape BlockShape => _blockShape;
// 事件
public event Action<IBlockShape> OnDragStart;
public event Action<IBlockShape> OnDragUpdate;
public event Action<IBlockShape, bool> OnDragEnd;
private void Awake()
{
_blockShape = GetComponent<BlockShape>();
_eventTrigger = GetComponent<EventTriggerEx>();
RegisterEvent();
}
private void OnDestroy()
{
_eventTrigger.UnRegister(EventTriggerType.PointerClick, OnPointerClick);
}
private void RegisterEvent()
{
_eventTrigger.Register(EventTriggerType.PointerClick, OnPointerClick);
// _eventTrigger.Register(EventTriggerType.PointerDown, OnPointerDown);
// _eventTrigger.Register(EventTriggerType.PointerUp, OnPointerUp);
}
private void Update()
{
if (CurrentState == DragState.Dragging)
{
UpdateDrag();
}
}
private void OnPointerClick(BaseEventData eventData)
{
if (eventData is not PointerEventData { button: PointerEventData.InputButton.Left })
{
return;
}
// 如果当前物体不在拖拽中则进入拖拽逻辑
if (CurrentState == DragState.Idle || CurrentState == DragState.Placed)
{
StartDrag();
}
// 如果当前物体在拖拽中则取消拖拽
else
{
EndDrag();
}
}
public void StartDrag()
{
if (!isDraggable) return;
// 如果原本就在网格中,则先移除
TargetGrid?.TryRemoveShapeFromGrid(_blockShape);
TargetGrid?.ResetPreviewGrid();
CurrentState = DragState.Dragging;
OnDragStart?.Invoke(_blockShape);
}
public void EndDrag()
{
// 先吸附到回收槽
var recycled = BlockPuzzleSystem.Instance.TrySnapToRecycleSlot(_blockShape);
if (recycled)
{
CurrentState = DragState.Idle;
_snapResult = SnapResult.RecycleResult;
TargetGrid.ShowSnapPreview(_snapResult);
OnDragEnd?.Invoke(_blockShape, CurrentState == DragState.Placed);
return;
}
// 再吸附到网格
TargetGrid?.ResetPreviewGrid();
if (_snapResult.canSnap)
{
CurrentState = DragState.Placed;
transform.localScale = Vector3.one;
TargetGrid.TrySnapToGrid(_blockShape, _snapResult.RootCell);
// 处理Cursor
_eventTrigger.OnPointerUp(null);
OnDragEnd?.Invoke(_blockShape, CurrentState == DragState.Placed);
}
// TODO: 都没吸附到,则恢复原位
TargetGrid.GridVisualizer.UpdateAllCellsVisual();
}
public void UpdateDrag()
{
// 检测右键点击进行旋转(仅在拖动中)
if (Input.GetMouseButtonDown(1)) // 1 = 右键
{
_blockShape.RotateClockwise();
}
// 更新拖拽位置
transform.position = GetMouseWorldPosition() - _blockShape.GetCenterPosition();
// 进行Snap检查
_snapResult = TargetGrid.CheckSnapToGrid(_blockShape);
// 在网格显示预览
TargetGrid.ShowSnapPreview(_snapResult);
OnDragUpdate?.Invoke(_blockShape);
}
private void HandleStateChange(DragState newState)
{
var sortingGroup = _blockShape?.SortingGroup;
if (sortingGroup == null) return;
switch (newState)
{
case DragState.Idle:
case DragState.Dragging:
sortingGroup.sortingOrder = dragLayerOrder;
sortingGroup.sortingLayerID = dragLayerId;
break;
case DragState.Placed:
sortingGroup.sortingOrder = idleLayerOrder;
sortingGroup.sortingLayerID = idleLayerId;
break;
}
}
private Vector3 GetMouseWorldPosition()
{
var mouseWorldPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
return new Vector3(mouseWorldPos.x, mouseWorldPos.y, 0);
}
// 实现IInteraction接口
public bool IsActive => true;
public bool IsAvailable => true;
public GameObject GetGameObject() => gameObject;
}
}