Tanoda
LeapInputModule.cs
Go to the documentation of this file.
1/******************************************************************************
2 * Copyright (C) Ultraleap, Inc. 2011-2020. *
3 * *
4 * Use subject to the terms of the Apache License 2.0 available at *
5 * http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
6 * between Ultraleap and you, your company or other organization. *
7 ******************************************************************************/
8
9using UnityEngine;
10using UnityEngine.UI;
13using System.Collections.Generic;
14
15namespace Leap.Unity.InputModule {
17 public class LeapInputModule : BaseInputModule {
18 //General Interaction Parameters
19 [Header(" Interaction Setup")]
20 [Tooltip("The current Leap Data Provider for the scene.")]
23 [Tooltip("An optional alternate detector for pinching on the left hand.")]
28 [Tooltip("An optional alternate detector for pinching on the right hand.")]
33 [Tooltip("How many hands and pointers the Input Module should allocate for.")]
35 int NumberOfPointers = 2;
36
37 //Customizable Pointer Parameters
38 [Header(" Pointer Setup")]
39 [Tooltip("The sprite used to represent your pointers during projective interaction.")]
41 public Sprite PointerSprite;
42 [Tooltip("The material to be instantiated for your pointers during projective interaction.")]
44 public Material PointerMaterial;
45 [Tooltip("The color of the pointer when it is hovering over blank canvas.")]
47 public Color StandardColor = Color.white;
48 [Tooltip("The color of the pointer when it is hovering over any other UI element.")]
50 public Color HoveringColor = Color.green;
51 [Tooltip("The color of the pointer when it is triggering a UI element.")]
54 [Tooltip("The color of the pointer when it is triggering blank canvas.")]
57
58 //Advanced Options
59 [Header(" Advanced Options")]
60 [Tooltip("Whether or not to show Advanced Options in the Inspector.")]
61 public bool ShowAdvancedOptions = false;
62 [Tooltip("The distance from the base of a UI element that tactile interaction is triggered.")]
64 public float TactilePadding = 0.005f;
65 [Tooltip("The sound that is played when the pointer transitions from canvas to element.")]
67 public AudioClip BeginHoverSound;
68 [Tooltip("The sound that is played when the pointer transitions from canvas to element.")]
70 public AudioClip EndHoverSound;
71 [Tooltip("The sound that is played when the pointer triggers a UI element.")]
73 public AudioClip BeginTriggerSound;
74 [Tooltip("The sound that is played when the pointer triggers a UI element.")]
76 public AudioClip EndTriggerSound;
77 [Tooltip("The sound that is played when the pointer triggers blank canvas.")]
79 public AudioClip BeginMissedSound;
80 [Tooltip("The sound that is played when the pointer triggers blank canvas.")]
82 public AudioClip EndMissedSound;
83 [Tooltip("The sound that is played while the pointer is dragging an object.")]
85 public AudioClip DragLoopSound;
86
87 // Event delegates triggered by Input
88 [System.Serializable]
89 public class PositionEvent : UnityEvent<Vector3> { }
90
91 [Header(" Event Setup")]
92 [Tooltip("The event that is triggered upon clicking on a non-canvas UI element.")]
95 [Tooltip("The event that is triggered upon lifting up from a non-canvas UI element (Not 1:1 with onClickDown!)")]
98 [Tooltip("The event that is triggered upon hovering over a non-canvas UI element.")]
101 [Tooltip("The event that is triggered while holding down a non-canvas UI element.")]
104
105 [Tooltip("Whether or not to show unsupported Experimental Options in the Inspector.")]
106 public bool ShowExperimentalOptions = false;
115 public enum InteractionCapability : int {
116 Hybrid,
117 Tactile,
118 Projective
119 };
120 [Tooltip("The interaction mode that the Input Module will be restricted to.")]
123 [Tooltip("The distance from the base of a UI element that interaction switches from Projective-Pointer based to Touch based.")]
126 [Tooltip("The size of the pointer in world coordinates with respect to the distance between the cursor and the camera.")]
128 public AnimationCurve PointerDistanceScale = AnimationCurve.Linear(0f, 0.1f, 6f, 1f);
129 [Tooltip("The size of the pointer in world coordinates with respect to the distance between the thumb and forefinger.")]
131 public AnimationCurve PointerPinchScale = AnimationCurve.Linear(30f, 0.6f, 70f, 1.1f);
132 [Tooltip("When not using a PinchDetector, the distance in mm that the tip of the thumb and forefinger should be to activate selection during projective interaction.")]
134 public float PinchingThreshold = 30f;
135 [Tooltip("Create a pointer for each finger.")]
137 public bool perFingerPointer = false;
138 [Tooltip("Render the pointer onto the enviroment.")]
140 public bool EnvironmentPointer = false;
141 [Tooltip("The event that is triggered while pinching to a point in the environment.")]
144 [Tooltip("Render a smaller pointer inside of the main pointer.")]
146 public bool InnerPointer = true;
147 [Tooltip("The Opacity of the Inner Pointer relative to the Primary Pointer.")]
149 public float InnerPointerOpacityScalar = 0.77f;
150 [Tooltip("Trigger a Hover Event when switching between UI elements.")]
152 public bool TriggerHoverOnElementSwitch = false;
153 [Tooltip("If the ScrollView still doesn't work even after disabling RaycastTarget on the intermediate layers.")]
155 public bool OverrideScrollViewClicks = false;
156 [Tooltip("Draw the raycast for projective interaction.")]
158 public bool DrawDebug = false;
159 [Tooltip("Retract compressible widgets when not using Tactile Interaction.")]
161 public bool RetractUI = false;
162 [Tooltip("Retransform the Interaction Pointer to allow the Module to work in a non-stationary reference frame.")]
164 public bool MovingReferenceFrame = false;
165
166 //Event related data
167 //private Camera EventCamera;
168 private PointerEventData[] PointEvents;
169 private pointerStates[] pointerState;
170 private Transform[] Pointers;
171 private Transform[] InnerPointers;
172 private LineRenderer[] PointerLines;
173
174 //Object the pointer is hovering over
175 private GameObject[] currentOverGo;
176
177 //Values from the previous frame
178 private pointerStates[] PrevState;
179 private Vector2[] PrevScreenPosition;
180 private Vector2[] DragBeginPosition;
181 private bool[] PrevTriggeringInteraction;
182 private bool PrevTouchingMode;
183 private GameObject[] prevOverGo;
184 private float[] timeEnteredCanvas;
185
186 //Misc. Objects
187 private Canvas[] canvases;
188 private Quaternion CurrentRotation;
189 private AudioSource SoundPlayer;
190 private GameObject[] currentGo;
191 private GameObject[] currentGoing;
192 private Vector3 OldCameraPos = Vector3.zero;
193 private Quaternion OldCameraRot = Quaternion.identity;
194 //private float OldCameraFoV;
195 private bool forceProjective = false;
196 private bool forceTactile = false;
197
198 //Queue of Spheres to Debug Draw
199 private Queue<Vector3> DebugSphereQueue;
200
201 enum pointerStates : int {
202 OnCanvas,
203 OnElement,
204 PinchingToCanvas,
205 PinchingToElement,
206 NearCanvas,
207 TouchingCanvas,
208 TouchingElement,
209 OffCanvas
210 };
211
212 //Initialization
213 protected override void Start() {
214 base.Start();
215
216 if (LeapDataProvider == null) {
217 LeapDataProvider = FindObjectOfType<LeapProvider>();
218 if (LeapDataProvider == null || !LeapDataProvider.isActiveAndEnabled) {
219 Debug.LogError("Cannot use LeapImageRetriever if there is no LeapProvider!");
220 enabled = false;
221 return;
222 }
223 }
224
225 canvases = Resources.FindObjectsOfTypeAll<Canvas>();
226
227 //Set Projective/Tactile Modes
228 if (InteractionMode == InteractionCapability.Projective) {
230 forceTactile = false;
231 forceProjective = true;
232 } else if (InteractionMode == InteractionCapability.Tactile) {
234 forceTactile = true;
235 forceProjective = false;
236 }
237
238 //Initialize the Pointers for Projective Interaction
239 if (perFingerPointer == true) {
240 NumberOfPointers = 10;
241 }
242 Pointers = new Transform[NumberOfPointers];
243 InnerPointers = new Transform[NumberOfPointers];
244 PointerLines = new LineRenderer[NumberOfPointers];
245 for (int index = 0; index < Pointers.Length; index++) {
246 //Create the Canvas to render the Pointer on
247 GameObject pointer = new GameObject("Pointer " + index);
248 SpriteRenderer renderer = pointer.AddComponent<SpriteRenderer>();
249 renderer.sortingOrder = 1000;
250
251 //Add your sprite to the Sprite Renderer
252 renderer.sprite = PointerSprite;
253 renderer.material = Instantiate(PointerMaterial); //Make sure to instantiate the material so each pointer can be modified independently
254
255 if (DrawDebug) {
256 PointerLines[index] = pointer.AddComponent<LineRenderer>();
257 PointerLines[index].material = Instantiate(PointerMaterial);
258 PointerLines[index].material.color = new Color(0f, 0f, 0f, 0f);
259#if UNITY_5_5_OR_NEWER
260#if UNITY_5_6_OR_NEWER
261 PointerLines[index].positionCount = 2;
262#else
263 PointerLines[index].numPositions = 2;
264#endif
265 PointerLines[index].startWidth = 0.001f;
266 PointerLines[index].endWidth = 0.001f;
267#else
268 PointerLines[index].SetVertexCount(2);
269 PointerLines[index].SetWidth(0.001f, 0.001f);
270#endif
271 }
272
273 Pointers[index] = pointer.GetComponent<Transform>();
274 Pointers[index].parent = transform;
275 pointer.SetActive(false);
276
277 if (InnerPointer) {
278 //Create the Canvas to render the Pointer on
279 GameObject innerPointer = new GameObject("Pointer " + index);
280 renderer = innerPointer.AddComponent<SpriteRenderer>();
281 renderer.sortingOrder = 1000;
282
283 //Add your sprite to the Canvas
284 renderer.sprite = PointerSprite;
285
286 renderer.material = Instantiate(PointerMaterial);
287
288 InnerPointers[index] = innerPointer.GetComponent<Transform>();
289 InnerPointers[index].parent = transform;
290 innerPointer.SetActive(false);
291 }
292 }
293
294
295 //Initialize our Sound Player
296 SoundPlayer = this.gameObject.AddComponent<AudioSource>();
297
298 //Initialize the arrays that store persistent objects per pointer
299 PointEvents = new PointerEventData[NumberOfPointers];
300 pointerState = new pointerStates[NumberOfPointers];
301 currentOverGo = new GameObject[NumberOfPointers];
302 prevOverGo = new GameObject[NumberOfPointers];
303 currentGo = new GameObject[NumberOfPointers];
304 currentGoing = new GameObject[NumberOfPointers];
305 PrevTriggeringInteraction = new bool[NumberOfPointers];
306 PrevScreenPosition = new Vector2[NumberOfPointers];
307 DragBeginPosition = new Vector2[NumberOfPointers];
308 PrevState = new pointerStates[NumberOfPointers];
309 timeEnteredCanvas = new float[NumberOfPointers];
310
311 //Used for calculating the origin of the Projective Interactions
312 if (Camera.main != null) {
313 CurrentRotation = Camera.main.transform.rotation;
314 } else {
315 Debug.LogAssertion("Tag your Main Camera with 'MainCamera' for the UI Module");
316 }
317
318 //Initializes the Queue of Spheres to draw in OnDrawGizmos
319 if (DrawDebug) {
320 DebugSphereQueue = new Queue<Vector3>();
321 }
322 }
323
324 //Update the Head Yaw for Calculating "Shoulder Positions"
325 void Update() {
326 if (Camera.main != null) {
327 Quaternion HeadYaw = Quaternion.Euler(0f, OldCameraRot.eulerAngles.y, 0f);
328 CurrentRotation = Quaternion.Slerp(CurrentRotation, HeadYaw, 0.1f);
329 }
330 }
331
332 //Process is called by UI system to process events
333 public override void Process() {
335 (LeapDataProvider as LeapServiceProvider).RetransformFrames();
336 }
337
338 OldCameraPos = Camera.main.transform.position;
339 OldCameraRot = Camera.main.transform.rotation;
340 //OldCameraFoV = Camera.main.fieldOfView;
341
342 //Send update events if there is a selected object
343 //This is important for InputField to receive keyboard events
344 SendUpdateEventToSelectedObject();
345
346 //Begin Processing Each Hand
347 for (int whichPointer = 0; whichPointer < NumberOfPointers; whichPointer++) {
348 int whichHand;
349 int whichFinger;
350 if (perFingerPointer) {
351 whichHand = whichPointer <= 4 ? 0 : 1;
352 whichFinger = whichPointer <= 4 ? whichPointer : whichPointer - 5;
353 //Move on if this hand isn't visible in the frame
354 if (LeapDataProvider.CurrentFrame.Hands.Count - 1 < whichHand) {
355 if (Pointers[whichPointer].gameObject.activeInHierarchy == true) {
356 Pointers[whichPointer].gameObject.SetActive(false);
357 if (InnerPointer) {
358 InnerPointers[whichPointer].gameObject.SetActive(false);
359 }
360 }
361 continue;
362 }
363 } else {
364 whichHand = whichPointer;
365 whichFinger = 1;
366 //Move on if this hand isn't visible in the frame
367 if (LeapDataProvider.CurrentFrame.Hands.Count - 1 < whichHand) {
368 if (Pointers[whichPointer].gameObject.activeInHierarchy == true) {
369 Pointers[whichPointer].gameObject.SetActive(false);
370 if (InnerPointer) {
371 InnerPointers[whichPointer].gameObject.SetActive(false);
372 }
373 }
374 continue;
375 }
376 }
377
378 //Calculate Shoulder Positions (for Projection)
379 Vector3 ProjectionOrigin = Vector3.zero;
380 if (Camera.main != null) {
381 switch (LeapDataProvider.CurrentFrame.Hands[whichHand].IsRight) {
382 case true:
383 ProjectionOrigin = OldCameraPos + CurrentRotation * new Vector3(0.15f, -0.2f, 0f);
384 break;
385 case false:
386 ProjectionOrigin = OldCameraPos + CurrentRotation * new Vector3(-0.15f, -0.2f, 0f);
387 break;
388 }
389 }
390
391 //Draw Shoulders as Spheres, and the Raycast as a Line
392 if (DrawDebug) {
393 DebugSphereQueue.Enqueue(ProjectionOrigin);
394 Debug.DrawRay(ProjectionOrigin, CurrentRotation * Vector3.forward * 5f);
395 }
396
397 //Raycast from shoulder through tip of the index finger to the UI
398 bool TipRaycast = false;
399 if (InteractionMode != InteractionCapability.Projective) {
400 TipRaycast = GetLookPointerEventData(whichPointer, whichHand, whichFinger, ProjectionOrigin, CurrentRotation * Vector3.forward, true);
401 PrevState[whichPointer] = pointerState[whichPointer]; //Store old state for sound transitionary purposes
402 UpdatePointer(whichPointer, PointEvents[whichPointer], PointEvents[whichPointer].pointerCurrentRaycast.gameObject);
403 ProcessState(whichPointer, whichHand, whichFinger, TipRaycast);
404 }
405
406 //If didn't hit anything near the fingertip, try doing it again, but through the knuckle this time
407 if (((pointerState[whichPointer] == pointerStates.OffCanvas) && (InteractionMode != InteractionCapability.Tactile)) || (InteractionMode == InteractionCapability.Projective)) {
408 TipRaycast = GetLookPointerEventData(whichPointer, whichHand, whichFinger, ProjectionOrigin, CurrentRotation * Vector3.forward, false);
409 if ((InteractionMode == InteractionCapability.Projective)) {
410 PrevState[whichPointer] = pointerState[whichPointer]; //Store old state for sound transitionary purposes
411 }
412 UpdatePointer(whichPointer, PointEvents[whichPointer], PointEvents[whichPointer].pointerCurrentRaycast.gameObject);
413 if (!TipRaycast && (forceTactile || (!forceProjective && distanceOfTipToPointer(whichPointer, whichHand, whichFinger) < ProjectiveToTactileTransitionDistance))) {
414 PointEvents[whichPointer].pointerCurrentRaycast = new RaycastResult();
415 }
416 ProcessState(whichPointer, whichHand, whichFinger, TipRaycast);
417 }
418
419 //Handle the Environment Pointer
420 if ((EnvironmentPointer) && (pointerState[whichPointer] == pointerStates.OffCanvas)) {
421 Vector3 IndexMetacarpal = LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[whichFinger].Bone(Bone.BoneType.TYPE_METACARPAL).Center.ToVector3();
422 RaycastHit EnvironmentSpot;
423 Physics.Raycast(ProjectionOrigin, (IndexMetacarpal - ProjectionOrigin).normalized, out EnvironmentSpot);
424 Pointers[whichPointer].position = EnvironmentSpot.point + (EnvironmentSpot.normal * 0.01f);
425 Pointers[whichPointer].rotation = Quaternion.LookRotation(EnvironmentSpot.normal);
426 if (InnerPointer) {
427 InnerPointers[whichPointer].position = EnvironmentSpot.point + (EnvironmentSpot.normal * 0.01f);
428 InnerPointers[whichPointer].rotation = Quaternion.LookRotation(EnvironmentSpot.normal);
429 }
430 evaluatePointerSize(whichPointer);
431
432 if (isTriggeringInteraction(whichPointer, whichHand, whichFinger)) {
433 environmentPinch.Invoke(Pointers[whichPointer].position);
434 }
435 }
436
437 PrevScreenPosition[whichPointer] = PointEvents[whichPointer].position;
438
439 if (DrawDebug) {
440 PointerLines[whichPointer].SetPosition(0, Camera.main.transform.position);
441 PointerLines[whichPointer].SetPosition(1, Pointers[whichPointer].position);
442 }
443
444 //Trigger events that come from changing pointer state
445 ProcessStateEvents(whichPointer);
446 if ((PointEvents[whichPointer] != null)) {
447 //Tell Leap Buttons how far away the finger is
448 GameObject Hoverer = ExecuteEvents.GetEventHandler<IPointerClickHandler>(PointEvents[whichPointer].pointerCurrentRaycast.gameObject);
449 if ((Hoverer != null)) {
450 ILeapWidget comp = Hoverer.GetComponent<ILeapWidget>();
451 if (comp == null) { comp = Hoverer.GetComponentInParent<ILeapWidget>(); }
452 if (comp != null) {
453 //if (!isTriggeringInteraction(whichPointer, whichHand, whichFinger)) { //I forget why I put this here....
454 ((ILeapWidget)comp).HoverDistance(distanceOfTipToPointer(whichPointer, whichHand, whichFinger));
455 //}
456 }
457 }
458
459 //If we hit something with our Raycast, let's see if we should interact with it
460 if (PointEvents[whichPointer].pointerCurrentRaycast.gameObject != null && pointerState[whichPointer] != pointerStates.OffCanvas) {
461 prevOverGo[whichPointer] = currentOverGo[whichPointer];
462 currentOverGo[whichPointer] = PointEvents[whichPointer].pointerCurrentRaycast.gameObject;
463
464 //Trigger Enter or Exit Events on the UI Element (like highlighting)
465 base.HandlePointerExitAndEnter(PointEvents[whichPointer], currentOverGo[whichPointer]);
466
467 //If we weren't triggering an interaction last frame, but we are now...
468 if (!PrevTriggeringInteraction[whichPointer] && isTriggeringInteraction(whichPointer, whichHand, whichFinger)) {
469 PrevTriggeringInteraction[whichPointer] = true;
470
471 if ((Time.time - timeEnteredCanvas[whichPointer] >= Time.deltaTime)) {
472 //Deselect all objects
473 if (base.eventSystem.currentSelectedGameObject) {
474 base.eventSystem.SetSelectedGameObject(null);
475 }
476
477 //Record pointer telemetry
478 PointEvents[whichPointer].pressPosition = PointEvents[whichPointer].position;
479 PointEvents[whichPointer].pointerPressRaycast = PointEvents[whichPointer].pointerCurrentRaycast;
480 PointEvents[whichPointer].pointerPress = null; //Clear this for setting later
481 PointEvents[whichPointer].useDragThreshold = true;
482
483 //If we hit something good, let's trigger it!
484 if (currentOverGo[whichPointer] != null) {
485 currentGo[whichPointer] = currentOverGo[whichPointer];
486
487 //See if this object, or one of its parents, has a pointerDownHandler
488 GameObject newPressed = ExecuteEvents.ExecuteHierarchy(currentGo[whichPointer], PointEvents[whichPointer], ExecuteEvents.pointerDownHandler);
489
490 //If not, see if one has a pointerClickHandler!
491 if (newPressed == null) {
492 newPressed = ExecuteEvents.ExecuteHierarchy(currentGo[whichPointer], PointEvents[whichPointer], ExecuteEvents.pointerClickHandler);
493 if (newPressed != null) {
494 currentGo[whichPointer] = newPressed;
495 }
496 } else {
497 currentGo[whichPointer] = newPressed;
498 //We want to do "click on button down" at same time, unlike regular mouse processing
499 //Which does click when mouse goes up over same object it went down on
500 //This improves the user's ability to select small menu items
501 //ExecuteEvents.Execute(newPressed, PointEvents[whichPointer], ExecuteEvents.pointerClickHandler);
502 }
503
504 if (newPressed != null) {
505 PointEvents[whichPointer].pointerPress = newPressed;
506 currentGo[whichPointer] = newPressed;
507
508 //Select the currently pressed object
509 if (ExecuteEvents.GetEventHandler<IPointerClickHandler>(currentGo[whichPointer])) {
510 base.eventSystem.SetSelectedGameObject(currentGo[whichPointer]);
511 }
512 }
513
514 //Debug.Log(currentGo[whichPointer].name);
515 PointEvents[whichPointer].pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(currentGo[whichPointer]);
516 //Debug.Log(PointEvents[whichPointer].pointerDrag.name);
517
518 if (PointEvents[whichPointer].pointerDrag) {
519 IDragHandler Dragger = PointEvents[whichPointer].pointerDrag.GetComponent<IDragHandler>();
520 if (Dragger != null) {
521 if (Dragger is EventTrigger && PointEvents[whichPointer].pointerDrag.transform.parent) { //Hack: EventSystems intercepting Drag Events causing funkiness
522 PointEvents[whichPointer].pointerDrag = ExecuteEvents.GetEventHandler<IDragHandler>(PointEvents[whichPointer].pointerDrag.transform.parent.gameObject);
523 if (PointEvents[whichPointer].pointerDrag != null) {
524 Dragger = PointEvents[whichPointer].pointerDrag.GetComponent<IDragHandler>();
525 if ((Dragger != null) && !(Dragger is EventTrigger)) {
526 currentGoing[whichPointer] = PointEvents[whichPointer].pointerDrag;
527 DragBeginPosition[whichPointer] = PointEvents[whichPointer].position;
528 if (currentGo[whichPointer] && currentGo[whichPointer] == currentGoing[whichPointer]) {
529 ExecuteEvents.Execute(PointEvents[whichPointer].pointerDrag, PointEvents[whichPointer], ExecuteEvents.beginDragHandler);
530 PointEvents[whichPointer].dragging = true;
531 }
532 }
533 }
534 } else {
535 currentGoing[whichPointer] = PointEvents[whichPointer].pointerDrag;
536 DragBeginPosition[whichPointer] = PointEvents[whichPointer].position;
537 if (currentGo[whichPointer] && currentGo[whichPointer] == currentGoing[whichPointer]) {
538 ExecuteEvents.Execute(PointEvents[whichPointer].pointerDrag, PointEvents[whichPointer], ExecuteEvents.beginDragHandler);
539 PointEvents[whichPointer].dragging = true;
540 }
541 }
542 }
543 }
544 }
545 }
546 }
547 }
548
549
550 //If we have dragged beyond the drag threshold
551 if (!PointEvents[whichPointer].dragging && currentGoing[whichPointer] && Vector2.Distance(PointEvents[whichPointer].position, DragBeginPosition[whichPointer]) * 100f > EventSystem.current.pixelDragThreshold) {
552 IDragHandler Dragger = PointEvents[whichPointer].pointerDrag.GetComponent<IDragHandler>();
553 if (Dragger != null && Dragger is ScrollRect) {
554 if (currentGo[whichPointer] && !(currentGo[whichPointer].GetComponent<ScrollRect>())) {
555 ExecuteEvents.Execute(PointEvents[whichPointer].pointerDrag, PointEvents[whichPointer], ExecuteEvents.beginDragHandler);
556 PointEvents[whichPointer].dragging = true;
557
558 ExecuteEvents.Execute(currentGo[whichPointer], PointEvents[whichPointer], ExecuteEvents.pointerUpHandler);
559 PointEvents[whichPointer].rawPointerPress = null;
560 PointEvents[whichPointer].pointerPress = null;
561 currentGo[whichPointer] = null;
562 }
563 }
564 }
565
566
567 //If we WERE interacting last frame, but are not this frame...
568 if (PrevTriggeringInteraction[whichPointer] && ((!isTriggeringInteraction(whichPointer, whichHand, whichFinger)) || (pointerState[whichPointer] == pointerStates.OffCanvas))) {
569 PrevTriggeringInteraction[whichPointer] = false;
570
571 if (currentGoing[whichPointer]) {
572 ExecuteEvents.Execute(currentGoing[whichPointer], PointEvents[whichPointer], ExecuteEvents.endDragHandler);
573 if ((currentGo[whichPointer]) && (currentGoing[whichPointer] == currentGo[whichPointer])) {
574 ExecuteEvents.Execute(currentGoing[whichPointer], PointEvents[whichPointer], ExecuteEvents.pointerUpHandler);
575 }
576 //Debug.Log(currentGoing[whichPointer].name);
577 if (currentOverGo[whichPointer] != null) {
578 ExecuteEvents.ExecuteHierarchy(currentOverGo[whichPointer], PointEvents[whichPointer], ExecuteEvents.dropHandler);
579 }
580 PointEvents[whichPointer].pointerDrag = null;
581 PointEvents[whichPointer].dragging = false;
582 currentGoing[whichPointer] = null;
583 }
584
585 if (currentGo[whichPointer]) {
586 ExecuteEvents.Execute(currentGo[whichPointer], PointEvents[whichPointer], ExecuteEvents.pointerUpHandler);
587 ExecuteEvents.Execute(currentGo[whichPointer], PointEvents[whichPointer], ExecuteEvents.pointerClickHandler);
588 PointEvents[whichPointer].rawPointerPress = null;
589 PointEvents[whichPointer].pointerPress = null;
590 currentGo[whichPointer] = null;
591 currentGoing[whichPointer] = null;
592 }
593 }
594
595 //And for everything else, there is dragging.
596 if (PointEvents[whichPointer].pointerDrag != null && PointEvents[whichPointer].dragging) {
597 ExecuteEvents.Execute(PointEvents[whichPointer].pointerDrag, PointEvents[whichPointer], ExecuteEvents.dragHandler);
598 }
599 }
600
601 updatePointerColor(whichPointer, whichHand, whichFinger);
602
603
604 //Make the special Leap Widget Buttons Pop Up and Flatten when Appropriate
605 if (PrevTouchingMode != getTouchingMode() && RetractUI) {
606 PrevTouchingMode = getTouchingMode();
607 if (PrevTouchingMode) {
608 for (int i = 0; i < canvases.Length; i++) {
609 canvases[i].BroadcastMessage("Expand", SendMessageOptions.DontRequireReceiver);
610 }
611 } else {
612 for (int i = 0; i < canvases.Length; i++) {
613 canvases[i].BroadcastMessage("Retract", SendMessageOptions.DontRequireReceiver);
614 }
615 }
616 }
617
618 }
619
620 Camera.main.transform.position = OldCameraPos;
621 Camera.main.transform.rotation = OldCameraRot;
622 //Camera.main.fieldOfView = OldCameraFoV;
623 }
624
625 //Raycast from the EventCamera into UI Space
626 private bool GetLookPointerEventData(int whichPointer, int whichHand, int whichFinger, Vector3 Origin, Vector3 Direction, bool forceTipRaycast) {
627
628 //Whether or not this will be a raycast through the finger tip
629 bool TipRaycast = false;
630
631 //Initialize a blank PointerEvent
632 if (PointEvents[whichPointer] == null) {
633 PointEvents[whichPointer] = new PointerEventData(base.eventSystem);
634 } else {
635 PointEvents[whichPointer].Reset();
636 }
637
638 //We're always going to assume we're "Left Clicking", for the benefit of uGUI
639 PointEvents[whichPointer].button = PointerEventData.InputButton.Left;
640
641 //If we're in "Touching Mode", Raycast through the fingers
642 Vector3 IndexFingerPosition;
643 if (getTouchingMode(whichPointer) || forceTipRaycast) {
644 TipRaycast = true;
645
646 //Focus pointer through the average of the extended fingers
647 if (!perFingerPointer) {
648 /*
649 float numberOfExtendedFingers = 0.1f;
650 IndexFingerPosition = LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[whichFinger].TipPosition.ToVector3() * 0.1f;
651 //Averages cursor position through average of extended fingers; ended up being worse than expected
652 for (int i = 1; i < 4; i++) {
653 float fingerExtension = Mathf.Clamp01(Vector3.Dot(LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[i].Direction.ToVector3(), LeapDataProvider.CurrentFrame.Hands[whichPointer].Direction.ToVector3())) / 1.5f;
654 if (fingerExtension > 0f) {
655 numberOfExtendedFingers += fingerExtension;
656 IndexFingerPosition += LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[i].TipPosition.ToVector3() * fingerExtension;
657 }
658 }
659 IndexFingerPosition /= numberOfExtendedFingers;
660 */
661
662 float farthest = 0f;
663 IndexFingerPosition = LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[1].TipPosition.ToVector3();
664 for (int i = 1; i < 3; i++) {
665 float fingerDistance = Vector3.Distance(Camera.main.transform.position, LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[i].TipPosition.ToVector3());
666 float fingerExtension = Mathf.Clamp01(Vector3.Dot(LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[i].Direction.ToVector3(), LeapDataProvider.CurrentFrame.Hands[whichPointer].Direction.ToVector3())) / 1.5f;
667 if (fingerDistance > farthest && fingerExtension > 0.5f) {
668 farthest = fingerDistance;
669 IndexFingerPosition = LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[i].TipPosition.ToVector3();
670 }
671 }
672 } else {
673 IndexFingerPosition = LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[whichFinger].TipPosition.ToVector3();
674 }
675
676 //Else Raycast through the knuckle of the Index Finger
677 } else {
678 Camera.main.transform.position = Origin;
679 IndexFingerPosition = LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[whichFinger].Bone(Bone.BoneType.TYPE_METACARPAL).Center.ToVector3();
680 }
681
682 //Draw Camera Origin
683 if (DrawDebug)
684 DebugSphereQueue.Enqueue(Camera.main.transform.position);
685
686 //Set EventCamera's FoV
687 //Camera.main.fieldOfView = 179f;
688
689 //Set the Raycast Direction and Delta
690 PointEvents[whichPointer].position = Vector2.Lerp(PrevScreenPosition[whichPointer], Camera.main.WorldToScreenPoint(IndexFingerPosition), 1.0f);//new Vector2(Screen.width / 2, Screen.height / 2);
691 PointEvents[whichPointer].delta = (PointEvents[whichPointer].position - PrevScreenPosition[whichPointer]) * -10f;
692 PointEvents[whichPointer].scrollDelta = Vector2.zero;
693
694 //Perform the Raycast and sort all the things we hit by distance...
695 base.eventSystem.RaycastAll(PointEvents[whichPointer], m_RaycastResultCache);
696
697 //Optional hack that subverts ScrollRect hierarchies; to avoid this, disable "RaycastTarget" on the Viewport and Content panes
699 PointEvents[whichPointer].pointerCurrentRaycast = new RaycastResult();
700 for (int i = 0; i < m_RaycastResultCache.Count; i++) {
701 if (m_RaycastResultCache[i].gameObject.GetComponent<Scrollbar>() != null) {
702 PointEvents[whichPointer].pointerCurrentRaycast = m_RaycastResultCache[i];
703 } else if (PointEvents[whichPointer].pointerCurrentRaycast.gameObject == null && m_RaycastResultCache[i].gameObject.GetComponent<ScrollRect>() != null) {
704 PointEvents[whichPointer].pointerCurrentRaycast = m_RaycastResultCache[i];
705 }
706 }
707 if (PointEvents[whichPointer].pointerCurrentRaycast.gameObject == null) {
708 PointEvents[whichPointer].pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
709 }
710 } else {
711 PointEvents[whichPointer].pointerCurrentRaycast = FindFirstRaycast(m_RaycastResultCache);
712 }
713
714 //Clear the list of things we hit; we don't need it anymore.
715 m_RaycastResultCache.Clear();
716
717 return TipRaycast;
718 }
719
720 //Tree to decide the State of the Pointer
721 private void ProcessState(int whichPointer, int whichHand, int whichFinger, bool forceTipRaycast) {
722 if ((PointEvents[whichPointer].pointerCurrentRaycast.gameObject != null)) {
723 if (forceTactile || (!forceProjective && distanceOfTipToPointer(whichPointer, whichHand, whichFinger) < ProjectiveToTactileTransitionDistance)) {
724 if (isTriggeringInteraction(whichPointer, whichHand, whichFinger)) {
725 if (ExecuteEvents.GetEventHandler<IPointerClickHandler>(PointEvents[whichPointer].pointerCurrentRaycast.gameObject)) {
726 pointerState[whichPointer] = pointerStates.TouchingElement;
727 } else {
728 pointerState[whichPointer] = pointerStates.TouchingCanvas;
729 }
730 } else {
731 pointerState[whichPointer] = pointerStates.NearCanvas;
732 }
733 } else if (!forceTipRaycast) {
734 if (ExecuteEvents.GetEventHandler<IPointerClickHandler>(PointEvents[whichPointer].pointerCurrentRaycast.gameObject)) {// || PointEvents[whichPointer].dragging) {
735 if (isTriggeringInteraction(whichPointer, whichHand, whichFinger)) {
736 pointerState[whichPointer] = pointerStates.PinchingToElement;
737 } else {
738 pointerState[whichPointer] = pointerStates.OnElement;
739 }
740 } else {
741 if (isTriggeringInteraction(whichPointer, whichHand, whichFinger)) {
742 pointerState[whichPointer] = pointerStates.PinchingToCanvas;
743 } else {
744 pointerState[whichPointer] = pointerStates.OnCanvas;
745 }
746 }
747 } else {
748 pointerState[whichPointer] = pointerStates.OffCanvas;
749 }
750 } else {
751 pointerState[whichPointer] = pointerStates.OffCanvas;
752 }
753 }
754
755 //Discrete 1-Frame Transition Behaviors like Sounds and Events
756 //(color changing is in a different function since it is lerped over multiple frames)
757 private void ProcessStateEvents(int whichPointer) {
759 if ((PrevState[whichPointer] != pointerStates.OffCanvas) && (pointerState[whichPointer] != pointerStates.OffCanvas)) {
760 if (currentOverGo[whichPointer] != prevOverGo[whichPointer]) {
761 //When you begin to hover on an element
762 SoundPlayer.PlayOneShot(BeginHoverSound);
763 onHover.Invoke(Pointers[whichPointer].transform.position);
764 }
765 }
766 }
767
768 //Warning: Horrible State Machine ahead...
769 if (PrevState[whichPointer] == pointerStates.OnCanvas) {
770 if (pointerState[whichPointer] == pointerStates.OnElement) {
771 //When you go from hovering on the Canvas to hovering on an element
773 SoundPlayer.PlayOneShot(BeginHoverSound);
774 onHover.Invoke(Pointers[whichPointer].transform.position);
775 }
776 } else if (pointerState[whichPointer] == pointerStates.PinchingToCanvas) {
777 //When you try to interact with the Canvas
778 SoundPlayer.PlayOneShot(BeginMissedSound);
779 }
780 } else if (PrevState[whichPointer] == pointerStates.PinchingToCanvas) {
781 if (pointerState[whichPointer] == pointerStates.OnCanvas) {
782 //When you unpinch off of Blank Canvas
783 SoundPlayer.PlayOneShot(EndMissedSound);
784 }
785 } else if (PrevState[whichPointer] == pointerStates.OnElement) {
786 if (pointerState[whichPointer] == pointerStates.OnCanvas) {
787 //When you begin to hover over the Canvas after hovering over an element
788 SoundPlayer.PlayOneShot(EndHoverSound);
789 } else if (pointerState[whichPointer] == pointerStates.PinchingToElement) {
790 //When you click on an element
791 SoundPlayer.PlayOneShot(BeginTriggerSound);
792 onClickDown.Invoke(Pointers[whichPointer].transform.position);
793 }
794 } else if (PrevState[whichPointer] == pointerStates.PinchingToElement) {
795 if (pointerState[whichPointer] == pointerStates.PinchingToCanvas) {
796 //When you slide off of an element while holding it
797 //SoundPlayer.PlayOneShot(HoverSound);
798 } else if (pointerState[whichPointer] == pointerStates.OnElement || pointerState[whichPointer] == pointerStates.OnCanvas) {
799 //When you let go of an element
800 SoundPlayer.PlayOneShot(EndTriggerSound);
801 onClickUp.Invoke(Pointers[whichPointer].transform.position);
802 }
803 } else if (PrevState[whichPointer] == pointerStates.NearCanvas) {
804 if (pointerState[whichPointer] == pointerStates.TouchingElement) {
805 //When you physically touch an element
806 SoundPlayer.PlayOneShot(BeginTriggerSound);
807 onClickDown.Invoke(Pointers[whichPointer].transform.position);
808 }
809 if (pointerState[whichPointer] == pointerStates.TouchingCanvas) {
810 //When you physically touch Blank Canvas
811 SoundPlayer.PlayOneShot(BeginMissedSound);
812 }
813 } else if (PrevState[whichPointer] == pointerStates.TouchingCanvas) {
814 if (pointerState[whichPointer] == pointerStates.NearCanvas) {
815 //When you physically lift off of Blank Canvas
816 SoundPlayer.PlayOneShot(EndMissedSound);
817 }
818 } else if (PrevState[whichPointer] == pointerStates.TouchingElement) {
819 if (pointerState[whichPointer] == pointerStates.NearCanvas) {
820 //When you physically pull out of an element
821 SoundPlayer.PlayOneShot(EndTriggerSound);
822 onClickUp.Invoke(Pointers[whichPointer].transform.position);
823 }
824 } else if (PrevState[whichPointer] == pointerStates.OffCanvas) {
825 if (pointerState[whichPointer] != pointerStates.OffCanvas) {
826 //Record the time the hand entered an interactable state
827 timeEnteredCanvas[whichPointer] = Time.time;
828 }
829 }
830 }
831
832 //Update the pointer location and whether or not it is enabled
833 private void UpdatePointer(int whichPointer, PointerEventData pointData, GameObject UIComponent) {
834 if (EnvironmentPointer && pointerState[whichPointer] == pointerStates.OffCanvas) {
835 Pointers[whichPointer].gameObject.SetActive(true);
836 if (InnerPointer) { InnerPointers[whichPointer].gameObject.SetActive(true); }
837 }
838 if (currentOverGo[whichPointer] != null) {
839 Pointers[whichPointer].gameObject.SetActive(true);
840 if (InnerPointer) { InnerPointers[whichPointer].gameObject.SetActive(true); }
841 if (PointEvents[whichPointer].pointerCurrentRaycast.gameObject != null) {
842 RectTransform draggingPlane = PointEvents[whichPointer].pointerCurrentRaycast.gameObject.GetComponent<RectTransform>();
843 Vector3 globalLookPos;
844 if (RectTransformUtility.ScreenPointToWorldPointInRectangle(draggingPlane, pointData.position, pointData.enterEventCamera, out globalLookPos)) {
845
846 GameObject Hoverer = ExecuteEvents.GetEventHandler<IPointerEnterHandler>(UIComponent);
847 if (Hoverer) {
848 Vector3 ComponentInPlane = Hoverer.transform.InverseTransformPoint(globalLookPos);
849 ComponentInPlane = new Vector3(ComponentInPlane.x, ComponentInPlane.y, 0f);
850 Pointers[whichPointer].position = Hoverer.transform.TransformPoint(ComponentInPlane);// -transform.forward * 0.01f; //Amount the pointer floats above the Canvas
851 } else {
852 Pointers[whichPointer].position = globalLookPos;
853 }
854
855 float pointerAngle = Mathf.Rad2Deg * (Mathf.Atan2(pointData.delta.x, pointData.delta.y));
856 Pointers[whichPointer].rotation = draggingPlane.rotation * Quaternion.Euler(0f, 0f, -pointerAngle);
857 if (InnerPointer) {
858 InnerPointers[whichPointer].position = globalLookPos;// -transform.forward * 0.01f; //Amount the pointer floats above the Canvas
859 InnerPointers[whichPointer].rotation = draggingPlane.rotation * Quaternion.Euler(0f, 0f, -pointerAngle);
860 }
861 evaluatePointerSize(whichPointer);
862 }
863 }
864 }
865 }
866
867
868 void evaluatePointerSize(int whichPointer) {
869 //Use the Scale AnimCurve to Evaluate the Size of the Pointer
870 float PointDistance = 1f;
871 if (Camera.main != null) {
872 PointDistance = (Pointers[whichPointer].position - Camera.main.transform.position).magnitude;
873 }
874
875 float Pointerscale = PointerDistanceScale.Evaluate(PointDistance);
876
877 if (InnerPointer) { InnerPointers[whichPointer].localScale = Pointerscale * PointerPinchScale.Evaluate(0f) * Vector3.one; }
878
879 if (!perFingerPointer && !getTouchingMode(whichPointer)) {
880 if (whichPointer == 0) {
881 Pointerscale *= PointerPinchScale.Evaluate(LeapDataProvider.CurrentFrame.Hands[0].PinchDistance);
882 } else if (whichPointer == 1) {
883 Pointerscale *= PointerPinchScale.Evaluate(LeapDataProvider.CurrentFrame.Hands[1].PinchDistance);
884 }
885 }
886
887 //Commented out Velocity Stretching because it looks funny when switching between Tactile and Projective
888 Pointers[whichPointer].localScale = Pointerscale * new Vector3(1f, 1f /*+ pointData.delta.magnitude*1f*/, 1f);
889 }
890
892 public bool isTriggeringInteraction(int whichPointer, int whichHand, int whichFinger) {
893
894 if (InteractionMode != InteractionCapability.Projective) {
895 if (getTouchingMode(whichPointer)) {
896 return (distanceOfTipToPointer(whichPointer, whichHand, whichFinger) < 0f);
897 }
898 }
899
900 if (InteractionMode != InteractionCapability.Tactile) {
901 if ((LeapDataProvider.CurrentFrame.Hands[whichHand].IsRight) && (RightHandDetector != null && RightHandDetector.IsPinching) || (RightHandDetector == null && LeapDataProvider.CurrentFrame.Hands[whichHand].PinchDistance < PinchingThreshold)) {
902 return true;
903 } else if ((LeapDataProvider.CurrentFrame.Hands[whichHand].IsLeft) && (LeftHandDetector != null && LeftHandDetector.IsPinching) || (LeftHandDetector == null && LeapDataProvider.CurrentFrame.Hands[whichHand].PinchDistance < PinchingThreshold)) {
904 return true;
905 }
906 }
907
908 //Disabling Pinching during touch interactions; maybe still desirable?
909 //return LeapDataProvider.CurrentFrame.Hands[whichPointer].PinchDistance < PinchingThreshold;
910
911 return false;
912 }
913
915 public float distanceOfTipToPointer(int whichPointer, int whichHand, int whichFinger) {
916 //Get Base of Index Finger Position
917 Vector3 TipPosition = LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[whichFinger].Bone(Bone.BoneType.TYPE_DISTAL).NextJoint.ToVector3();
918 return (-Pointers[whichPointer].InverseTransformPoint(TipPosition).z * Pointers[whichPointer].lossyScale.z) - TactilePadding;
919 }
920
922 public float distanceOfTipToElement(Transform UIElement, int whichHand, int whichFinger) {
923 //Get Base of Index Finger Position
924 Vector3 TipPosition = LeapDataProvider.CurrentFrame.Hands[whichHand].Fingers[whichFinger].Bone(Bone.BoneType.TYPE_DISTAL).NextJoint.ToVector3();
925 return (-UIElement.InverseTransformPoint(TipPosition).z * UIElement.lossyScale.z) - TactilePadding;
926 }
927
929 public bool getTouchingMode() {
930 bool mode = false;
931 for (int i = 0; i < pointerState.Length; i++) {
932 if (pointerState[i] == pointerStates.NearCanvas || pointerState[i] == pointerStates.TouchingCanvas || pointerState[i] == pointerStates.TouchingElement) {
933 mode = true;
934 }
935 }
936 return mode;
937 }
938
940 public bool getTouchingMode(int whichPointer) {
941 return (pointerState[whichPointer] == pointerStates.NearCanvas || pointerState[whichPointer] == pointerStates.TouchingCanvas || pointerState[whichPointer] == pointerStates.TouchingElement);
942 }
943
944 //Where the color that the Pointer will lerp to is chosen
945 void updatePointerColor(int whichPointer, int whichHand, int whichFinger) {
946 float TransitionAmount = Mathf.Clamp01(Mathf.Abs((distanceOfTipToPointer(whichPointer, whichHand, whichFinger) - ProjectiveToTactileTransitionDistance)) / 0.05f);
947
948 switch (pointerState[whichPointer]) {
949 case pointerStates.OnCanvas:
950 lerpPointerColor(whichPointer, new Color(0f, 0f, 0f, 1f * TransitionAmount), 0.2f);
951 lerpPointerColor(whichPointer, StandardColor, 0.2f);
952 break;
953 case pointerStates.OnElement:
954 lerpPointerColor(whichPointer, new Color(0f, 0f, 0f, 1f * TransitionAmount), 0.2f);
955 lerpPointerColor(whichPointer, HoveringColor, 0.2f);
956 break;
957 case pointerStates.PinchingToCanvas:
958 lerpPointerColor(whichPointer, new Color(0f, 0f, 0f, 1f * TransitionAmount), 0.2f);
959 lerpPointerColor(whichPointer, TriggerMissedColor, 0.2f);
960 break;
961 case pointerStates.PinchingToElement:
962 lerpPointerColor(whichPointer, new Color(0f, 0f, 0f, 1f * TransitionAmount), 0.2f);
963 lerpPointerColor(whichPointer, TriggeringColor, 0.2f);
964 break;
965 case pointerStates.NearCanvas:
966 lerpPointerColor(whichPointer, new Color(0.0f, 0.0f, 0.0f, 0.5f * TransitionAmount), 0.3f);
967 lerpPointerColor(whichPointer, StandardColor, 0.2f);
968 break;
969 case pointerStates.TouchingElement:
970 lerpPointerColor(whichPointer, new Color(0.0f, 0.0f, 0.0f, 0.7f * TransitionAmount), 0.2f);
971 lerpPointerColor(whichPointer, TriggeringColor, 0.2f);
972 break;
973 case pointerStates.TouchingCanvas:
974 lerpPointerColor(whichPointer, new Color(0.0f, 0.01f, 0.0f, 0.5f * TransitionAmount), 0.2f);
975 lerpPointerColor(whichPointer, TriggerMissedColor, 0.2f);
976 break;
977 case pointerStates.OffCanvas:
978 lerpPointerColor(whichPointer, TriggerMissedColor, 0.2f);
979 if (EnvironmentPointer) {
980 lerpPointerColor(whichPointer, new Color(0.0f, 0.0f, 0.0f, 0.5f * TransitionAmount), 1f);
981 } else {
982 lerpPointerColor(whichPointer, new Color(0.0f, 0.0f, 0.0f, 0.001f), 1f);
983 }
984 break;
985 }
986 }
987
988 //Where the lerping of the pointer's color takes place
989 //If RGB are 0f or Alpha is 1f, then it will ignore those components and only lerp the remaining components
995 public void lerpPointerColor(int whichPointer, Color color, float lerpalpha) {
996 SpriteRenderer PointerSprite = Pointers[whichPointer].GetComponent<SpriteRenderer>();
997 Color oldColor = PointerSprite.color;
998 if (color.r == 0f && color.g == 0f && color.b == 0f) {
999 PointerSprite.material.color = Color.Lerp(oldColor, new Color(oldColor.r, oldColor.g, oldColor.b, color.a), lerpalpha);
1000 PointerSprite.color = Color.Lerp(oldColor, new Color(oldColor.r, oldColor.g, oldColor.b, color.a), lerpalpha);
1001 } else if (color.a == 1f) {
1002 PointerSprite.material.color = Color.Lerp(oldColor, new Color(color.r, color.g, color.b, oldColor.a), lerpalpha);
1003 PointerSprite.color = Color.Lerp(oldColor, new Color(color.r, color.g, color.b, oldColor.a), lerpalpha);
1004 } else {
1005 PointerSprite.material.color = Color.Lerp(oldColor, color, lerpalpha);
1006 PointerSprite.color = Color.Lerp(oldColor, color, lerpalpha);
1007 }
1008
1009 if (InnerPointer) {
1010 SpriteRenderer InnerPointerSprite = InnerPointers[whichPointer].GetComponent<SpriteRenderer>();
1011 oldColor = InnerPointerSprite.color;
1012 if (color.r == 0f && color.g == 0f && color.b == 0f) {
1013 InnerPointerSprite.material.color = Color.Lerp(oldColor, new Color(oldColor.r, oldColor.g, oldColor.b, color.a * InnerPointerOpacityScalar), lerpalpha);
1014 InnerPointerSprite.color = Color.Lerp(oldColor, new Color(oldColor.r, oldColor.g, oldColor.b, color.a * InnerPointerOpacityScalar), lerpalpha);
1015 } else if (color.a == 1f) {
1016 InnerPointerSprite.material.color = Color.Lerp(oldColor, new Color(color.r, color.g, color.b, oldColor.a * InnerPointerOpacityScalar), lerpalpha);
1017 InnerPointerSprite.color = Color.Lerp(oldColor, new Color(color.r, color.g, color.b, oldColor.a * InnerPointerOpacityScalar), lerpalpha);
1018 } else {
1019 InnerPointerSprite.material.color = Color.Lerp(oldColor, new Color(color.r, color.g, color.b, color.a * InnerPointerOpacityScalar), lerpalpha);
1020 InnerPointerSprite.color = Color.Lerp(oldColor, new Color(color.r, color.g, color.b, color.a * InnerPointerOpacityScalar), lerpalpha);
1021 }
1022 }
1023 }
1024
1025 private bool SendUpdateEventToSelectedObject() {
1026 if (base.eventSystem.currentSelectedGameObject == null)
1027 return false;
1028
1029 BaseEventData data = GetBaseEventData();
1030 ExecuteEvents.Execute(base.eventSystem.currentSelectedGameObject, data, ExecuteEvents.updateSelectedHandler);
1031 return data.used;
1032 }
1033
1034 void OnDrawGizmos() {
1035 if (DrawDebug) {
1036 while (DebugSphereQueue != null && DebugSphereQueue.Count > 0) {
1037 Gizmos.DrawSphere(DebugSphereQueue.Dequeue(), 0.1f);
1038 }
1039 }
1040 }
1041
1043 public override bool ShouldActivateModule() {
1044 return LeapDataProvider.CurrentFrame != null && LeapDataProvider.CurrentFrame.Hands.Count > 0 && base.ShouldActivateModule();
1045 }
1046 }
1047}
UnityEngine.Debug Debug
Definition: TanodaServer.cs:19
UnityEngine.Color Color
Definition: TestScript.cs:32
The Bone class represents a tracked bone.
Definition: Bone.cs:26
BoneType
Enumerates the type of bones.
Definition: Bone.cs:168
List< Hand > Hands
The list of Hand objects detected in this frame, given in arbitrary order. The list can be empty if n...
Definition: Frame.cs:156
bool isTriggeringInteraction(int whichPointer, int whichHand, int whichFinger)
float distanceOfTipToPointer(int whichPointer, int whichHand, int whichFinger)
Leap.Unity.PinchDetector RightHandDetector
Leap.Unity.PinchDetector LeftHandDetector
float distanceOfTipToElement(Transform UIElement, int whichHand, int whichFinger)
void lerpPointerColor(int whichPointer, Color color, float lerpalpha)
Provides Frame object data to the Unity application by firing events as soon as Frame data is availab...
Definition: LeapProvider.cs:21
abstract Frame CurrentFrame
The current frame for this update cycle, in world space.
Definition: LeapProvider.cs:37
The LeapServiceProvider provides tracked Leap Hand data and images from the device via the Leap servi...
A basic utility class to aid in creating pinch based actions. Once linked with a HandModelBase,...
void HoverDistance(float distance)