296 lines
9.4 KiB
C#
296 lines
9.4 KiB
C#
using System;
|
||
using System.Collections;
|
||
using AibisDream.Framework;
|
||
using UnityEngine;
|
||
using UnityEngine.EventSystems;
|
||
|
||
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;
|
||
|
||
[Header("长按设置")]
|
||
[SerializeField] private float longPressDuration = 0.65f;
|
||
[SerializeField] private float longPressScale = 1.1f;
|
||
[SerializeField] private float shakeIntensity = 0.1f;
|
||
#endregion
|
||
|
||
// 拖拽状态
|
||
private DragState _currentState = DragState.Placed;
|
||
public DragState CurrentState
|
||
{
|
||
get => _currentState;
|
||
set
|
||
{
|
||
if (value == _currentState) return;
|
||
// 处理状态切换
|
||
HandleStateChange(value);
|
||
_currentState = value;
|
||
}
|
||
}
|
||
private SnapResult _snapResult;
|
||
|
||
// 长按相关状态
|
||
private bool _isPressing;
|
||
private bool _isLongPressTriggered;
|
||
private Coroutine _longPressCoroutine;
|
||
private Vector3 _originalScale;
|
||
private Vector3 _originalPosition;
|
||
|
||
// 组件引用
|
||
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.PointerDown, OnPointerDown);
|
||
_eventTrigger.UnRegister(EventTriggerType.PointerUp, OnPointerUp);
|
||
_eventTrigger.UnRegister(EventTriggerType.PointerClick, OnPointerClick);
|
||
|
||
// 清理协程
|
||
if (_longPressCoroutine != null)
|
||
{
|
||
StopCoroutine(_longPressCoroutine);
|
||
_longPressCoroutine = null;
|
||
}
|
||
}
|
||
|
||
private void RegisterEvent()
|
||
{
|
||
_eventTrigger.Register(EventTriggerType.PointerDown, OnPointerDown);
|
||
_eventTrigger.Register(EventTriggerType.PointerUp, OnPointerUp);
|
||
_eventTrigger.Register(EventTriggerType.PointerClick, OnPointerClick);
|
||
}
|
||
|
||
private void Update()
|
||
{
|
||
if (CurrentState == DragState.Dragging)
|
||
{
|
||
UpdateDrag();
|
||
}
|
||
}
|
||
|
||
private void OnPointerDown(BaseEventData eventData)
|
||
{
|
||
if (eventData is not PointerEventData { button: PointerEventData.InputButton.Left })
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (!isDraggable) return;
|
||
|
||
// 只有在静止状态才能开始长按
|
||
if (CurrentState == DragState.Idle || CurrentState == DragState.Placed)
|
||
{
|
||
_isPressing = true;
|
||
_isLongPressTriggered = false;
|
||
_longPressCoroutine = StartCoroutine(LongPressCoroutine());
|
||
}
|
||
}
|
||
|
||
private void OnPointerUp(BaseEventData eventData)
|
||
{
|
||
if (eventData is not PointerEventData { button: PointerEventData.InputButton.Left })
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 如果还在长按过程中(未完成),则取消
|
||
if (_isPressing && !_isLongPressTriggered)
|
||
{
|
||
CancelLongPress();
|
||
}
|
||
}
|
||
|
||
private void OnPointerClick(BaseEventData eventData)
|
||
{
|
||
if (eventData is not PointerEventData { button: PointerEventData.InputButton.Left })
|
||
{
|
||
return;
|
||
}
|
||
|
||
// 只有在拖拽中点击才结束拖拽
|
||
if (CurrentState == DragState.Dragging && _isLongPressTriggered)
|
||
{
|
||
EndDrag();
|
||
}
|
||
}
|
||
|
||
public void StartDrag()
|
||
{
|
||
if (!isDraggable) return;
|
||
|
||
// 如果原本就在网格中,则先移除
|
||
TargetGrid?.TryRemoveShapeFromGrid(_blockShape);
|
||
TargetGrid?.ResetPreviewGrid();
|
||
|
||
CurrentState = DragState.Dragging;
|
||
|
||
OnDragStart?.Invoke(_blockShape);
|
||
}
|
||
|
||
public void EndDrag()
|
||
{
|
||
// 清理长按状态
|
||
CancelLongPress();
|
||
|
||
// 先吸附到回收槽
|
||
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);
|
||
}
|
||
else
|
||
{
|
||
// 都没吸附到,恢复原状态和缩放
|
||
transform.localScale = Vector3.one;
|
||
}
|
||
|
||
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);
|
||
}
|
||
|
||
private IEnumerator LongPressCoroutine()
|
||
{
|
||
float elapsed = 0f;
|
||
_originalScale = transform.localScale;
|
||
_originalPosition = transform.localPosition;
|
||
|
||
while (elapsed < longPressDuration)
|
||
{
|
||
elapsed += Time.deltaTime;
|
||
float progress = elapsed / longPressDuration;
|
||
|
||
// 抖动效果(轻微)
|
||
float shake = Mathf.Sin(elapsed * 30f) * shakeIntensity * progress;
|
||
transform.localPosition = _originalPosition + Vector3.right * shake;
|
||
|
||
// 放大效果(缓慢 EaseOut)
|
||
float scale = Mathf.Lerp(1f, longPressScale, EaseOutQuad(progress));
|
||
transform.localScale = _originalScale * scale;
|
||
|
||
yield return null;
|
||
}
|
||
|
||
// 完成长按,开始拖拽
|
||
_isLongPressTriggered = true;
|
||
StartDrag();
|
||
}
|
||
|
||
private float EaseOutQuad(float t)
|
||
{
|
||
return t * (2f - t);
|
||
}
|
||
|
||
private void CancelLongPress()
|
||
{
|
||
if (_longPressCoroutine != null)
|
||
{
|
||
StopCoroutine(_longPressCoroutine);
|
||
_longPressCoroutine = null;
|
||
}
|
||
|
||
// 恢复原始状态
|
||
if (_isPressing && !_isLongPressTriggered)
|
||
{
|
||
transform.localScale = _originalScale;
|
||
transform.localPosition = _originalPosition;
|
||
}
|
||
|
||
_isPressing = false;
|
||
_isLongPressTriggered = false;
|
||
}
|
||
|
||
// 实现IInteraction接口
|
||
public bool IsActive => true;
|
||
public bool IsAvailable => true;
|
||
public GameObject GetGameObject() => gameObject;
|
||
}
|
||
}
|