目标:实现类似拖拽后“飘回”原位的效果
我们知道改变物体的位置可以通过对transform.position
赋值实现,但这是一次性的,哪怕使用了Lerp
将一段距离均分为100份放在Update
函数中,也是在当前的一帧内,直接“闪现”到目标位置
其实是因为,若将所有代码均放于Update
,那么这一百份更新,仍旧会在这一帧的时间内执行完,而并非均分到各帧
而对于拖拽事件,则相当于每一帧获取鼠标的世界坐标,并赋值给物体即可
知道了这些,就可以写下如下代码实现功能,基本变量与函数功能均已注释:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Move : MonoBehaviour
{
// 复位时间(速度)
float duration = 0.5f, currentTime = 0f;
bool isDrag = false;
// 初始位置坐标,复位时每次的偏移
Vector3 originPos, offset;
// 物体的屏幕坐标
Vector3 screenSpace;
void Start()
{
originPos = transform.position;
}
void Update()
{
// 鼠标按下,拖拽事件
if(Input.GetMouseButtonDown(0))
{
// 物体世界坐标转为屏幕坐标
screenSpace = Camera.main.WorldToScreenPoint(transform.position);
isDrag = true;
}
// 鼠标松开,返回原位
else if(Input.GetMouseButtonUp(0))
{
isDrag = false;
offset = originPos - transform.position;
}
if(!isDrag && transform.position != originPos)
{
ResetPosition();
}
// 鼠标一直按下未松开,执行拖拽
if (isDrag)
{
DragObject();
}
}
// 复位
private void ResetPosition()
{
// 每次向offset的方向偏移
if (currentTime < duration)
{
transform.position += offset * Time.deltaTime / duration;
currentTime += Time.deltaTime;
}
// 若移动足够的时间,赋值最终位置,重置当前移动时间
else
{
transform.position = originPos;
currentTime = 0;
}
}
// 拖拽
private void DragObject()
{
Vector3 curScreenSpace = new Vector3(Input.mousePosition.x, Input.mousePosition.y, screenSpace.z);
var curPosition = Camera.main.ScreenToWorldPoint(curScreenSpace);
transform.position = curPosition;
}
}