using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; namespace Rokid.UXR.Interaction { public class InteractorButton : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler, IPointerUpHandler, IPointerClickHandler { public enum TouchState { Normal = 1,//正常状态 Hover = 2,//手指到达开始按钮浮起的位置 Touch = 4,//手指触碰到浮起的 PressDown = 8,//按下,触碰到按钮地板 } public TouchState touchState { get; private set; } = TouchState.Normal; /// /// 默认抬起的高度,米 /// public float normalOffsetAlongNormal = 0.00f; /// /// 被hover时自动抬起的高度,米 /// public float hoverOffsetAlongNormal = 0.006f; /// /// 开始抬起时手指高度,米 /// public float beginHoverOffsetAlongNormal = 0.08f; /// /// 抬起的UI图片 /// public Transform buttonUp; public UnityEvent onStateChanged; public UnityEvent onPointerDown = new UnityEvent(); public UnityEvent onPointerUp = new UnityEvent(); public UnityEvent onPointerClick = new UnityEvent(); public UnityEvent onPointerEnter = new UnityEvent(); public UnityEvent onPointerExit = new UnityEvent(); public HashSet _pokeInteractors = new HashSet(); private PokeInteractable _pokeInteractable; private bool hoverEnter = false; private bool pointerDown = false; private PokeInteractable pokeInteractable { get { if (_pokeInteractable == null) { _pokeInteractable = transform.GetComponentInParent(); if (_pokeInteractable == null) { enabled = false; } } return _pokeInteractable; } } void Awake() { if (!buttonUp) { enabled = false; } buttonUp.position = transform.position - transform.forward * normalOffsetAlongNormal; } private void OnEnable() { hoverEnter = false; _pokeInteractors.Clear(); _pokeInteractors.UnionWith(pokeInteractable.Interactors); pokeInteractable.WhenInteractorAdded.Action += HandleInteractorAdded; pokeInteractable.WhenInteractorRemoved.Action += HandleInteractorRemoved; } private void OnDisable() { OnPointerExit(null); pokeInteractable.WhenInteractorAdded.Action -= HandleInteractorAdded; pokeInteractable.WhenInteractorRemoved.Action -= HandleInteractorRemoved; _pokeInteractors.Clear(); } private void HandleInteractorAdded(PokeInteractor pokeInteractor) { _pokeInteractors.Add(pokeInteractor); } private void HandleInteractorRemoved(PokeInteractor pokeInteractor) { pokeInteractor.InteractorButtonUpPosition = Vector3.zero; _pokeInteractors.Remove(pokeInteractor); } private void Update() { if (hoverEnter) { if (_pokeInteractors.Count > 0) { float closestDistance = int.MaxValue; foreach (var v in _pokeInteractors) { float dis = Vector3.Dot(transform.position - v.transform.position, transform.forward); closestDistance = closestDistance < dis ? closestDistance : dis; } closestDistance = closestDistance < 0 ? 0 : closestDistance; if (closestDistance > beginHoverOffsetAlongNormal) { buttonUp.position = Vector3.Lerp(buttonUp.position, transform.position - transform.forward * normalOffsetAlongNormal, 20 * Time.deltaTime); } else if (closestDistance > hoverOffsetAlongNormal) { buttonUp.position = Vector3.Lerp(buttonUp.position, transform.position - transform.forward * hoverOffsetAlongNormal, 30 * Time.deltaTime); } else { buttonUp.position = transform.position - transform.forward * closestDistance; } foreach (var item in _pokeInteractors) { item.InteractorButtonUpPosition = buttonUp.position; } ChangeState(closestDistance); } } } void ChangeState(float closestDistance) { TouchState curState; if (closestDistance > beginHoverOffsetAlongNormal) { curState = TouchState.Normal; } else if (closestDistance > hoverOffsetAlongNormal) { curState = TouchState.Hover; } else if (closestDistance > 0.001) { curState = TouchState.Touch; } else { curState = TouchState.PressDown; } if (curState != touchState) { touchState = curState; onStateChanged?.Invoke(curState); } } public void OnPointerDown(PointerEventData eventData) { RKLog.Info($"====InteractorButton==== P {eventData?.currentInputModule?.GetType().Name} pointerDown"); if (_pokeInteractors.Count == 0) { buttonUp.position = transform.position; } onPointerDown?.Invoke(eventData); pointerDown = true; } public void OnPointerUp(PointerEventData eventData) { RKLog.Info($"====InteractorButton==== P {eventData?.currentInputModule?.GetType().Name} pointerUp"); if (_pokeInteractors.Count == 0) { buttonUp.position = transform.position - transform.forward * normalOffsetAlongNormal; } onPointerUp?.Invoke(eventData); pointerDown = false; } public void OnPointerEnter(PointerEventData eventData) { RKLog.Info($"====InteractorButton==== E {eventData?.currentInputModule?.GetType().Name} pointerEnter"); hoverEnter = true; onPointerEnter?.Invoke(eventData); } public void OnPointerExit(PointerEventData eventData) { RKLog.Info($"====InteractorButton==== E {eventData?.currentInputModule?.GetType().Name} pointerExit"); hoverEnter = false; buttonUp.position = transform.position - transform.forward * normalOffsetAlongNormal; if (touchState != TouchState.Normal) { touchState = TouchState.Normal; onStateChanged?.Invoke(touchState); } foreach (var item in _pokeInteractors) { item.InteractorButtonUpPosition = Vector3.zero; } onPointerExit?.Invoke(eventData); pointerDown = false; } public void OnPointerClick(PointerEventData eventData) { onPointerClick?.Invoke(eventData); } } }