You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
256 lines
9.3 KiB
256 lines
9.3 KiB
using NaughtyAttributes; |
|
using System; |
|
using System.Collections.Generic; |
|
using UnityEngine; |
|
using UnityEngine.Events; |
|
using UnityEngine.UI; |
|
|
|
namespace UDE_HAND_INTERACTION |
|
{ |
|
public class FingerPressController : MonoBehaviour |
|
{ |
|
private FingerPressInteractable _fingerPressInteractable; |
|
|
|
[SerializeField] |
|
private Transform _buttonBaseTransform; |
|
|
|
[SerializeField, Interface(typeof(IInteractableView))] |
|
private IInteractableView InteractableView; |
|
|
|
|
|
private enum QuadStyle |
|
{ |
|
PureColor, |
|
Sprite |
|
} |
|
[SerializeField, Space] |
|
private QuadStyle _quadStyle; |
|
|
|
private bool QuadStyleCheck => _quadStyle == QuadStyle.PureColor; |
|
private bool InUILayer; |
|
|
|
[SerializeField, ShowIf("QuadStyleCheck")] |
|
private Renderer _renderer; |
|
|
|
[SerializeField, ShowIf("QuadStyleCheck")] |
|
private Color _normalColor = Color.red; |
|
|
|
[SerializeField, ShowIf("QuadStyleCheck")] |
|
private Color _hoverColor = Color.blue; |
|
|
|
[SerializeField, ShowIf("QuadStyleCheck")] |
|
private Color _selectColor = Color.green; |
|
|
|
[SerializeField, ShowIf("QuadStyleCheck")] |
|
private Color _disabledColor = Color.black; |
|
|
|
private Image imageSprite; |
|
private SpriteRenderer spriteRender; |
|
|
|
[SerializeField, HideIf("QuadStyleCheck")] |
|
private Sprite _normalSprite; |
|
|
|
[SerializeField, HideIf("QuadStyleCheck")] |
|
private Sprite _hoverSprite; |
|
|
|
[SerializeField, HideIf("QuadStyleCheck")] |
|
private Sprite _selectSprite; |
|
|
|
[SerializeField, HideIf("QuadStyleCheck")] |
|
private Sprite _disabledSprite; |
|
|
|
[Space] |
|
public UnityEvent OnHover; |
|
public UnityEvent OnSelect; |
|
|
|
private float _maxOffsetAlongNormal; |
|
private Vector2 _planarOffset; |
|
|
|
private HashSet<FingerPressInteractor> _fingerPressInteractors; |
|
private FingerPressInteractor _postProcessInteractor; |
|
|
|
private Action _postProcessHandler => UpdateComponentPosition; |
|
|
|
private Material _material; |
|
protected bool _started = false; |
|
|
|
protected virtual void Start() |
|
{ |
|
this.BeginStart(ref _started); |
|
_fingerPressInteractable = transform.parent.GetComponent<FingerPressInteractable>(); |
|
this.AssertField(_fingerPressInteractable, nameof(_fingerPressInteractable)); |
|
this.AssertField(_buttonBaseTransform, nameof(_buttonBaseTransform)); |
|
InUILayer = transform.GetChild(0).GetComponent<RectTransform>() != null; |
|
if (InUILayer) |
|
{ |
|
imageSprite = GetComponentInChildren<Image>(); |
|
imageSprite.enabled = !QuadStyleCheck; |
|
} |
|
else if(!QuadStyleCheck) |
|
{ |
|
spriteRender = GetComponentInChildren<SpriteRenderer>(); |
|
spriteRender.enabled = true; |
|
} |
|
_material = _renderer.material; |
|
if(_renderer == null) |
|
GetComponent<MeshRenderer>().enabled = QuadStyleCheck; |
|
UpdateVisual(); |
|
_fingerPressInteractors = new(); |
|
_maxOffsetAlongNormal = Vector3.Dot(transform.position - _buttonBaseTransform.position, -1f * _buttonBaseTransform.forward); |
|
Vector3 pointOnPlane = transform.position - _maxOffsetAlongNormal * _buttonBaseTransform.forward; |
|
_planarOffset = new Vector2( Vector3.Dot(pointOnPlane - _buttonBaseTransform.position, _buttonBaseTransform.right), Vector3.Dot(pointOnPlane - _buttonBaseTransform.position, _buttonBaseTransform.up)); |
|
this.EndStart(ref _started); |
|
} |
|
|
|
protected virtual void OnEnable() |
|
{ |
|
if (_started) |
|
{ |
|
_fingerPressInteractors.Clear(); |
|
_fingerPressInteractors.UnionWith(_fingerPressInteractable.Interactors); |
|
_fingerPressInteractable.WhenInteractorAdded.Action += HandleInteractorAdded; |
|
_fingerPressInteractable.WhenInteractorRemoved.Action += HandleInteractorRemoved; |
|
_fingerPressInteractable.WhenStateChanged += UpdateVisualState; |
|
UpdateVisual(); |
|
} |
|
} |
|
|
|
protected virtual void OnDisable() |
|
{ |
|
if (_started) |
|
{ |
|
_fingerPressInteractors.Clear(); |
|
_fingerPressInteractable.WhenInteractorAdded.Action -= HandleInteractorAdded; |
|
_fingerPressInteractable.WhenInteractorRemoved.Action -= HandleInteractorRemoved; |
|
_fingerPressInteractable.WhenStateChanged -= UpdateVisualState; |
|
if (_postProcessInteractor) |
|
{ |
|
_postProcessInteractor.WhenPostprocessed -= _postProcessHandler; |
|
_postProcessInteractor = null; |
|
} |
|
} |
|
} |
|
|
|
private void OnDestroy() |
|
{ |
|
Destroy(_material); |
|
} |
|
|
|
private void UpdateVisual() |
|
{ |
|
switch (_fingerPressInteractable.State) |
|
{ |
|
case InteractableState.Normal: |
|
if (!QuadStyleCheck) |
|
{ |
|
if(InUILayer) |
|
imageSprite.sprite = _normalSprite; |
|
else |
|
spriteRender.sprite = _normalSprite; |
|
} |
|
else |
|
{ |
|
_material.color = _normalColor; |
|
} |
|
break; |
|
case InteractableState.Hover: |
|
if (!QuadStyleCheck) |
|
{ |
|
if (InUILayer) |
|
imageSprite.sprite = _hoverSprite; |
|
else |
|
spriteRender.sprite = _hoverSprite; |
|
} |
|
else |
|
{ |
|
_material.color = _hoverColor; |
|
} |
|
OnHover.Invoke(); |
|
break; |
|
case InteractableState.Select: |
|
if (!QuadStyleCheck) |
|
{ |
|
if (InUILayer) |
|
imageSprite.sprite = _selectSprite; |
|
else |
|
spriteRender.sprite = _selectSprite; |
|
} |
|
else |
|
{ |
|
_material.color = _selectColor; |
|
} |
|
OnSelect.Invoke(); |
|
break; |
|
case InteractableState.Disabled: |
|
if (!QuadStyleCheck) |
|
{ |
|
if (InUILayer) |
|
imageSprite.sprite = _disabledSprite; |
|
else |
|
spriteRender.sprite = _disabledSprite; |
|
} |
|
else |
|
{ |
|
_material.color = _disabledColor; |
|
} |
|
break; |
|
} |
|
} |
|
private void UpdateVisualState(InteractableStateChangeArgs args) => UpdateVisual(); |
|
|
|
private void HandleInteractorAdded(FingerPressInteractor fingerPressInteractable) |
|
{ |
|
_fingerPressInteractors.Add(fingerPressInteractable); |
|
|
|
if (_postProcessInteractor == null) |
|
{ |
|
_postProcessInteractor = fingerPressInteractable; |
|
_postProcessInteractor.WhenPostprocessed += _postProcessHandler; |
|
} |
|
} |
|
|
|
private void HandleInteractorRemoved(FingerPressInteractor fingerPressInteractor) |
|
{ |
|
_fingerPressInteractors.Remove(fingerPressInteractor); |
|
|
|
if (fingerPressInteractor == _postProcessInteractor) |
|
{ |
|
_postProcessInteractor.WhenPostprocessed -= _postProcessHandler; |
|
using var enumerator = _fingerPressInteractors.GetEnumerator(); |
|
if (enumerator.MoveNext() && enumerator.Current != null) |
|
{ |
|
_postProcessInteractor = enumerator.Current; |
|
_postProcessInteractor.WhenPostprocessed += _postProcessHandler; |
|
} |
|
else |
|
{ |
|
_postProcessInteractor = null; |
|
UpdateComponentPosition(); |
|
} |
|
} |
|
} |
|
|
|
private void UpdateComponentPosition() |
|
{ |
|
float closestDistance = _maxOffsetAlongNormal; |
|
foreach (FingerPressInteractor fingerPressInteractor in _fingerPressInteractors) |
|
{ |
|
float pokeDistance = |
|
Vector3.Dot(fingerPressInteractor.Origin - _buttonBaseTransform.position, |
|
-1f * _buttonBaseTransform.forward); |
|
pokeDistance -= fingerPressInteractor.Radius; |
|
if (pokeDistance < 0f) |
|
{ |
|
pokeDistance = 0f; |
|
} |
|
|
|
closestDistance = Math.Min(pokeDistance, closestDistance); |
|
} |
|
|
|
transform.position = _buttonBaseTransform.position + |
|
_buttonBaseTransform.forward * (-1f * closestDistance) + |
|
_buttonBaseTransform.right * _planarOffset.x + |
|
_buttonBaseTransform.up * _planarOffset.y; |
|
} |
|
} |
|
}
|
|
|