155 lines
5.0 KiB
C#
155 lines
5.0 KiB
C#
using System.Collections;
|
||
using UnityEngine;
|
||
using UnityEngine.XR.Interaction.Toolkit;
|
||
using UnityEngine.XR.Interaction.Toolkit.Interactables;
|
||
|
||
/// <summary>
|
||
/// S1 天命玄鸟 - 悬浮甲骨交互
|
||
///
|
||
/// 同一 GameObject 需要同时挂 XRGrabInteractable。
|
||
///
|
||
/// 交互逻辑:
|
||
/// hover(触摸/靠近,未抓取)→ 播放文字显示动画
|
||
/// selectEntered(抓取) → 隐藏文字,取消归位计时
|
||
/// selectExited(松手) → 延迟后溶解消失 → 瞬间归位 → 溶解出现
|
||
/// </summary>
|
||
[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<XRGrabInteractable>();
|
||
m_rb = GetComponent<Rigidbody>();
|
||
}
|
||
|
||
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 事件 ──────────────────────────────────────────────
|
||
|
||
/// <summary>手靠近/触摸(未抓取)→ 显示文字</summary>
|
||
private void OnHoverEntered(HoverEnterEventArgs args)
|
||
{
|
||
if (m_grab.isSelected) return; // 已被抓取中,不重复触发
|
||
ShowText();
|
||
}
|
||
|
||
/// <summary>抓取 → 隐藏文字,取消归位计时</summary>
|
||
private void OnSelectEntered(SelectEnterEventArgs args)
|
||
{
|
||
StopReset();
|
||
HideText();
|
||
}
|
||
|
||
/// <summary>松手 → 延迟后溶解归位</summary>
|
||
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);
|
||
}
|
||
}
|