提交S1交互
This commit is contained in:
@@ -1,110 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.Interaction.Toolkit;
|
||||
using System.Collections;
|
||||
|
||||
namespace LevelUp.GrabInteractions
|
||||
{
|
||||
public class ResetObjectSmooth : ResetObject
|
||||
{
|
||||
[Header("平滑重置设置")]
|
||||
[SerializeField] private float resetSpeed = 5f;
|
||||
[SerializeField] private float stopDistance = 0.01f;
|
||||
|
||||
private Quaternion returnToRotation;
|
||||
private Rigidbody rb;
|
||||
private Coroutine smoothMoveCoroutine;
|
||||
private bool initialIsKinematic;
|
||||
// 新增:用于备份物理插值设置
|
||||
private RigidbodyInterpolation initialInterpolation;
|
||||
|
||||
protected new void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
rb = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
base.Start();
|
||||
returnToRotation = transform.rotation;
|
||||
|
||||
if (rb != null)
|
||||
{
|
||||
initialIsKinematic = rb.isKinematic;
|
||||
initialInterpolation = rb.interpolation; // 记录初始插值状态
|
||||
}
|
||||
}
|
||||
|
||||
void OnDestroy() => StopAllCoroutinesAndCancelInvoke();
|
||||
|
||||
private void StopAllCoroutinesAndCancelInvoke()
|
||||
{
|
||||
CancelInvoke(nameof(ReturnHome));
|
||||
if (smoothMoveCoroutine != null)
|
||||
{
|
||||
StopCoroutine(smoothMoveCoroutine);
|
||||
smoothMoveCoroutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnSelect(SelectEnterEventArgs arg0) => StopAllCoroutinesAndCancelInvoke();
|
||||
|
||||
protected override void OnSelectExit(SelectExitEventArgs arg0)
|
||||
{
|
||||
StopAllCoroutinesAndCancelInvoke();
|
||||
if (rb != null)
|
||||
{
|
||||
rb.isKinematic = false;
|
||||
rb.WakeUp();
|
||||
}
|
||||
base.OnSelectExit(arg0);
|
||||
}
|
||||
|
||||
protected override void ReturnHome()
|
||||
{
|
||||
if (shouldReturnHome)
|
||||
smoothMoveCoroutine = StartCoroutine(SmoothMoveToHome());
|
||||
}
|
||||
|
||||
private IEnumerator SmoothMoveToHome()
|
||||
{
|
||||
if (rb != null)
|
||||
{
|
||||
// 【关键优化 1】禁用物理插值,防止物理引擎尝试预测物体的 Transform 更新
|
||||
rb.interpolation = RigidbodyInterpolation.None;
|
||||
rb.isKinematic = true;
|
||||
rb.velocity = Vector3.zero;
|
||||
rb.angularVelocity = Vector3.zero;
|
||||
}
|
||||
|
||||
float stopDistanceSqr = stopDistance * stopDistance;
|
||||
|
||||
while ((transform.position - returnToPosition).sqrMagnitude > stopDistanceSqr)
|
||||
{
|
||||
float lerpFactor = 1f - Mathf.Exp(-resetSpeed * Time.deltaTime);
|
||||
|
||||
transform.position = Vector3.Lerp(transform.position, returnToPosition, lerpFactor);
|
||||
transform.rotation = Quaternion.Slerp(transform.rotation, returnToRotation, lerpFactor);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
transform.position = returnToPosition;
|
||||
transform.rotation = returnToRotation;
|
||||
|
||||
// 【关键优化 2】在恢复物理属性前,等待一个物理帧,确保位置同步完成
|
||||
yield return new WaitForFixedUpdate();
|
||||
|
||||
if (rb != null)
|
||||
{
|
||||
rb.isKinematic = initialIsKinematic;
|
||||
// 【关键优化 3】恢复初始插值设置
|
||||
rb.interpolation = initialInterpolation;
|
||||
rb.velocity = Vector3.zero;
|
||||
rb.angularVelocity = Vector3.zero;
|
||||
}
|
||||
|
||||
smoothMoveCoroutine = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
141
Assets/YOMOV Access/Scripts/ReturnPosition.cs
Normal file
141
Assets/YOMOV Access/Scripts/ReturnPosition.cs
Normal file
@@ -0,0 +1,141 @@
|
||||
using System.Collections;
|
||||
using UnityEngine;
|
||||
using UnityEngine.XR.Interaction.Toolkit;
|
||||
using UnityEngine.XR.Interaction.Toolkit.Interactables;
|
||||
|
||||
/// <summary>
|
||||
/// 抓取后松手归回原位(替代 ResetObjectSmooth,避免模型拉伸)
|
||||
/// 同一 GameObject 需要挂 XRGrabInteractable。
|
||||
/// 可选:挂 EffectHideAndShowCtr 实现溶解消失/出现效果。
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(XRGrabInteractable))]
|
||||
public class ReturnPosition : MonoBehaviour
|
||||
{
|
||||
[Header("归位设置")]
|
||||
[SerializeField] private float resetDelayTime = 2f; // 松手后延迟归位秒数
|
||||
[SerializeField] private EffectHideAndShowCtr effectCtr; // 溶解效果(可为空)
|
||||
[SerializeField] private float dissolveDuration = 1f; // 溶解动画时长
|
||||
|
||||
[Header("音效")]
|
||||
public AudioSource grabAudio;
|
||||
public AudioSource releaseAudio;
|
||||
|
||||
// 归位目标(启动时记录)
|
||||
private Vector3 m_returnPos;
|
||||
private Quaternion m_returnRot;
|
||||
|
||||
private XRGrabInteractable m_grab;
|
||||
private Rigidbody m_rb;
|
||||
private Coroutine m_resetCoroutine;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_grab = GetComponent<XRGrabInteractable>();
|
||||
m_rb = GetComponent<Rigidbody>();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
// 记录初始世界坐标作为归位目标
|
||||
m_returnPos = transform.position;
|
||||
m_returnRot = transform.rotation;
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_grab.selectEntered.AddListener(OnSelectEntered);
|
||||
m_grab.selectExited.AddListener(OnSelectExited);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
m_grab.selectEntered.RemoveListener(OnSelectEntered);
|
||||
m_grab.selectExited.RemoveListener(OnSelectExited);
|
||||
}
|
||||
|
||||
// ── XRI 事件 ──────────────────────────────────────────────
|
||||
|
||||
private void OnSelectEntered(SelectEnterEventArgs args)
|
||||
{
|
||||
// 抓取时取消正在进行的归位
|
||||
StopReset();
|
||||
if (grabAudio != null) grabAudio.Play();
|
||||
}
|
||||
|
||||
private void OnSelectExited(SelectExitEventArgs args)
|
||||
{
|
||||
if (releaseAudio != null) releaseAudio.Play();
|
||||
m_resetCoroutine = StartCoroutine(DelayThenReturn());
|
||||
}
|
||||
|
||||
// ── 归位协程 ──────────────────────────────────────────────
|
||||
|
||||
private IEnumerator DelayThenReturn()
|
||||
{
|
||||
yield return new WaitForSeconds(resetDelayTime);
|
||||
|
||||
// 归位期间禁止被重新抓取
|
||||
m_grab.enabled = false;
|
||||
|
||||
// 停止物理运动
|
||||
StopPhysics();
|
||||
|
||||
if (effectCtr != null)
|
||||
{
|
||||
// 有溶解效果:消失 → 归位 → 出现
|
||||
effectCtr.Hide();
|
||||
yield return new WaitForSeconds(dissolveDuration);
|
||||
|
||||
ReturnPositionAndRotation();
|
||||
|
||||
effectCtr.Show();
|
||||
yield return new WaitForSeconds(dissolveDuration);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 无溶解效果:直接瞬移归位
|
||||
ReturnPositionAndRotation();
|
||||
}
|
||||
|
||||
m_grab.enabled = true;
|
||||
m_resetCoroutine = null;
|
||||
}
|
||||
|
||||
// ── 公共方法 ──────────────────────────────────────────────
|
||||
|
||||
/// <summary>立即归回初始位置和旋转</summary>
|
||||
public void ReturnPositionAndRotation()
|
||||
{
|
||||
transform.position = m_returnPos;
|
||||
transform.rotation = m_returnRot;
|
||||
StopPhysics();
|
||||
}
|
||||
|
||||
/// <summary>更新归位目标为当前位置(需要重新记录原点时调用)</summary>
|
||||
public void RecordCurrentAsHome()
|
||||
{
|
||||
m_returnPos = transform.position;
|
||||
m_returnRot = transform.rotation;
|
||||
}
|
||||
|
||||
// ── 内部工具 ──────────────────────────────────────────────
|
||||
|
||||
private void StopPhysics()
|
||||
{
|
||||
if (m_rb == null) return;
|
||||
m_rb.velocity = Vector3.zero;
|
||||
m_rb.angularVelocity = Vector3.zero;
|
||||
m_rb.isKinematic = true;
|
||||
}
|
||||
|
||||
private void StopReset()
|
||||
{
|
||||
if (m_resetCoroutine != null)
|
||||
{
|
||||
StopCoroutine(m_resetCoroutine);
|
||||
m_resetCoroutine = null;
|
||||
}
|
||||
if (m_grab != null)
|
||||
m_grab.enabled = true;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7877962557443e34f8190e3278bd4a5d
|
||||
guid: 7cf98a8d188845e4b9cca594d4776f95
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
Reference in New Issue
Block a user