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.
257 lines
9.3 KiB
257 lines
9.3 KiB
|
1 month ago
|
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;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|