314 lines
8.6 KiB
C#
314 lines
8.6 KiB
C#
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;
|
||
|
||
/// <summary>
|
||
/// 检测拖拽位置是否可以放置
|
||
/// </summary>
|
||
private Func<Vector2, bool> checkValidFunction;
|
||
|
||
private Action onStartDrag;
|
||
private Action onEndDrag;
|
||
|
||
/// <summary>
|
||
/// 接收原始位置并返回调整后位置的函数
|
||
/// </summary>
|
||
private Func<Vector2, Vector2> positionAdjuster;
|
||
|
||
/// <summary>
|
||
/// 处理成功放置逻辑的函数
|
||
/// </summary>
|
||
private Action<Vector2> placementHandler;
|
||
|
||
/// <summary>
|
||
/// 处理拖拽过程中检测的函数
|
||
/// </summary>
|
||
private Action<Vector2> dragUpdateHandler;
|
||
|
||
/// <summary>
|
||
/// 是否启用拖拽功能
|
||
/// </summary>
|
||
private bool isDraggableEnabled = true;
|
||
|
||
private void Awake()
|
||
{
|
||
rectTransform = GetComponent<RectTransform>();
|
||
|
||
if (buttonUpDrag == null)
|
||
{
|
||
Debug.LogError("DirectDragHandler需要ButtonUpDrag组件!");
|
||
return;
|
||
}
|
||
|
||
// 注册长按事件
|
||
buttonUpDrag.AddLongPress(OnStartDrag);
|
||
}
|
||
|
||
public void Init(Func<Vector2, bool> checkValidFunction, Action onStartDrag, Action onEndDrag)
|
||
{
|
||
this.checkValidFunction = checkValidFunction;
|
||
this.onStartDrag = onStartDrag;
|
||
this.onEndDrag = onEndDrag;
|
||
|
||
// 查找父级ScrollRect
|
||
parentScrollRect = GetComponentInParent<ScrollRect>();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置位置调整处理器
|
||
/// </summary>
|
||
/// <param name="positionAdjuster">接收原始位置并返回调整后位置的函数</param>
|
||
public void SetPositionAdjuster(Func<Vector2, Vector2> positionAdjuster)
|
||
{
|
||
this.positionAdjuster = positionAdjuster;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置成功放置处理器
|
||
/// </summary>
|
||
/// <param name="placementHandler">处理成功放置逻辑的函数</param>
|
||
public void SetPlacementHandler(Action<Vector2> placementHandler)
|
||
{
|
||
this.placementHandler = placementHandler;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 设置拖拽过程中的位置检测处理器
|
||
/// </summary>
|
||
/// <param name="dragUpdateHandler">在拖拽过程中处理位置检测的函数</param>
|
||
public void SetDragUpdateHandler(Action<Vector2> dragUpdateHandler)
|
||
{
|
||
this.dragUpdateHandler = dragUpdateHandler;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 启用或禁用拖拽功能
|
||
/// </summary>
|
||
public void SetDraggable(bool draggable)
|
||
{
|
||
this.isDraggableEnabled = draggable;
|
||
}
|
||
|
||
private void OnStartDrag()
|
||
{
|
||
if (!isDraggableEnabled)
|
||
return;
|
||
|
||
// 开始拖拽
|
||
isDragging = true;
|
||
scaleFactor = UIRoot.Instance.RootCanvas.GetComponent<RectTransform>().sizeDelta.x / Screen.width;
|
||
|
||
// 如果在ScrollRect中,则暂时禁用它
|
||
if (parentScrollRect != 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 != 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<UnityEngine.EventSystems.RaycastResult>();
|
||
//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;
|
||
}
|
||
} |