1
- using System ;
2
1
using System . Collections . Generic ;
3
2
using System . Linq ;
4
3
using UnityEngine ;
5
- using UnityEngine . Pool ;
6
- using UnityEngine . XR . Hands ;
7
4
using UnityEngine . XR . Interaction . Toolkit ;
5
+ using UnityEngine . XR . Interaction . Toolkit . Utilities ;
8
6
9
7
namespace ubco . ovilab . HPUI . Interaction
10
8
{
@@ -13,10 +11,8 @@ namespace ubco.ovilab.HPUI.Interaction
13
11
/// </summary>
14
12
[ SelectionBase ]
15
13
[ DisallowMultipleComponent ]
16
- public class HPUIInteractor : XRPokeInteractor , IHPUIInteractor
14
+ public class HPUIInteractor : XRBaseInteractor , IHPUIInteractor
17
15
{
18
- public new Handedness handedness ;
19
-
20
16
// TODO move these to an asset?
21
17
[ SerializeField ]
22
18
private float tapTimeThreshold ;
@@ -27,29 +23,42 @@ public class HPUIInteractor: XRPokeInteractor, IHPUIInteractor
27
23
public float TapDistanceThreshold { get => tapDistanceThreshold ; set => tapDistanceThreshold = value ; }
28
24
29
25
[ SerializeField ]
26
+ [ Tooltip ( "Event triggered on tap" ) ]
30
27
private HPUITapEvent tapEvent = new HPUITapEvent ( ) ;
31
28
32
- /// <summary>
33
- /// Event triggered on tap
34
- /// </summary>
29
+ /// <inheritdoc />
35
30
public HPUITapEvent TapEvent { get => tapEvent ; set => tapEvent = value ; }
36
31
37
32
[ SerializeField ]
33
+ [ Tooltip ( "Event triggered on gesture" ) ]
38
34
private HPUIGestureEvent gestureEvent = new HPUIGestureEvent ( ) ;
39
35
36
+ /// <inheritdoc />
37
+ public HPUIGestureEvent GestureEvent { get => gestureEvent ; set => gestureEvent = value ; }
38
+
39
+ [ SerializeField ]
40
+ [ Tooltip ( "Interation hover radius." ) ]
41
+ private float interactionHoverRadius = 0.015f ;
42
+
40
43
/// <summary>
41
- /// Event triggered on gesture
44
+ /// Interation hover radius.
42
45
/// </summary>
43
- public HPUIGestureEvent GestureEvent { get => gestureEvent ; set => gestureEvent = value ; }
46
+ public float InteractionHoverRadius { get => interactionHoverRadius ; set => interactionHoverRadius = value ; }
44
47
45
48
protected IHPUIGestureLogic gestureLogic ;
46
49
private List < IXRInteractable > validTargets = new List < IXRInteractable > ( ) ;
50
+ private bool justStarted = false ;
51
+ private Vector3 lastInteractionPoint ;
52
+ private PhysicsScene physicsScene ;
53
+ private RaycastHit [ ] sphereCastHits = new RaycastHit [ 25 ] ;
54
+ private Collider [ ] overlapSphereHits = new Collider [ 25 ] ;
47
55
48
56
/// <inheritdoc />
49
57
protected override void Awake ( )
50
58
{
51
59
base . Awake ( ) ;
52
60
keepSelectedTargetValid = true ;
61
+ physicsScene = gameObject . scene . GetPhysicsScene ( ) ;
53
62
gestureLogic = new HPUIGestureLogicUnified ( this , TapTimeThreshold , TapDistanceThreshold ) ;
54
63
}
55
64
@@ -66,6 +75,13 @@ protected void OnValidate()
66
75
}
67
76
#endif
68
77
78
+ /// <inheritdoc />
79
+ protected override void OnEnable ( )
80
+ {
81
+ base . OnEnable ( ) ;
82
+ justStarted = true ;
83
+ }
84
+
69
85
/// <inheritdoc />
70
86
protected override void OnSelectEntering ( SelectEnterEventArgs args )
71
87
{
@@ -80,6 +96,68 @@ protected override void OnSelectExiting(SelectExitEventArgs args)
80
96
gestureLogic . OnSelectExiting ( args . interactableObject as IHPUIInteractable ) ;
81
97
}
82
98
99
+ /// <inheritdoc />
100
+ public override void PreprocessInteractor ( XRInteractionUpdateOrder . UpdatePhase updatePhase )
101
+ {
102
+ base . PreprocessInteractor ( updatePhase ) ;
103
+
104
+ // Following the logic in XRPokeInteractor
105
+ if ( updatePhase == XRInteractionUpdateOrder . UpdatePhase . Dynamic )
106
+ {
107
+ validTargets . Clear ( ) ;
108
+
109
+ // Hover Check
110
+ Vector3 pokeInteractionPoint = GetAttachTransform ( null ) . position ;
111
+ Vector3 overlapStart = lastInteractionPoint ;
112
+ Vector3 interFrameEnd = pokeInteractionPoint ; // FIXME: Think of getting this of collision points?
113
+
114
+ BurstPhysicsUtils . GetSphereOverlapParameters ( overlapStart , interFrameEnd , out Vector3 normalizedOverlapVector , out float overlapSqrMagnitude , out float overlapDistance ) ;
115
+
116
+ // If no movement is recorded.
117
+ // Check if spherecast size is sufficient for proper cast, or if first frame since last frame poke position will be invalid.
118
+ int numberOfOverlaps ;
119
+
120
+ if ( justStarted || overlapSqrMagnitude < 0.001f )
121
+ {
122
+ numberOfOverlaps = physicsScene . OverlapSphere (
123
+ interFrameEnd ,
124
+ InteractionHoverRadius ,
125
+ overlapSphereHits ,
126
+ // FIXME: physics layers should be allowed to be set in inpsector
127
+ Physics . AllLayers ,
128
+ // FIXME: QueryTriggerInteraction should be allowed to be set in inpsector
129
+ QueryTriggerInteraction . Ignore ) ;
130
+ }
131
+ else
132
+ {
133
+ numberOfOverlaps = physicsScene . SphereCast (
134
+ overlapStart ,
135
+ InteractionHoverRadius ,
136
+ normalizedOverlapVector ,
137
+ sphereCastHits ,
138
+ overlapDistance ,
139
+ // FIXME: physics layers should be allowed to be set in inpsector
140
+ Physics . AllLayers ,
141
+ // FIXME: QueryTriggerInteraction should be allowed to be set in inpsector
142
+ QueryTriggerInteraction . Ignore ) ;
143
+
144
+ }
145
+
146
+ lastInteractionPoint = pokeInteractionPoint ;
147
+ justStarted = false ;
148
+
149
+ for ( var i = 0 ; i < numberOfOverlaps ; ++ i )
150
+ {
151
+ if ( interactionManager . TryGetInteractableForCollider ( sphereCastHits [ i ] . collider , out var interactable ) &&
152
+ interactable is IXRSelectInteractable selectable &&
153
+ interactable is IXRHoverInteractable hoverable && hoverable . IsHoverableBy ( this ) )
154
+ {
155
+ validTargets . Add ( interactable ) ;
156
+ }
157
+ }
158
+ }
159
+ }
160
+
83
161
/// <inheritdoc />
84
162
public override void ProcessInteractor ( XRInteractionUpdateOrder . UpdatePhase updatePhase )
85
163
{
@@ -93,25 +171,13 @@ public override void ProcessInteractor(XRInteractionUpdateOrder.UpdatePhase upda
93
171
public override void GetValidTargets ( List < IXRInteractable > targets )
94
172
{
95
173
base . GetValidTargets ( targets ) ;
96
- if ( handedness == Handedness . Invalid )
97
- {
98
- throw new InvalidOperationException ( "handedness not correcly set." ) ;
99
- }
100
-
101
- List < IXRInteractable > recievedTargets = ListPool < IXRInteractable > . Get ( ) ;
102
- recievedTargets . AddRange ( targets . Distinct ( ) ) ;
103
174
104
175
targets . Clear ( ) ;
105
- validTargets . Clear ( ) ;
106
- foreach ( IXRInteractable target in recievedTargets . Select ( t => t as IHPUIInteractable ) . Where ( ht => ht != null ) . OrderBy ( ht => ht . zOrder ) )
176
+ foreach ( IXRInteractable target in validTargets . Select ( t => t as IHPUIInteractable ) . Where ( ht => ht != null ) . OrderBy ( ht => ht . zOrder ) )
107
177
{
108
178
targets . Add ( target ) ;
109
179
validTargets . Add ( target ) ;
110
180
}
111
-
112
- // TODO check if an interactable with lower z order is selected. If so cancel it.
113
-
114
- ListPool < IXRInteractable > . Release ( recievedTargets ) ;
115
181
}
116
182
117
183
// NOTE: PokeInteractor has a bug where it doesn't account for the re-prioritization.
0 commit comments