Interactable.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEngine.Assertions;
  6. namespace Rokid.UXR.Interaction {
  7. /// <summary>
  8. /// Interactable provides a base template for any kind of interactable object.
  9. /// An Interactable can have Hover and HandleSelected Interactor(s) acting on it.
  10. /// Concrete Interactables can define whether they have a One-to-One or
  11. /// One-to-Many relationship with their associated concrete Interactors.
  12. /// Interactable 为任何类型的可交互对象提供了一个基本模板。
  13. /// Interactable 可以有 Hover 和 HandleSelected Interactor(s) 作用于它。
  14. /// 具体的可交互对象可以定义它们是否具有一对一或
  15. /// 与其关联的具体交互器的一对多关系。
  16. /// </summary>
  17. public abstract class Interactable<TInteractor, TInteractable> : MonoBehaviour, IInteractable
  18. where TInteractor : Interactor<TInteractor, TInteractable>
  19. where TInteractable : Interactable<TInteractor, TInteractable>
  20. {
  21. [SerializeField, Interface(typeof(IGameObjectFilter)), Optional]
  22. private List<MonoBehaviour> _interactorFilters = new List<MonoBehaviour>();
  23. private List<IGameObjectFilter> InteractorFilters = null;
  24. /// <summary>
  25. /// The max Interactors and max selecting Interactors that this Interactable can
  26. /// have acting on it.
  27. /// -1 signifies NO limit (can have any number of Interactors)
  28. /// </summary>
  29. [SerializeField]
  30. private int _maxInteractors = -1;
  31. [SerializeField]
  32. private int _maxSelectingInteractors = -1;
  33. [SerializeField, Optional]
  34. private UnityEngine.Object _data = null;
  35. public object Data { get; protected set; } = null;
  36. #region Properties
  37. public int MaxInteractors
  38. {
  39. get
  40. {
  41. return _maxInteractors;
  42. }
  43. set
  44. {
  45. _maxInteractors = value;
  46. }
  47. }
  48. public int MaxSelectingInteractors
  49. {
  50. get
  51. {
  52. return _maxSelectingInteractors;
  53. }
  54. set
  55. {
  56. _maxSelectingInteractors = value;
  57. }
  58. }
  59. #endregion
  60. public IEnumerable<IInteractorView> InteractorViews => _interactors.Cast<IInteractorView>();
  61. public IEnumerable<IInteractorView> SelectingInteractorViews => _selectingInteractors.Cast<IInteractorView>();
  62. private HashSet<TInteractor> _interactors = new HashSet<TInteractor>();
  63. private HashSet<TInteractor> _selectingInteractors = new HashSet<TInteractor>();
  64. [SerializeField]
  65. private InteractableState _state = InteractableState.Normal;
  66. public event Action<InteractableStateChangeArgs> WhenStateChanged = delegate { };
  67. public event Action<IInteractorView> WhenInteractorViewAdded = delegate { };
  68. public event Action<IInteractorView> WhenInteractorViewRemoved = delegate { };
  69. public event Action<IInteractorView> WhenSelectingInteractorViewAdded = delegate { };
  70. public event Action<IInteractorView> WhenSelectingInteractorViewRemoved = delegate { };
  71. private MultiAction<TInteractor> _whenInteractorAdded = new MultiAction<TInteractor>();
  72. private MultiAction<TInteractor> _whenInteractorRemoved = new MultiAction<TInteractor>();
  73. private MultiAction<TInteractor> _whenSelectingInteractorAdded = new MultiAction<TInteractor>();
  74. private MultiAction<TInteractor> _whenSelectingInteractorRemoved = new MultiAction<TInteractor>();
  75. public MAction<TInteractor> WhenInteractorAdded => _whenInteractorAdded;
  76. public MAction<TInteractor> WhenInteractorRemoved => _whenInteractorRemoved;
  77. public MAction<TInteractor> WhenSelectingInteractorAdded => _whenSelectingInteractorAdded;
  78. public MAction<TInteractor> WhenSelectingInteractorRemoved => _whenSelectingInteractorRemoved;
  79. public InteractableState State
  80. {
  81. get
  82. {
  83. return _state;
  84. }
  85. private set
  86. {
  87. if (_state == value) return;
  88. InteractableState previousState = _state;
  89. _state = value;
  90. WhenStateChanged(new InteractableStateChangeArgs(previousState, _state));
  91. }
  92. }
  93. private static InteractableRegistry<TInteractor, TInteractable> _registry =
  94. new InteractableRegistry<TInteractor, TInteractable>();
  95. public static InteractableRegistry<TInteractor, TInteractable> Registry => _registry;
  96. protected virtual void InteractorAdded(TInteractor interactor)
  97. {
  98. WhenInteractorViewAdded(interactor);
  99. _whenInteractorAdded.Invoke(interactor);
  100. }
  101. protected virtual void InteractorRemoved(TInteractor interactor)
  102. {
  103. WhenInteractorViewRemoved(interactor);
  104. _whenInteractorRemoved.Invoke(interactor);
  105. }
  106. protected virtual void SelectingInteractorAdded(TInteractor interactor)
  107. {
  108. WhenSelectingInteractorViewAdded(interactor);
  109. _whenSelectingInteractorAdded.Invoke(interactor);
  110. }
  111. protected virtual void SelectingInteractorRemoved(TInteractor interactor)
  112. {
  113. WhenSelectingInteractorViewRemoved(interactor);
  114. _whenSelectingInteractorRemoved.Invoke(interactor);
  115. }
  116. public ICollection<TInteractor> Interactors => _interactors;
  117. public ICollection<TInteractor> SelectingInteractors => _selectingInteractors;
  118. public void AddInteractor(TInteractor interactor)
  119. {
  120. _interactors.Add(interactor);
  121. InteractorAdded(interactor);
  122. UpdateInteractableState();
  123. }
  124. public void RemoveInteractor(TInteractor interactor)
  125. {
  126. if (!_interactors.Remove(interactor))
  127. {
  128. return;
  129. }
  130. interactor.InteractableChangesUpdate();
  131. InteractorRemoved(interactor);
  132. UpdateInteractableState();
  133. }
  134. public void AddSelectingInteractor(TInteractor interactor)
  135. {
  136. _selectingInteractors.Add(interactor);
  137. SelectingInteractorAdded(interactor);
  138. UpdateInteractableState();
  139. }
  140. public void RemoveSelectingInteractor(TInteractor interactor)
  141. {
  142. if (!_selectingInteractors.Remove(interactor))
  143. {
  144. return;
  145. }
  146. interactor.InteractableChangesUpdate();
  147. SelectingInteractorRemoved(interactor);
  148. UpdateInteractableState();
  149. }
  150. private void UpdateInteractableState()
  151. {
  152. if (_selectingInteractors.Count > 0)
  153. {
  154. State = InteractableState.Select;
  155. }
  156. else if (_interactors.Count > 0)
  157. {
  158. State = InteractableState.Hover;
  159. }
  160. else
  161. {
  162. State = InteractableState.Normal;
  163. }
  164. }
  165. public bool CanBeSelectedBy(TInteractor interactor)
  166. {
  167. if (MaxSelectingInteractors >= 0 &&
  168. _selectingInteractors.Count == MaxSelectingInteractors)
  169. {
  170. return false;
  171. }
  172. if (MaxInteractors >= 0 &&
  173. _interactors.Count == MaxInteractors &&
  174. !_interactors.Contains(interactor))
  175. {
  176. return false;
  177. }
  178. if (InteractorFilters == null)
  179. {
  180. return true;
  181. }
  182. foreach (IGameObjectFilter interactorFilter in InteractorFilters)
  183. {
  184. if (!interactorFilter.Filter(interactor.gameObject))
  185. {
  186. return false;
  187. }
  188. }
  189. return true;
  190. }
  191. public bool HasInteractor(TInteractor interactor)
  192. {
  193. return _interactors.Contains(interactor);
  194. }
  195. public bool HasSelectingInteractor(TInteractor interactor)
  196. {
  197. return _selectingInteractors.Contains(interactor);
  198. }
  199. public void Enable()
  200. {
  201. // RKLog.Info($"====Interaction==== {this.gameObject.name}, register interactable");
  202. _registry.Register((TInteractable)this);
  203. State = InteractableState.Normal;
  204. }
  205. public void Disable()
  206. {
  207. List<TInteractor> selectingInteractorsCopy = new List<TInteractor>(_selectingInteractors);
  208. foreach (TInteractor selectingInteractor in selectingInteractorsCopy)
  209. {
  210. RemoveSelectingInteractor(selectingInteractor);
  211. }
  212. List<TInteractor> interactorsCopy = new List<TInteractor>(_interactors);
  213. foreach (TInteractor interactor in interactorsCopy)
  214. {
  215. RemoveInteractor(interactor);
  216. }
  217. RKLog.Info($"====Interaction==== {this.gameObject.name}, unregister interactable");
  218. _registry.Unregister((TInteractable)this);
  219. }
  220. public void RemoveInteractorByIdentifier(int id)
  221. {
  222. TInteractor foundInteractor = null;
  223. foreach (TInteractor selectingInteractor in _selectingInteractors)
  224. {
  225. if (selectingInteractor.Identifier == id)
  226. {
  227. foundInteractor = selectingInteractor;
  228. break;
  229. }
  230. }
  231. if (foundInteractor != null)
  232. {
  233. RemoveSelectingInteractor(foundInteractor);
  234. }
  235. foundInteractor = null;
  236. foreach (TInteractor interactor in _interactors)
  237. {
  238. if (interactor.Identifier == id)
  239. {
  240. foundInteractor = interactor;
  241. break;
  242. }
  243. }
  244. if (foundInteractor == null)
  245. {
  246. return;
  247. }
  248. RemoveInteractor(foundInteractor);
  249. }
  250. protected virtual void Awake()
  251. {
  252. InteractorFilters = _interactorFilters.ConvertAll(mono => mono as IGameObjectFilter);
  253. }
  254. protected virtual void Start()
  255. {
  256. foreach (IGameObjectFilter filter in InteractorFilters)
  257. {
  258. Assert.IsNotNull(filter);
  259. }
  260. if (Data == null)
  261. {
  262. _data = this;
  263. Data = _data;
  264. }
  265. }
  266. protected virtual void OnEnable()
  267. {
  268. Enable();
  269. }
  270. protected virtual void OnDisable()
  271. {
  272. Disable();
  273. }
  274. protected virtual void SetRegistry(InteractableRegistry<TInteractor, TInteractable> registry)
  275. {
  276. if (registry == _registry) return;
  277. var interactables = _registry.List();
  278. foreach (TInteractable interactable in interactables)
  279. {
  280. registry.Register(interactable);
  281. _registry.Unregister(interactable);
  282. }
  283. _registry = registry;
  284. }
  285. }
  286. }