/Assets/LeapMotion/Modules/InteractionEngine/Scripts/UI/Anchors/Anchor.cs

https://bitbucket.org/jonathondhartunisa/firstpersonsquared · C# · 238 lines · 152 code · 56 blank · 30 comment · 15 complexity · 23c53ea611a8f4c30089924674c41f92 MD5 · raw file

  1. /******************************************************************************
  2. * Copyright (C) Leap Motion, Inc. 2011-2017. *
  3. * Leap Motion proprietary and confidential. *
  4. * *
  5. * Use subject to the terms of the Leap Motion SDK Agreement available at *
  6. * https://developer.leapmotion.com/sdk_agreement, or another agreement *
  7. * between Leap Motion and you, your company or other organization. *
  8. ******************************************************************************/
  9. using Leap.Unity.Attributes;
  10. using Leap.Unity.RuntimeGizmos;
  11. using System;
  12. using System.Collections;
  13. using System.Collections.Generic;
  14. using UnityEngine;
  15. using UnityEngine.Events;
  16. namespace Leap.Unity.Interaction {
  17. public class Anchor : MonoBehaviour {
  18. private static HashSet<Anchor> _allAnchors;
  19. public static HashSet<Anchor> allAnchors {
  20. get {
  21. if (_allAnchors == null) {
  22. _allAnchors = new HashSet<Anchor>();
  23. }
  24. return _allAnchors;
  25. }
  26. }
  27. [Tooltip("Should this anchor allow multiple objects to be attached to it at the same time? "
  28. + "This property is enforced by AnchorGroups and AnchorableBehaviours.")]
  29. public bool allowMultipleObjects = false;
  30. [Tooltip("Should this anchor attempt to enable and disable the GameObjects of attached "
  31. + "AnchorableBehaviours when its own active state changes? If this setting is enabled, "
  32. + "the Anchor will deactivate the attached objects when its own GameObject is deactivated "
  33. + "or if its script is disabled, and similarly for becoming active or enabled.")]
  34. public bool matchActiveStateWithAttachedObjects = false;
  35. private HashSet<AnchorGroup> _groups = new HashSet<AnchorGroup>();
  36. public HashSet<AnchorGroup> groups { get { return _groups; } }
  37. private HashSet<AnchorableBehaviour> _preferringAnchorables = new HashSet<AnchorableBehaviour>();
  38. private HashSet<AnchorableBehaviour> _anchoredObjects = new HashSet<AnchorableBehaviour>();
  39. /// <summary>
  40. /// Gets the set of AnchorableBehaviours currently attached to this anchor.
  41. /// </summary>
  42. public HashSet<AnchorableBehaviour> anchoredObjects { get { return _anchoredObjects; } }
  43. public bool isPreferred { get { return _preferringAnchorables.Count > 0; } }
  44. public bool hasAnchoredObjects { get { return _anchoredObjects.Count > 0; } }
  45. #region Events
  46. /// <summary>
  47. /// Called as soon as any anchorable objects prefer this anchor if they were to try to
  48. /// attach to an anchor.
  49. /// </summary>
  50. public Action OnAnchorPreferred = () => { };
  51. /// <summary>
  52. /// Called when no anchorable objects prefer this anchor any more.
  53. /// </summary>
  54. public Action OnAnchorNotPreferred = () => { };
  55. /// <summary>
  56. /// Called every Update() that an AnchorableBehaviour prefers this anchor.
  57. /// </summary>
  58. public Action WhileAnchorPreferred = () => { };
  59. /// <summary>
  60. /// Called as soon as any anchorables become attached to this anchor.
  61. /// </summary>
  62. public Action OnAnchorablesAttached = () => { };
  63. /// <summary>
  64. /// Called when there are no anchorables attached to this anchor.
  65. /// </summary>
  66. public Action OnNoAnchorablesAttached = () => { };
  67. /// <summary>
  68. /// Called every Update() that one or more AnchorableBehaviours is attached to this anchor.
  69. /// </summary>
  70. public Action WhileAnchorablesAttached = () => { };
  71. #endregion
  72. void Awake() {
  73. allAnchors.Add(this);
  74. }
  75. void OnEnable() {
  76. if (matchActiveStateWithAttachedObjects) {
  77. foreach (var anchObj in _anchoredObjects) {
  78. anchObj.gameObject.SetActive(true);
  79. }
  80. }
  81. }
  82. void Start() {
  83. initUnityEvents();
  84. }
  85. void Update() {
  86. updateAnchorCallbacks();
  87. }
  88. void OnAnchorDisabled() {
  89. if (matchActiveStateWithAttachedObjects) {
  90. foreach (var anchObj in _anchoredObjects) {
  91. anchObj.gameObject.SetActive(false);
  92. }
  93. }
  94. }
  95. void OnDestroy() {
  96. foreach (var group in groups) {
  97. group.Remove(this);
  98. }
  99. allAnchors.Remove(this);
  100. }
  101. #region Anchor Callbacks
  102. public void NotifyAttached(AnchorableBehaviour anchObj) {
  103. _anchoredObjects.Add(anchObj);
  104. if (_anchoredObjects.Count == 1) {
  105. OnAnchorablesAttached();
  106. }
  107. }
  108. public void NotifyDetached(AnchorableBehaviour anchObj) {
  109. _anchoredObjects.Remove(anchObj);
  110. if (_anchoredObjects.Count == 0) {
  111. OnNoAnchorablesAttached();
  112. }
  113. }
  114. private void updateAnchorCallbacks() {
  115. WhileAnchorPreferred();
  116. WhileAnchorablesAttached();
  117. }
  118. public void NotifyAnchorPreference(AnchorableBehaviour anchObj) {
  119. _preferringAnchorables.Add(anchObj);
  120. if (_preferringAnchorables.Count == 1) {
  121. OnAnchorPreferred();
  122. }
  123. }
  124. public void NotifyEndAnchorPreference(AnchorableBehaviour anchObj) {
  125. _preferringAnchorables.Remove(anchObj);
  126. if (_preferringAnchorables.Count == 0) {
  127. OnAnchorNotPreferred();
  128. }
  129. }
  130. #endregion
  131. #region Gizmos
  132. public static Color AnchorGizmoColor = new Color(0.6F, 0.2F, 0.8F);
  133. void OnDrawGizmosSelected() {
  134. Matrix4x4 origMatrix = Gizmos.matrix;
  135. Gizmos.matrix = this.transform.localToWorldMatrix;
  136. Gizmos.color = AnchorGizmoColor;
  137. float radius = 0.015F;
  138. drawWireSphereGizmo(Vector3.zero, radius);
  139. drawSphereCirclesGizmo(5, Vector3.zero, radius, Vector3.forward);
  140. Gizmos.matrix = origMatrix;
  141. }
  142. private static Vector3[] worldDirs = new Vector3[] { Vector3.right, Vector3.up, Vector3.forward };
  143. private void drawWireSphereGizmo(Vector3 pos, float radius) {
  144. foreach (var dir in worldDirs) {
  145. if (dir == Vector3.forward) continue;
  146. Utils.DrawCircle(pos, dir, radius, AnchorGizmoColor, quality: 24, depthTest: true);
  147. }
  148. }
  149. private void drawSphereCirclesGizmo(int numCircles, Vector3 pos, float radius, Vector3 poleDir) {
  150. float dTheta = 180F / numCircles;
  151. float halfTheta = dTheta / 2F;
  152. for (int i = 0; i < numCircles; i++) {
  153. float curTheta = (dTheta * i) + halfTheta;
  154. Utils.DrawCircle(pos + poleDir * Mathf.Cos(curTheta * Mathf.Deg2Rad) * radius, poleDir, Mathf.Sin(curTheta * Mathf.Deg2Rad) * radius, AnchorGizmoColor, quality: 16, depthTest: true);
  155. }
  156. }
  157. #endregion
  158. #region Unity Events (Internal)
  159. [SerializeField]
  160. private EnumEventTable _eventTable;
  161. public enum EventType {
  162. OnAnchorPreferred = 100,
  163. OnAnchorNotPreferred = 110,
  164. WhileAnchorPreferred = 120,
  165. OnAnchorablesAttached = 130,
  166. OnNoAnchorablesAttached = 140,
  167. WhileAnchorablesAttached = 150,
  168. }
  169. private void initUnityEvents() {
  170. setupCallback(ref OnAnchorPreferred, EventType.OnAnchorPreferred);
  171. setupCallback(ref OnAnchorNotPreferred, EventType.OnAnchorNotPreferred);
  172. setupCallback(ref WhileAnchorPreferred, EventType.WhileAnchorPreferred);
  173. setupCallback(ref OnAnchorablesAttached, EventType.OnAnchorablesAttached);
  174. setupCallback(ref OnNoAnchorablesAttached, EventType.OnNoAnchorablesAttached);
  175. setupCallback(ref WhileAnchorablesAttached, EventType.WhileAnchorablesAttached);
  176. }
  177. private void setupCallback(ref Action action, EventType type) {
  178. action += () => _eventTable.Invoke((int)type);
  179. }
  180. #endregion
  181. }
  182. }