分享一个功能:用leap拉动一个固定位置的物体,拉动的同时使物体跟随手旋转,具体是这样的,手向上(下)运动,物体在世界坐标系中向上(下)旋转,手向右(左)运动,物体向右(左)旋转。手松开之后,物体要慢慢停下来,也就是模仿物理中的惯性。
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
[RequireComponent(typeof(AmeliGrabEventReceiver)), RequireComponent(typeof(SphereCollider))]
public class GrabRotate : MonoBehaviour
{
public Camera cam;
[Tooltip("Inertial falloff per second")]
public float inertial = 0.99f;
private Collider colObj;
private Vector3 lastPos;
private bool grab;
private Vector3 lastAxis;
private float lastAngle;
public Text dbgText;
void Start()
{
colObj = transform.GetComponent<Collider>();
}
/// <summary>
/// 抓住的事件
/// </summary>
/// <param name="e"></param>
void OnGrab(AmeliGrabEvent e)
{
lastPos = e.grabber.transform.position;//记录手的位置
grab = true;
}
/// <summary>
/// 手抓住球拖动的事件,这个事件是在update里面实现的
/// </summary>
/// <param name="e"></param>
void OnGlobalGrabDrag(AmeliGrabEvent e)
{
if (e.grabbed != colObj)
return;
Vector3 newVec = Vector3.Normalize(e.grabber.position - transform.position);//实时的记录当前手与球位置的偏移差
Vector3 lastVec = Vector3.Normalize(lastPos - transform.position);//计算球与手初始位置的偏移差
Quaternion drot = Quaternion.FromToRotation(lastVec, newVec);//计算两个偏移差之间的旋转的角度
Vector3 euler = drot.eulerAngles;
Vector3 camfor = cam.transform.forward;
Vector3 fwd = Vector3.Cross(camfor, Vector3.up);//(0,1,0)*(0,0,1)=(1,0,0)right方向
transform.Rotate(cam.transform.up, euler.y, Space.World);//球绕着camera的y轴旋转角度的y分量
transform.Rotate(fwd, -euler.x, Space.World);//这里根据实际情况判断取eular的x或y分量
lastPos = e.grabber.transform.position;//每一帧都记录手的位置,用来求两帧之间的差值
drot.ToAngleAxis(out lastAngle, out lastAxis);//把四元数转换成绕某个轴旋转的角度
}
void OnRelease(AmeliGrabEvent e)
{
grab = false;
}
/// <summary>
/// 用来控制手松开之后球的惯性
/// </summary>
void Update()
{
if (grab)
return;
if (dbgText != null)
{
dbgText.text = "" + lastAngle + "\n" + transform.rotation.eulerAngles;
}
if (lastAngle < 0.1f)
return;
float dra = lastAngle;
Vector3 camfor = cam.transform.forward;
Vector3 fwd = Vector3.Cross(camfor, Vector3.up);
transform.Rotate(lastAxis, dra, Space.World);//球绕着返回的轴转相应的角度
lastAngle *= (1 - Time.deltaTime) * inertial;//角度按一定的参数递减,直到角度小于0.1
}
}