using System.Collections; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; using UnityEngine.XR.Interaction.Toolkit.Interactables; /// /// S1 天命玄鸟 - 悬浮甲骨交互 /// /// 同一 GameObject 需要同时挂 XRGrabInteractable。 /// /// 交互逻辑: /// hover(触摸/靠近,未抓取)→ 播放文字显示动画 /// selectEntered(抓取) → 隐藏文字,取消归位计时 /// selectExited(松手) → 延迟后溶解消失 → 瞬间归位 → 溶解出现 /// [RequireComponent(typeof(XRGrabInteractable))] public class S1_OracleBoneInteract : MonoBehaviour { [Header("文字动画")] [SerializeField] private Animator textAnimator; [SerializeField] private string showAnimName = "Open"; // 文字出现 [SerializeField] private string hideAnimName = "Translate"; // 文字消失 [SerializeField] private AudioSource touchAudio; [Header("归位溶解效果")] [SerializeField] private EffectHideAndShowCtr effectCtr; [SerializeField] private float resetDelayTime = 2f; // 松手后多久开始归位 [SerializeField] private float dissolveDuration = 1f; // 溶解动画时长 // ── 内部状态 ───────────────────────────────────────────── private XRGrabInteractable m_grab; private Rigidbody m_rb; private Vector3 m_returnPos; private Quaternion m_returnRot; private Coroutine m_resetCoroutine; // ── 生命周期 ────────────────────────────────────────────── private void Awake() { m_grab = GetComponent(); m_rb = GetComponent(); } private void Start() { // 记录初始世界位置/旋转作为归位目标 m_returnPos = transform.position; m_returnRot = transform.rotation; } private void OnEnable() { m_grab.hoverEntered.AddListener(OnHoverEntered); m_grab.selectEntered.AddListener(OnSelectEntered); m_grab.selectExited.AddListener(OnSelectExited); } private void OnDisable() { m_grab.hoverEntered.RemoveListener(OnHoverEntered); m_grab.selectEntered.RemoveListener(OnSelectEntered); m_grab.selectExited.RemoveListener(OnSelectExited); StopReset(); } // ── XRI 事件 ────────────────────────────────────────────── /// 手靠近/触摸(未抓取)→ 显示文字 private void OnHoverEntered(HoverEnterEventArgs args) { if (m_grab.isSelected) return; // 已被抓取中,不重复触发 ShowText(); } /// 抓取 → 隐藏文字,取消归位计时 private void OnSelectEntered(SelectEnterEventArgs args) { StopReset(); HideText(); } /// 松手 → 延迟后溶解归位 private void OnSelectExited(SelectExitEventArgs args) { m_resetCoroutine = StartCoroutine(DelayThenReturn()); } // ── 归位协程 ────────────────────────────────────────────── private IEnumerator DelayThenReturn() { yield return new WaitForSeconds(resetDelayTime); // 归位期间禁止被重新抓取 m_grab.enabled = false; // 1. 停止物理运动(避免归位时还在飞) if (m_rb != null) { m_rb.velocity = Vector3.zero; m_rb.angularVelocity = Vector3.zero; m_rb.isKinematic = true; } // 2. 溶解消失 if (effectCtr != null) effectCtr.Hide(); yield return new WaitForSeconds(dissolveDuration); // 3. 瞬间归位 transform.position = m_returnPos; transform.rotation = m_returnRot; // 4. 溶解出现 if (effectCtr != null) effectCtr.Show(); yield return new WaitForSeconds(dissolveDuration); // 5. 恢复交互 m_grab.enabled = true; m_resetCoroutine = null; } private void StopReset() { if (m_resetCoroutine != null) { StopCoroutine(m_resetCoroutine); m_resetCoroutine = null; } // 确保归位中断时交互器恢复可用 if (m_grab != null) m_grab.enabled = true; } // ── 文字动画 ────────────────────────────────────────────── private void ShowText() { if (textAnimator != null) textAnimator.Play(showAnimName); if (touchAudio != null) touchAudio.Play(); } private void HideText() { if (textAnimator != null) textAnimator.Play(hideAnimName); } }