Unity Udexreal开发插件包
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.

1270 lines
35 KiB

using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using NaughtyAttributes;
namespace UDE_HAND_INTERACTION
{
public enum InteractorState
{
Normal,
Hover,
Select,
Disabled
};
public enum InteractableState
{
Normal,
Hover,
Select,
Disabled
};
public interface IActiveState
{
bool Active { get; }
}
public interface IGameObjectFilter
{
bool Filter(GameObject gameObject);
}
public struct InteractorStateChangeArgs
{
public InteractorState PreviousState { get; }
public InteractorState NewState { get; }
public InteractorStateChangeArgs(InteractorState previousState, InteractorState newState)
{
PreviousState = previousState;
NewState = newState;
}
}
public interface IInteractorView
{
int Identifier { get; }
bool HasCandidate { get; }
object CandidateProperties { get; }
bool HasInteractable { get; }
bool HasSelectedInteractable { get; }
InteractorState State { get; }
event Action<InteractorStateChangeArgs> WhenStateChanged;
event Action WhenPreprocessed;
event Action WhenProcessed;
event Action WhenPostprocessed;
}
public interface IUpdateDriver
{
bool IsRootDriver { get; set; }
void Drive();
}
public interface IInteractor : IInteractorView, IUpdateDriver
{
void Preprocess();
void Process();
void Postprocess();
void ProcessCandidate();
void Enable();
void Disable();
void Hover();
void Unhover();
void Select();
void Unselect();
bool ShouldHover { get; }
bool ShouldUnhover { get; }
bool ShouldSelect { get; }
bool ShouldUnselect { get; }
}
public interface MAction<out T>
{
event Action<T> Action;
}
public class MultiAction<T> : MAction<T>
{
protected HashSet<Action<T>> actions = new HashSet<Action<T>>();
public event Action<T> Action
{
add
{
actions.Add(value);
}
remove
{
actions.Remove(value);
}
}
public void Invoke(T t)
{
foreach (Action<T> action in actions)
{
action(t);
}
}
}
public class UniqueIdentifier
{
public int ID { get; private set; }
private UniqueIdentifier(int identifier)
{
ID = identifier;
}
private static System.Random Random = new();
private static HashSet<int> _identifierSet = new();
public static UniqueIdentifier Generate()
{
while (true)
{
int identifier = Random.Next(Int32.MaxValue);
if (_identifierSet.Contains(identifier)) continue;
_identifierSet.Add(identifier);
return new UniqueIdentifier(identifier);
}
}
public static void Release(UniqueIdentifier identifier)
{
_identifierSet.Remove(identifier.ID);
}
}
public abstract class Interactor<interactor, interactable> : MonoBehaviour, IInteractor
where interactor : Interactor<interactor, interactable>
where interactable : Interactable<interactor, interactable>
{
private Func<interactable> _computeCandidateOverride;
private bool _clearComputeCandidateOverrideOnSelect = false;
private Func<bool> _computeShouldSelectOverride;
private bool _clearComputeShouldSelectOverrideOnSelect = false;
private Func<bool> _computeShouldUnselectOverride;
private bool _clearComputeShouldUnselectOverrideOnUnselect;
protected virtual void DoPreprocess() { }
protected virtual void DoNormalUpdate() { }
protected virtual void DoHoverUpdate() { }
protected virtual void DoSelectUpdate() { }
protected virtual void DoPostprocess() { }
public virtual bool ShouldHover
{
get
{
if (State != InteractorState.Normal)
{
return false;
}
return HasCandidate || ComputeShouldSelect();
}
}
public virtual bool ShouldUnhover
{
get
{
if (State != InteractorState.Hover)
{
return false;
}
return _interactable != _candidate || _candidate == null;
}
}
public bool ShouldSelect
{
get
{
if (State != InteractorState.Hover)
{
return false;
}
if (_computeShouldSelectOverride != null)
{
return _computeShouldSelectOverride.Invoke();
}
return _candidate == _interactable && ComputeShouldSelect();
}
}
public bool ShouldUnselect
{
get
{
if (State != InteractorState.Select)
{
return false;
}
if (_computeShouldUnselectOverride != null)
{
return _computeShouldUnselectOverride.Invoke();
}
return ComputeShouldUnselect();
}
}
protected virtual bool ComputeShouldSelect()
{
return QueuedSelect;
}
protected virtual bool ComputeShouldUnselect()
{
return QueuedUnselect;
}
public interface ISelector
{
event Action WhenSelected;
event Action WhenUnselected;
}
private InteractorState _state = InteractorState.Normal;
public event Action<InteractorStateChangeArgs> WhenStateChanged = delegate { };
public event Action WhenPreprocessed = delegate { };
public event Action WhenProcessed = delegate { };
public event Action WhenPostprocessed = delegate { };
private ISelector _selector = null;
[SerializeField, Label("Check Rate Per Frame")]
private int _maxIterationsPerFrame = 3;
public int MaxIterationsPerFrame
{
get
{
return _maxIterationsPerFrame;
}
set
{
_maxIterationsPerFrame = value;
}
}
private Queue<bool> _selectorQueue = new();
private bool QueuedSelect => _selectorQueue.Count > 0 && _selectorQueue.Peek();
private bool QueuedUnselect => _selectorQueue.Count > 0 && !_selectorQueue.Peek();
public InteractorState State
{
get
{
return _state;
}
private set
{
if (_state == value)
{
return;
}
InteractorState previousState = _state;
_state = value;
WhenStateChanged(new InteractorStateChangeArgs(previousState, _state));
}
}
protected interactable _candidate;
protected interactable _interactable;
protected interactable _selectedInteractable;
public virtual object CandidateProperties
{
get
{
return null;
}
}
public interactable Interactable => _interactable;
public bool HasCandidate => _candidate != null;
public bool HasInteractable => _interactable != null;
public bool HasSelectedInteractable => _selectedInteractable != null;
protected virtual void InteractableSelected(interactable interactable) { }
private UniqueIdentifier _identifier;
public int Identifier => _identifier.ID;
protected bool _started;
protected virtual void Awake()
{
_identifier = UniqueIdentifier.Generate();
}
protected virtual void Start()
{
this.BeginStart(ref _started);
this.EndStart(ref _started);
}
protected virtual void OnEnable()
{
if (_started)
{
if (_selector != null)
{
_selectorQueue.Clear();
_selector.WhenSelected += HandleSelected;
_selector.WhenUnselected += HandleUnselected;
}
}
}
protected virtual void OnDisable()
{
if (_started)
{
if (_selector != null)
{
_selector.WhenSelected -= HandleSelected;
_selector.WhenUnselected -= HandleUnselected;
}
Disable();
}
}
protected virtual void OnDestroy()
{
UniqueIdentifier.Release(_identifier);
}
public virtual void SetComputeCandidateOverride(Func<interactable> computeCandidate,
bool shouldClearOverrideOnSelect = true)
{
_computeCandidateOverride = computeCandidate;
_clearComputeCandidateOverrideOnSelect = shouldClearOverrideOnSelect;
}
public virtual void ClearComputeCandidateOverride()
{
_computeCandidateOverride = null;
_clearComputeCandidateOverrideOnSelect = false;
}
public virtual void SetComputeShouldSelectOverride(Func<bool> computeShouldSelect,
bool clearOverrideOnSelect = true)
{
_computeShouldSelectOverride = computeShouldSelect;
_clearComputeShouldSelectOverrideOnSelect = clearOverrideOnSelect;
}
public virtual void ClearComputeShouldSelectOverride()
{
_computeShouldSelectOverride = null;
_clearComputeShouldSelectOverrideOnSelect = false;
}
public virtual void SetComputeShouldUnselectOverride(Func<bool> computeShouldUnselect,
bool clearOverrideOnUnselect = true)
{
_computeShouldUnselectOverride = computeShouldUnselect;
_clearComputeShouldUnselectOverrideOnUnselect = clearOverrideOnUnselect;
}
public virtual void ClearComputeShouldUnselectOverride()
{
_computeShouldUnselectOverride = null;
_clearComputeShouldUnselectOverrideOnUnselect = false;
}
public void Preprocess()
{
DoPreprocess();
WhenPreprocessed();
}
public void Process()
{
switch (State)
{
case InteractorState.Normal:
DoNormalUpdate();
break;
case InteractorState.Hover:
DoHoverUpdate();
break;
case InteractorState.Select:
DoSelectUpdate();
break;
}
WhenProcessed();
}
public void Postprocess()
{
_selectorQueue.Clear();
DoPostprocess();
WhenPostprocessed();
}
public virtual void ProcessCandidate()
{
_candidate = null;
if (_computeCandidateOverride != null)
{
_candidate = _computeCandidateOverride.Invoke();
}
else
{
_candidate = ComputeCandidate();
}
}
public void InteractableChangesUpdate()
{
if (_selectedInteractable != null &&
!_selectedInteractable.HasSelectingInteractor(this as interactor))
{
UnselectInteractable();
}
if (_interactable != null &&
!_interactable.HasInteractor(this as interactor))
{
UnsetInteractable();
}
}
public void Hover()
{
if (State != InteractorState.Normal)
{
return;
}
SetInteractable(_candidate);
State = InteractorState.Hover;
}
public void Unhover()
{
if (State != InteractorState.Hover)
{
return;
}
UnsetInteractable();
State = InteractorState.Normal;
}
public virtual void Select()
{
if (State != InteractorState.Hover)
{
return;
}
if (_clearComputeCandidateOverrideOnSelect)
{
ClearComputeCandidateOverride();
}
if (_clearComputeShouldSelectOverrideOnSelect)
{
ClearComputeShouldSelectOverride();
}
while (QueuedSelect)
{
_selectorQueue.Dequeue();
}
if (Interactable != null)
{
SelectInteractable(Interactable);
}
State = InteractorState.Select;
}
public virtual void Unselect()
{
if (State != InteractorState.Select)
{
return;
}
if (_clearComputeShouldUnselectOverrideOnUnselect)
{
ClearComputeShouldUnselectOverride();
}
while (QueuedUnselect)
{
_selectorQueue.Dequeue();
}
UnselectInteractable();
State = InteractorState.Hover;
}
protected abstract interactable ComputeCandidate();
private void SetInteractable(interactable interactable)
{
if (_interactable == interactable)
{
return;
}
UnsetInteractable();
_interactable = interactable;
interactable.AddInteractor(this as interactor);
}
private void UnsetInteractable()
{
interactable interactable = _interactable;
if (interactable == null)
{
return;
}
_interactable = null;
interactable.RemoveInteractor(this as interactor);
}
private void SelectInteractable(interactable interactable)
{
Unselect();
_selectedInteractable = interactable;
interactable.AddSelectingInteractor(this as interactor);
}
private void UnselectInteractable()
{
interactable interactable = _selectedInteractable;
if (interactable == null)
{
return;
}
_selectedInteractable = null;
interactable.RemoveSelectingInteractor(this as interactor);
}
public void Enable()
{
if (State == InteractorState.Disabled)
{
State = InteractorState.Normal;
HandleEnabled();
}
}
public void Disable()
{
if (State == InteractorState.Disabled)
{
return;
}
HandleDisabled();
if (State == InteractorState.Select)
{
UnselectInteractable();
State = InteractorState.Hover;
}
if (State == InteractorState.Hover)
{
UnsetInteractable();
State = InteractorState.Normal;
}
if (State == InteractorState.Normal)
{
State = InteractorState.Disabled;
}
}
protected virtual void HandleEnabled() { }
protected virtual void HandleDisabled() { }
protected virtual void HandleSelected()
{
_selectorQueue.Enqueue(true);
}
protected virtual void HandleUnselected()
{
_selectorQueue.Enqueue(false);
}
public bool IsRootDriver { get; set; } = true;
protected virtual void Update()
{
if (!IsRootDriver)
{
return;
}
Drive();
}
public virtual void Drive()
{
Preprocess();
Enable();
InteractorState previousState = State;
for (int i = 0; i < MaxIterationsPerFrame; i++)
{
if (State == InteractorState.Normal ||
(State == InteractorState.Hover && previousState != InteractorState.Normal))
{
ProcessCandidate();
}
previousState = State;
Process();
if (State == InteractorState.Disabled)
{
break;
}
if (State == InteractorState.Normal)
{
if (ShouldHover)
{
Hover();
continue;
}
break;
}
if (State == InteractorState.Hover)
{
if (ShouldSelect)
{
Select();
continue;
}
if (ShouldUnhover)
{
Unhover();
continue;
}
break;
}
if (State == InteractorState.Select)
{
if (ShouldUnselect)
{
Unselect();
continue;
}
break;
}
}
Postprocess();
}
}
public struct InteractableStateChangeArgs
{
public InteractableState PreviousState { get; }
public InteractableState NewState { get; }
public InteractableStateChangeArgs(
InteractableState previousState,
InteractableState newState)
{
PreviousState = previousState;
NewState = newState;
}
}
public interface IInteractableView
{
InteractableState State { get; }
event Action<InteractableStateChangeArgs> WhenStateChanged;
int MaxInteractors { get; }
int MaxSelectingInteractors { get; }
IEnumerable<IInteractorView> InteractorViews { get; }
IEnumerable<IInteractorView> SelectingInteractorViews { get; }
event Action<IInteractorView> WhenInteractorViewAdded;
event Action<IInteractorView> WhenInteractorViewRemoved;
event Action<IInteractorView> WhenSelectingInteractorViewAdded;
event Action<IInteractorView> WhenSelectingInteractorViewRemoved;
}
public interface IInteractable : IInteractableView
{
void Enable();
void Disable();
new int MaxInteractors { get; set; }
new int MaxSelectingInteractors { get; set; }
void RemoveInteractorByIdentifier(int id);
}
public class InteractableRegistry<interactor, interactable>
where interactor : Interactor<interactor, interactable>
where interactable : Interactable<interactor, interactable>
{
public struct InteractableSet
{
private readonly IReadOnlyList<interactable> _data;
private readonly ISet<interactable> _onlyInclude;
private readonly interactor _testAgainst;
public InteractableSet( ISet<interactable> onlyInclude, interactor testAgainst)
{
_data = _interactables;
_onlyInclude = onlyInclude;
_testAgainst = testAgainst;
}
public Enumerator GetEnumerator()
{
return new Enumerator(this);
}
private bool Include(interactable interactable)
{
if (_onlyInclude != null && !_onlyInclude.Contains(interactable))
{
return false;
}
if (_testAgainst != null && !interactable.CanBeSelectedBy(_testAgainst))
{
return false;
}
return true;
}
public struct Enumerator
{
private readonly InteractableSet _set;
private int _position;
private IReadOnlyList<interactable> Data => _set._data;
public Enumerator(in InteractableSet set)
{
_set = set;
_position = -1;
}
public interactable Current
{
get
{
if (Data == null || _position < 0)
{
throw new System.InvalidOperationException();
}
return Data[_position];
}
}
public bool MoveNext()
{
if (Data == null)
{
return false;
}
do
{
_position++;
} while (_position < Data.Count &&
!_set.Include(Data[_position]));
return _position < Data.Count;
}
}
}
private static List<interactable> _interactables;
public InteractableRegistry()
{
_interactables = new List<interactable>();
}
public virtual void Register(interactable interactable)
{
_interactables.Add(interactable);
}
public virtual void Unregister(interactable interactable)
{
_interactables.Remove(interactable);
}
public virtual InteractableSet List(interactor interactor)
{
return new InteractableSet(null, interactor);
}
public virtual InteractableSet List()
{
return new InteractableSet(null, null);
}
}
public abstract class Interactable<interactor, interactable> : MonoBehaviour, IInteractable
where interactor : Interactor<interactor, interactable>
where interactable : Interactable<interactor, interactable>
{
private List<UnityEngine.Object> _interactorFilters = new();
private List<IGameObjectFilter> InteractorFilters = null;
private int _maxInteractors = -1;
private int _maxSelectingInteractors = -1;
private UnityEngine.Object _data = null;
public object Data { get; protected set; } = null;
protected bool _started = false;
#region Properties
public int MaxInteractors
{
get
{
return _maxInteractors;
}
set
{
_maxInteractors = value;
}
}
public int MaxSelectingInteractors
{
get
{
return _maxSelectingInteractors;
}
set
{
_maxSelectingInteractors = value;
}
}
#endregion
public IEnumerable<IInteractorView> InteractorViews => _interactors.Cast<IInteractorView>();
public IEnumerable<IInteractorView> SelectingInteractorViews => _selectingInteractors.Cast<IInteractorView>();
private EnumerableHashSet<interactor> _interactors = new();
private EnumerableHashSet<interactor> _selectingInteractors = new();
private InteractableState _state = InteractableState.Disabled;
public event Action<InteractableStateChangeArgs> WhenStateChanged = delegate { };
public event Action<IInteractorView> WhenInteractorViewAdded = delegate { };
public event Action<IInteractorView> WhenInteractorViewRemoved = delegate { };
public event Action<IInteractorView> WhenSelectingInteractorViewAdded = delegate { };
public event Action<IInteractorView> WhenSelectingInteractorViewRemoved = delegate { };
private MultiAction<interactor> _whenInteractorAdded = new();
private MultiAction<interactor> _whenInteractorRemoved = new();
private MultiAction<interactor> _whenSelectingInteractorAdded = new();
private MultiAction<interactor> _whenSelectingInteractorRemoved = new();
public MAction<interactor> WhenInteractorAdded => _whenInteractorAdded;
public MAction<interactor> WhenInteractorRemoved => _whenInteractorRemoved;
public InteractableState State
{
get
{
return _state;
}
private set
{
if (_state == value) return;
InteractableState previousState = _state;
_state = value;
WhenStateChanged(new InteractableStateChangeArgs(previousState, _state));
}
}
private static InteractableRegistry<interactor, interactable> _registry = new();
public static InteractableRegistry<interactor, interactable> Registry => _registry;
protected virtual void InteractorAdded(interactor interactor)
{
WhenInteractorViewAdded(interactor);
_whenInteractorAdded.Invoke(interactor);
}
protected virtual void InteractorRemoved(interactor interactor)
{
WhenInteractorViewRemoved(interactor);
_whenInteractorRemoved.Invoke(interactor);
}
protected virtual void SelectingInteractorAdded(interactor interactor)
{
WhenSelectingInteractorViewAdded(interactor);
_whenSelectingInteractorAdded.Invoke(interactor);
}
protected virtual void SelectingInteractorRemoved(interactor interactor)
{
WhenSelectingInteractorViewRemoved(interactor);
_whenSelectingInteractorRemoved.Invoke(interactor);
}
public IEnumerableHashSet<interactor> Interactors => _interactors;
public void AddInteractor(interactor interactor)
{
_interactors.Add(interactor);
InteractorAdded(interactor);
UpdateInteractableState();
}
public void RemoveInteractor(interactor interactor)
{
if (!_interactors.Remove(interactor))
{
return;
}
interactor.InteractableChangesUpdate();
InteractorRemoved(interactor);
UpdateInteractableState();
}
public void AddSelectingInteractor(interactor interactor)
{
_selectingInteractors.Add(interactor);
SelectingInteractorAdded(interactor);
UpdateInteractableState();
}
public void RemoveSelectingInteractor(interactor interactor)
{
if (!_selectingInteractors.Remove(interactor))
{
return;
}
interactor.InteractableChangesUpdate();
SelectingInteractorRemoved(interactor);
UpdateInteractableState();
}
private void UpdateInteractableState()
{
if (State == InteractableState.Disabled) return;
if (_selectingInteractors.Count > 0)
{
State = InteractableState.Select;
}
else if (_interactors.Count > 0)
{
State = InteractableState.Hover;
}
else
{
State = InteractableState.Normal;
}
}
public bool CanBeSelectedBy(interactor interactor)
{
if (State == InteractableState.Disabled)
{
return false;
}
if (MaxSelectingInteractors >= 0 &&
_selectingInteractors.Count == MaxSelectingInteractors)
{
return false;
}
if (MaxInteractors >= 0 &&
_interactors.Count == MaxInteractors &&
!_interactors.Contains(interactor))
{
return false;
}
if (InteractorFilters == null)
{
return true;
}
foreach (IGameObjectFilter interactorFilter in InteractorFilters)
{
if (!interactorFilter.Filter(interactor.gameObject))
{
return false;
}
}
return true;
}
public bool HasInteractor(interactor interactor)
{
return _interactors.Contains(interactor);
}
public bool HasSelectingInteractor(interactor interactor)
{
return _selectingInteractors.Contains(interactor);
}
public void Enable()
{
if (State != InteractableState.Disabled)
{
return;
}
if (_started)
{
_registry.Register((interactable)this);
State = InteractableState.Normal;
}
}
public void Disable()
{
if (State == InteractableState.Disabled)
{
return;
}
if (_started)
{
List<interactor> selectingInteractorsCopy = new List<interactor>(_selectingInteractors);
foreach (interactor selectingInteractor in selectingInteractorsCopy)
{
RemoveSelectingInteractor(selectingInteractor);
}
List<interactor> interactorsCopy = new List<interactor>(_interactors);
foreach (interactor interactor in interactorsCopy)
{
RemoveInteractor(interactor);
}
_registry.Unregister((interactable)this);
State = InteractableState.Disabled;
}
}
public void RemoveInteractorByIdentifier(int id)
{
interactor foundInteractor = null;
foreach (interactor selectingInteractor in _selectingInteractors)
{
if (selectingInteractor.Identifier == id)
{
foundInteractor = selectingInteractor;
break;
}
}
if (foundInteractor != null)
{
RemoveSelectingInteractor(foundInteractor);
}
foundInteractor = null;
foreach (interactor interactor in _interactors)
{
if (interactor.Identifier == id)
{
foundInteractor = interactor;
break;
}
}
if (foundInteractor == null)
{
return;
}
RemoveInteractor(foundInteractor);
}
protected virtual void Awake()
{
InteractorFilters = _interactorFilters.ConvertAll(mono => mono as IGameObjectFilter);
}
protected virtual void Start()
{
this.BeginStart(ref _started);
if (Data == null)
{
_data = this;
Data = _data;
}
this.EndStart(ref _started);
}
protected virtual void OnEnable()
{
Enable();
}
protected virtual void OnDisable()
{
Disable();
}
}
public interface IEnumerableHashSet<T> : IEnumerable<T>
{
new HashSet<T>.Enumerator GetEnumerator();
}
public class EnumerableHashSet<T> : HashSet<T>, IEnumerableHashSet<T>
{
public EnumerableHashSet() : base() { }
public EnumerableHashSet(IEnumerable<T> values) : base(values) { }
}
public static class MonoBehaviourStartExtensions
{
public static void BeginStart(this MonoBehaviour monoBehaviour, ref bool started, Action baseStart = null)
{
if (!started)
{
monoBehaviour.enabled = false;
started = true;
baseStart?.Invoke();
started = false;
}
else
{
baseStart?.Invoke();
}
}
public static void EndStart(this MonoBehaviour monoBehaviour, ref bool started)
{
if (!started)
{
started = true;
monoBehaviour.enabled = true;
}
}
}
[Serializable]
public class ProgressCurve
{
[SerializeField]
private AnimationCurve _animationCurve;
[SerializeField]
private float _animationLength;
private Func<float> _timeProvider = () => Time.time;
private float _animationStartTime;
public ProgressCurve()
{
_animationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f);
_animationLength = 1.0f;
}
public ProgressCurve(AnimationCurve animationCurve, float animationLength)
{
_animationCurve = animationCurve;
_animationLength = animationLength;
}
public void Copy(ProgressCurve other)
{
_animationCurve = other._animationCurve;
_animationLength = other._animationLength;
_animationStartTime = other._animationStartTime;
_timeProvider = other._timeProvider;
}
public void Start()
{
_animationStartTime = _timeProvider();
}
public float Progress()
{
if (_animationLength <= 0f)
{
return _animationCurve.Evaluate(1.0f);
}
float normalizedTimeProgress = Mathf.Clamp01(ProgressTime() / _animationLength);
return _animationCurve.Evaluate(normalizedTimeProgress);
}
public float ProgressTime()
{
return Mathf.Clamp(_timeProvider() - _animationStartTime, 0f, _animationLength);
}
}
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false)]
public class InterfaceAttribute : PropertyAttribute
{
public Type[] Types = null;
public string TypeFromFieldName;
public InterfaceAttribute(Type type, params Type[] types)
{
Debug.Assert(type.IsInterface, $"{type.Name} needs to be an interface.");
Types = new Type[types.Length + 1];
Types[0] = type;
for (int i = 0; i < types.Length; i++)
{
Debug.Assert(types[i].IsInterface, $"{types[i].Name} needs to be an interface.");
Types[i + 1] = types[i];
}
}
}
}