Files
aibis-dream/Assets/Scripts/MiniGame/BlockPuzzle/Class/ShapeDragger.cs
T
2026-02-11 17:28:58 +08:00

296 lines
9.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}