1.抓取的不会穿透其它带碰撞的模型。
2.碰撞会受质量影响,质量大的容易撞开质量小的,质量小的不容易撞开质量大的。
3.可以开启连续碰撞检测选项避免一些高速运动等特殊情况的穿透,但也会增加一定性能开销。
// An highlighted block
/*----------------------------------------------------------------
// 文件名:GrabFollow.cs
// 功能描述:自定义抓取(代码直接挂在要被抓取的物体上,注意删除默认的抓取脚本)
//
// 创建标识:辛羊华 2024/5/25 10:17:22
//
// 修改标识:
// 修改描述:
//
//----------------------------------------------------------------*/
using UnityEngine;
using UnityEngine.EventSystems;
using zSpace.Core.Input;
public class GrabFollow : ZPointerInteractable, IBeginDragHandler, IDragHandler, IEndDragHandler
{
[Header("使用连续检测碰撞")]
public bool ContinuousDetection; //可防止快速运动穿透模型,但会增加性能开销
private const float m_MaxVelocityChange = 10f;
private const float m_VelocityMagic = 6000f;
private const float m_AngularVelocityMagic = 50f;
private const float m_MaxAngularVelocityChange = 20f;
/// <summary>
/// 笔
/// </summary>
private ZStylus m_ZStylus;
/// <summary>
/// 该物体的刚体
/// </summary>
private Rigidbody m_Rigi;
/// <summary>
/// 抓取前的自带刚体
/// </summary>
private Rigidbody m_OriRigi;
/// <summary>
/// 抓取连接物
/// </summary>
private GameObject m_GrabHandle;
/// <summary>
/// 跟随目标位置
/// </summary>
private Transform m_Target;
void Start()
{
m_ZStylus = GameObject.FindObjectOfType<ZStylus>();
}
public void OnBeginDrag(PointerEventData eventData)
{
//获取自身刚体或添加一个刚体
m_OriRigi = GetComponent<Rigidbody>();
if (m_OriRigi == null)
{
m_Rigi = gameObject.AddComponent<Rigidbody>();
}
else
{
m_Rigi = m_OriRigi;
}
if (ContinuousDetection)
{
m_Rigi.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
}
//生成一个关节跟随物体
m_GrabHandle = new GameObject("GrabHandle");
m_GrabHandle.transform.position = this.transform.position;
m_GrabHandle.transform.rotation = this.transform.rotation;
m_GrabHandle.transform.SetParent(m_ZStylus.Visualization.transform);
m_Target = m_GrabHandle.transform;
}
public void OnEndDrag(PointerEventData eventData)
{
//还原抓取前状态
m_Target = null;
Destroy(m_GrabHandle);
if (m_OriRigi == null) Destroy(m_Rigi); //删除添加的刚体
}
private void FixedUpdate()
{
if (m_Target)
{
UpdateFollow();
}
}
private void UpdateFollow()
{
Vector3 velocityTarget; //目标速度
Vector3 angularTarget; //目标角速度
bool success = GetUpdatedVelocities(out velocityTarget, out angularTarget);
if (success)
{
m_Rigi.velocity = Vector3.MoveTowards(m_Rigi.velocity, velocityTarget, m_MaxVelocityChange);
m_Rigi.angularVelocity = Vector3.MoveTowards(m_Rigi.angularVelocity, angularTarget, m_MaxAngularVelocityChange);
}
}
/// <summary>
/// 获取目标速度
/// </summary>
/// <param name="velocityTarget"></param>
/// <param name="angularTarget"></param>
/// <returns></returns>
protected bool GetUpdatedVelocities(out Vector3 velocityTarget, out Vector3 angularTarget)
{
bool realNumbers = false;
//速度
Vector3 positionDelta = (m_Target.position - transform.position);
velocityTarget = (positionDelta * m_VelocityMagic * Time.deltaTime);
if (float.IsNaN(velocityTarget.x) == false && float.IsInfinity(velocityTarget.x) == false)
{
velocityTarget /= 10;
realNumbers = true;
}
else
{
velocityTarget = Vector3.zero;
}
//角速度
Quaternion rotationDelta = m_Target.rotation * Quaternion.Inverse(transform.rotation);
float angle;
Vector3 axis;
rotationDelta.ToAngleAxis(out angle, out axis);
if (angle > 180) angle -= 360;
if (angle != 0 && float.IsNaN(axis.x) == false && float.IsInfinity(axis.x) == false)
{
angularTarget = angle * axis * m_AngularVelocityMagic * Time.deltaTime;
angularTarget /= 10;
realNumbers &= true;
}
else
{
angularTarget = Vector3.zero;
}
return realNumbers;
}
}