using System; using UnityEngine; using UnityEngine.UI; public class DirectDragHandler : MonoBehaviour { [Tooltip("是否在拖拽时限制移动范围")] public bool restrictMovement = false; [Tooltip("拖拽范围限制(如果启用限制)")] public RectTransform movementBounds; [Tooltip("是否锁定垂直方向移动")] public bool lockVertical = false; [Tooltip("是否锁定水平方向移动")] public bool lockHorizontal = false; [Tooltip("拖拽时是否改变视觉效果")] public bool changeDragAppearance = true; [Tooltip("拖拽时的缩放")] public Vector3 dragScale = new Vector3(1.1f, 1.1f, 1.1f); // 原始位置和缩放 private Vector3 originalPosition; private Vector3 originalScale; private RectTransform rectTransform; private float scaleFactor; // 拖拽状态 private bool isDragging = false; [SerializeField] private ButtonUpDrag buttonUpDrag; private ScrollRect parentScrollRect; /// /// 检测拖拽位置是否可以放置 /// private Func checkValidFunction; private Action onStartDrag; private Action onEndDrag; /// /// 接收原始位置并返回调整后位置的函数 /// private Func positionAdjuster; /// /// 处理成功放置逻辑的函数 /// private Action placementHandler; /// /// 处理拖拽过程中检测的函数 /// private Action dragUpdateHandler; /// /// 拖拽按下事件处理器 /// private Action onPointDownHandler; /// /// 拖拽松开事件处理器 /// private Action onPointUpHandler; /// /// 取消长按事件处理器 /// private Action onCancelLongPress; /// /// 是否启用拖拽功能 /// private bool isDraggableEnabled = true; /// 是否处于长按已触发后的拖拽中(供外部与 ScrollRect 锁定等逻辑配合)。 public bool IsDragging => isDragging; private void Awake() { rectTransform = GetComponent(); if (buttonUpDrag == null) { Debug.LogError("DirectDragHandler需要ButtonUpDrag组件!"); return; } // 注册长按事件 buttonUpDrag.AddLongPress(OnStartDrag); buttonUpDrag.AddLongPressCancel(OnLongPressCancel); buttonUpDrag.AddPointerDown(OnPointDown); buttonUpDrag.AddPointerUp(OnPointUp); } public void Init(Func checkValidFunction, Action onStartDrag, Action onEndDrag) { this.checkValidFunction = checkValidFunction; this.onStartDrag = onStartDrag; this.onEndDrag = onEndDrag; // 查找父级ScrollRect parentScrollRect = GetComponentInParent(); } /// /// 设置位置调整处理器 /// /// 接收原始位置并返回调整后位置的函数 public void SetPositionAdjuster(Func positionAdjuster) { this.positionAdjuster = positionAdjuster; } /// /// 设置成功放置处理器 /// /// 处理成功放置逻辑的函数 public void SetPlacementHandler(Action placementHandler) { this.placementHandler = placementHandler; } /// /// 设置拖拽过程中的位置检测处理器 /// /// 在拖拽过程中处理位置检测的函数 public void SetDragUpdateHandler(Action dragUpdateHandler) { this.dragUpdateHandler = dragUpdateHandler; } public void SetPointDownHandler(Action pointDownCallback, Action pointUpCallback) { this.onPointDownHandler = pointDownCallback; this.onPointUpHandler = pointUpCallback; } /// /// 设置取消长按处理器 /// /// public void SetLongPressCancel(Action cancelLongPress) { this.onCancelLongPress = cancelLongPress; } /// /// 长按蓄力阶段:触点移出该 Rect 的屏幕范围时取消长按(由 ButtonUpDrag 处理)。 /// public void SetLongPressCancelBounds(RectTransform bounds) { if (buttonUpDrag != null) buttonUpDrag.SetLongPressCancelBounds(bounds); } /// /// 启用或禁用拖拽功能 /// public void SetDraggable(bool draggable) { this.isDraggableEnabled = draggable; } private void OnPointDown() { onPointDownHandler?.Invoke(); } private void OnPointUp() { onPointUpHandler?.Invoke(); } private void OnLongPressCancel() { onCancelLongPress?.Invoke(); } private void OnStartDrag() { if (!isDraggableEnabled) return; // 开始拖拽 isDragging = true; scaleFactor = UIRoot.Instance.UINormalCanvas.GetComponent().sizeDelta.x / Screen.width; // 如果在ScrollRect中,则暂时禁用它 if (parentScrollRect is not null) { parentScrollRect.enabled = false; } originalPosition = rectTransform.position; originalScale = rectTransform.localScale; // 改变外观(如果启用) if (changeDragAppearance) { rectTransform.localScale = dragScale; } // 注册移动和结束拖拽事件 InputManager.Instance.OnFingerMoveUI += UpdateDragPosition; InputManager.Instance.OnFingerUpUI += EndDrag; onStartDrag?.Invoke(); } private void UpdateDragPosition(Vector2 delta) { if (!isDragging || !isDraggableEnabled) return; // 计算新位置(考虑偏移) Vector2 newPosition = rectTransform.anchoredPosition + delta * scaleFactor; // 应用方向锁定和边界限制逻辑... // 使用自定义位置调整器(如果有) if (positionAdjuster != null) { newPosition = positionAdjuster(newPosition); } // 更新位置 rectTransform.anchoredPosition = newPosition; // 调用拖拽更新处理器 dragUpdateHandler?.Invoke(rectTransform.position); } private void EndDrag(Vector2 position) { if (!isDragging) return; isDragging = false; // 恢复原始外观 if (changeDragAppearance) { rectTransform.localScale = originalScale; } // 处理拖拽结束逻辑 HandleDragEnd(rectTransform.position);//position // 重新启用ScrollRect if (parentScrollRect is not null) { parentScrollRect.enabled = true; } // 清理事件监听 InputManager.Instance.OnFingerMoveUI -= UpdateDragPosition; InputManager.Instance.OnFingerUpUI -= EndDrag; onEndDrag?.Invoke(); } private void HandleDragEnd(Vector2 position) { // 在这里实现放置逻辑 bool validPlacement = CheckValidPlacement(position); if (validPlacement) { // 有效放置,执行相应逻辑 FinalizeItemPlacement(position); } } private bool CheckValidPlacement(Vector2 position) { // 实现放置检测逻辑 // 这里只是示例,你需要根据具体需求实现 // 示例:使用射线检测 //var results = new System.Collections.Generic.List(); //var eventData = new UnityEngine.EventSystems.PointerEventData(UnityEngine.EventSystems.EventSystem.current); //eventData.position = position; //UnityEngine.EventSystems.EventSystem.current.RaycastAll(eventData, results); // //foreach (var result in results) //{ // // 检查是否是有效的放置目标 // // 例如:检查是否有特定的组件或标签 // if (result.gameObject.CompareTag("DropZone")) // { // return true; // } //} // // 默认返回true,允许在任何位置放置 // 如果需要更严格的控制,改为return false; //return true; if (checkValidFunction != null) { return checkValidFunction(position); } return false; } private void FinalizeItemPlacement(Vector2 position) { if (placementHandler != null) { placementHandler(position); } } private void ReturnToOriginalPosition() { // 返回原始位置 // 可以使用动画或直接设置 // 直接设置: // rectTransform.position = originalPosition; // 使用动画效果: //StartCoroutine(AnimateReturn()); rectTransform.position = originalPosition; } private System.Collections.IEnumerator AnimateReturn() { float duration = 0.3f; float elapsed = 0f; Vector3 startPos = rectTransform.position; while (elapsed < duration) { rectTransform.position = Vector3.Lerp(startPos, originalPosition, elapsed / duration); elapsed += Time.deltaTime; yield return null; } rectTransform.position = originalPosition; } private void OnDestroy() { // 清理事件监听 if (InputManager.Instance != null) { InputManager.Instance.OnFingerMoveUI -= UpdateDragPosition; InputManager.Instance.OnFingerUp -= EndDrag; InputManager.Instance.OnFingerUpUI -= EndDrag; } } // 可选:提供公共方法以在外部重置位置 public void ResetPosition() { rectTransform.position = originalPosition; } // 可选:提供公共方法以更新原始位置(例如在布局变化后) public void UpdateOriginalPosition() { originalPosition = rectTransform.position; } }