InteractableRegistry.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. namespace Rokid.UXR.Interaction
  4. {
  5. /// <summary>
  6. /// A registry that houses a set of concrete Interactables.
  7. /// 包含一组具体可交互对象的注册表。
  8. /// </summary>
  9. public class InteractableRegistry<TInteractor, TInteractable>
  10. where TInteractor : Interactor<TInteractor, TInteractable>
  11. where TInteractable : Interactable<TInteractor, TInteractable>
  12. {
  13. /// <summary>
  14. /// Allocation-free collection that can be iterated over
  15. /// to provide a pruned list of Interactables.
  16. /// </summary>
  17. public struct InteractableSet : IEnumerable<TInteractable>
  18. {
  19. private readonly IReadOnlyList<TInteractable> _data;
  20. private readonly ISet<TInteractable> _onlyInclude;
  21. private readonly TInteractor _testAgainst;
  22. /// <summary>
  23. /// A pruned set of interactables from the
  24. /// <see cref="InteractableRegistry{TInteractor, TInteractable}"/>
  25. /// </summary>
  26. /// <param name="onlyInclude">Include only these interactables from
  27. /// the base <see cref="_interactables"/> collection.
  28. /// Provide a null value to skip this filtering.</param>
  29. /// <param name="testAgainst">Filter against an interactor.
  30. /// Provide a null value to skip this filtering.</param>
  31. public InteractableSet(
  32. ISet<TInteractable> onlyInclude,
  33. TInteractor testAgainst)
  34. {
  35. _data = _interactables;
  36. _onlyInclude = onlyInclude;
  37. _testAgainst = testAgainst;
  38. }
  39. public Enumerator GetEnumerator()
  40. {
  41. return new Enumerator(this);
  42. }
  43. IEnumerator<TInteractable> IEnumerable<TInteractable>.GetEnumerator()
  44. {
  45. return GetEnumerator();
  46. }
  47. IEnumerator IEnumerable.GetEnumerator()
  48. {
  49. return GetEnumerator();
  50. }
  51. private bool Include(TInteractable interactable)
  52. {
  53. // Skip interactables not contained in a provided subset
  54. if (_onlyInclude != null)
  55. {
  56. if (!_onlyInclude.Contains(interactable))
  57. {
  58. return false;
  59. }
  60. }
  61. // Skip interactables that fail test against interactable
  62. if (_testAgainst != null)
  63. {
  64. if (!_testAgainst.CanSelect(interactable))
  65. {
  66. return false;
  67. }
  68. if (!interactable.CanBeSelectedBy(_testAgainst))
  69. {
  70. return false;
  71. }
  72. }
  73. return true;
  74. }
  75. public struct Enumerator : IEnumerator<TInteractable>
  76. {
  77. private readonly InteractableSet _set;
  78. private int _position;
  79. private IReadOnlyList<TInteractable> Data => _set._data;
  80. public Enumerator(in InteractableSet set)
  81. {
  82. _set = set;
  83. _position = -1;
  84. }
  85. public TInteractable Current
  86. {
  87. get
  88. {
  89. if (Data == null || _position < 0)
  90. {
  91. throw new System.InvalidOperationException();
  92. }
  93. return Data[_position];
  94. }
  95. }
  96. object IEnumerator.Current => Current;
  97. public bool MoveNext()
  98. {
  99. if (Data == null)
  100. {
  101. return false;
  102. }
  103. do
  104. {
  105. _position++;
  106. } while (_position < Data.Count &&
  107. !_set.Include(Data[_position]));
  108. return _position < Data.Count;
  109. }
  110. public void Reset()
  111. {
  112. _position = -1;
  113. }
  114. public void Dispose()
  115. {
  116. }
  117. }
  118. }
  119. private static List<TInteractable> _interactables;
  120. public InteractableRegistry()
  121. {
  122. _interactables = new List<TInteractable>();
  123. }
  124. public virtual void Register(TInteractable interactable)
  125. {
  126. _interactables.Add(interactable);
  127. }
  128. public virtual void Unregister(TInteractable interactable)
  129. {
  130. _interactables.Remove(interactable);
  131. }
  132. /// <summary>
  133. /// Returns a filtered collection of interactables
  134. /// </summary>
  135. /// <param name="interactor">Only interactables that can be selected by
  136. /// this interactor will be returned</param>
  137. /// <param name="onlyInclude">Only interactables included in this
  138. /// subset will be included in the returned collection</param>
  139. protected InteractableSet List(TInteractor interactor,
  140. HashSet<TInteractable> onlyInclude)
  141. {
  142. return new InteractableSet(onlyInclude, interactor);
  143. }
  144. /// <summary>
  145. /// Returns a filtered collection of interactables
  146. /// </summary>
  147. /// <param name="interactor">Only interactables that can be selected by
  148. /// this interactor will be returned</param>
  149. public virtual InteractableSet List(TInteractor interactor)
  150. {
  151. return new InteractableSet(null, interactor);
  152. }
  153. /// <summary>
  154. /// Returns all interactables in this registry
  155. /// </summary>
  156. public virtual InteractableSet List()
  157. {
  158. return new InteractableSet(null, null);
  159. }
  160. }
  161. }