AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
BaseGrabbable.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System;
5 using System.Collections;
6 using System.Collections.Generic;
7 using UnityEngine;
8 
9 namespace HoloToolkit.Unity.InputModule.Examples.Grabbables
10 {
16  public abstract class BaseGrabbable : MonoBehaviour
17  {
18  public event Action<BaseGrabbable> OnGrabStateChange;
19  public event Action<BaseGrabbable> OnContactStateChange;
20  public event Action<BaseGrabbable> OnGrabbed;
21  public event Action<BaseGrabbable> OnReleased;
22 
23  public BaseGrabber GrabberPrimary
24  {
25  get
26  {
27  return activeGrabbers.Count > 0 ? activeGrabbers[activeGrabbers.Count - 1] : null;
28  }
29  }
30 
31  public BaseGrabber[] ActiveGrabbers
32  {
33  get
34  {
35  return activeGrabbers.ToArray();
36  }
37  }
38 
39  public Vector3 GrabPoint
40  {
41  get
42  {
43  return grabSpot != null ? grabSpot.position : transform.position;
44  }
45  }
46 
50  public GrabStateEnum GrabState
51  {
52  get
53  {
54  if (activeGrabbers.Count > 1)
55  {
56  return GrabStateEnum.Multi;
57  }
58 
59  return activeGrabbers.Count > 0 ? GrabStateEnum.Single : GrabStateEnum.Inactive;
60  }
61  }
62 
66  public GrabStateEnum ContactState
67  {
68  get
69  {
70  if (availableGrabbers.Count > 1)
71  return GrabStateEnum.Multi;
72  else if (availableGrabbers.Count > 0)
73  return GrabStateEnum.Single;
74  else
75  return GrabStateEnum.Inactive;
76  }
77  }
78 
83  protected HashSet<BaseGrabber> availableGrabbers = new HashSet<BaseGrabber>();
84 
89  protected List<BaseGrabber> activeGrabbers = new List<BaseGrabber>();
90 
91  //left protected unless we have the occasion to use them publicly, then switch to public access
92  [SerializeField]
93  protected Transform grabSpot;
94 
95  [SerializeField]
96  protected GrabStyleEnum grabStyle = GrabStyleEnum.Exclusive;
97 
98  private GrabStateEnum prevGrabState = GrabStateEnum.Inactive;
99  private GrabStateEnum prevContactState = GrabStateEnum.Inactive;
100  private Vector3 velocity;
101  private Vector3 averageVelocity;
102  private Vector3 previousVel;
103 
104  public virtual bool TryGrabWith(BaseGrabber grabber)
105  {
106  // TODO error checking, multi-grab checking
107  if (GrabState != GrabStateEnum.Inactive)
108  {
109  switch (grabStyle)
110  {
111  case GrabStyleEnum.Exclusive:
112  // Try to transfer ownership of grabbed object
113  BaseGrabber primary = GrabberPrimary;
114  if (GrabberPrimary.CanTransferOwnershipTo(this, grabber))
115  {
116  // Remove from grabbable list and detach
117  activeGrabbers.Remove(primary);
118  DetachFromGrabber(primary);
119  }
120  else
121  {
122  // If we can't, it's a no-go
123  return false;
124  }
125  break;
126  case GrabStyleEnum.Multi:
127  break;
128  default:
129  throw new ArgumentOutOfRangeException();
130  }
131  }
132 
133  StartGrab(grabber);
134  return true;
135  }
136 
140  public void AddContact(BaseGrabber availableObject)
141  {
142  availableGrabbers.Add(availableObject);
143  }
144 
148  public void RemoveContact(BaseGrabber availableObject)
149  {
150  availableGrabbers.Remove(availableObject);
151  }
152 
153  // The next three functions provide basic behavior. Extend from this base script in order to provide more specific functionality.
154 
155  protected virtual void AttachToGrabber(BaseGrabber grabber)
156  {
157  // By default this does nothing
158  // In most cases this will parent or create a joint
159  }
160 
161  protected virtual void DetachFromGrabber(BaseGrabber grabber)
162  {
163  // By default this does nothing
164  // In most cases this will un-parent or destroy a joint
165  }
166 
167  protected virtual void StartGrab(BaseGrabber grabber)
168  {
169  Debug.Log("Start grab");
170  if (GrabState == GrabStateEnum.Inactive)
171  {
172  Debug.Log("State is inactive");
173  // If we're not already updating our grab state, start now
174  activeGrabbers.Add(grabber);
175  StartCoroutine(StayGrab());
176  }
177  else
178  {
179  Debug.Log("State is not inactive");
180  // Otherwise just push the grabber
181  activeGrabbers.Add(grabber);
182  }
183 
184  // Attach ourselves to this grabber
185  AttachToGrabber(grabber);
186  if (OnGrabbed != null)
187  {
188  OnGrabbed(this);
189  }
190  }
191 
196  protected virtual IEnumerator StayGrab()
197  {
198  yield return null;
199 
200  // While grabbers are grabbing
201  while (GrabState != GrabStateEnum.Inactive)
202  {
203  // Call on grab stay in case this grabbable wants to update itself
204  OnGrabStay();
205  for (int i = activeGrabbers.Count - 1; i >= 0; i--)
206  {
207  if (activeGrabbers[i] == null || !activeGrabbers[i].IsGrabbing(this))
208  {
209  Debug.Log("no longer being grabbed by active grabber");
210  if (activeGrabbers[i] != null)
211  {
212  DetachFromGrabber(activeGrabbers[i]);
213  }
214 
215  activeGrabbers.RemoveAt(i);
216  }
217  }
218  yield return null;
219  }
220 
221  EndGrab();
222  }
227  protected virtual void EndGrab()
228  {
229  if (OnReleased != null)
230  {
231  OnReleased(this);
232  }
233  }
234 
238  protected virtual void OnGrabStay()
239  {
240  }
241 
242  protected virtual void Start()
243  {
244  }
245 
246  protected virtual void Update()
247  {
248  if (prevGrabState != GrabState && OnGrabStateChange != null)
249  {
250  Debug.Log("Calling on grab change in grabbable");
251  OnGrabStateChange(this);
252  }
253 
254  if (prevContactState != ContactState && OnContactStateChange != null)
255  {
256  Debug.Log("Calling on contact change in grabbable");
257  OnContactStateChange(this);
258  }
259 
260  prevGrabState = GrabState;
261  prevContactState = ContactState;
262  }
263  }
264 }
virtual void OnGrabStay()
Called every frame while StayGrab is active
virtual IEnumerator StayGrab()
As long as the grabber script (usually attached to the controller, but not always) reports more than ...
Intended usage: scripts that inherit from this can be attached to the controller, or any object with ...
Definition: BaseGrabber.cs:18
void RemoveContact(BaseGrabber availableObject)
Removes a grabber object from the list of available grabbers
void AddContact(BaseGrabber availableObject)
Adds a grabber object to the list of available grabbers
//Intended Usage// Attach a "grabbable_x" script (a script that inherits from this) to any object tha...
virtual void EndGrab()
Grab end fires off a GrabEnded event, but also cleans up some of the variables associated with an act...