一:前言
针对上一节讲解的事件机制https://blog.csdn.net/HexianWHH/article/details/119741189,这节练习一个实际应用。基于IDragHandler事件做一个在指定区域拖动松手自动吸附的功能。
二:效果演示
拖动滑块只能在指定区域内滑动,不能超出边界。松开鼠标以后自动吸附到最近的格子。
?
?
三:制作过程
- 添加一个图片作为拖动区域。
- 制作一个每一个格子的预制体。
- 给第一步的拖动区域添加GridLayoutGroup组件和自己写的GridWindow组件,并设置参数。
- 新建一个图片作为滑动块,并且挂上DragMove组件,并设置参数。
四:代码讲解
GridWindow负责创建格子,拥有所有的格子对象。
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 所有格子的窗体
/// </summary>
public class GridWindow : MonoBehaviour
{
/// <summary>
/// 挂载每一个格子的父物体
/// </summary>
[SerializeField]
Transform parentTrans;
/// <summary>
/// 格子的个数
/// </summary>
[SerializeField]
int gridItemCount;
/// <summary>
/// 格子物体
/// </summary>
[SerializeField]
GameObject childObj;
/// <summary>
/// 所有格子
/// </summary>
List<RectTransform> allChildGrid = new List<RectTransform>();
void Start()
{
for (int i = 0; i < gridItemCount; i++)
{
var obj = Instantiate(childObj);
obj.transform.SetParent(parentTrans);
allChildGrid.Add(obj.GetComponent<RectTransform>());
}
}
private void OnDestroy()
{
//删除所有创建的格子
foreach (var item in allChildGrid)
{
Destroy(item.gameObject);
}
allChildGrid.Clear();
}
/// <summary>
/// 得到距离指定位置最近的一个格子位置
/// </summary>
/// <param name="pos">指定位置</param>
/// <returns>最近的格子位置</returns>
public Vector3 GetNearestPos(Vector3 pos)
{
float minDis = float.MaxValue;
Vector3 returnPos = Vector3.zero;
foreach (var child in allChildGrid)
{
var dis = Vector3.Distance(child.position, pos);
if (dis < minDis)
{
minDis = dis;
returnPos = child.position;
}
}
return returnPos;
}
}
DragMove拖动的滑块,里面涉及到的变量具体意思
eventData.delta这次滑动的距离
rectTrans.rect和rectTrans.anchoredPosition,以及最小最大边界为什么是这样计算的。可以参照我之前写的文章有详细的解析https://blog.csdn.net/HexianWHH/article/details/118881151
Mathf.Clamp把值限定在最小和最大值范围之内。
using UnityEngine;
using UnityEngine.EventSystems;
/// <summary>
/// 可以拖动的物体
/// </summary>
public class DragMove : MonoBehaviour, IDragHandler,IEndDragHandler
{
/// <summary>
/// 可以拖拽的区域
/// </summary>
[SerializeField]
RectTransform dragRangeRect;
/// <summary>
/// 所有格子的窗体
/// </summary>
[SerializeField]
GridWindow gridWindow;
/// <summary>
/// 当前物体自己的矩形组件
/// </summary>
RectTransform rectTrans;
private void Awake()
{
rectTrans = this.GetComponent<RectTransform>();
}
public void OnDrag(PointerEventData eventData)
{
//拖动区域的最小边界
var minPos = 0.5f * (rectTrans.rect.size - dragRangeRect.rect.size);
//拖动区域的最大边界
var maxPos = 0.5f * (dragRangeRect.rect.size - rectTrans.rect.size);
//拖动以后的距离
var movePos = rectTrans.anchoredPosition + eventData.delta;
//把滑块限定在拖动区域内部
var curPos = new Vector2(Mathf.Clamp(movePos.x, minPos.x, maxPos.x), Mathf.Clamp(movePos.y, minPos.x, maxPos.y));
rectTrans.anchoredPosition = curPos;
}
public void OnEndDrag(PointerEventData eventData)
{
//查找距离该点最近的格子的位置
var pos = gridWindow.GetNearestPos(rectTrans.position);
rectTrans.position = pos;
}
}
|