-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathPanelUIController.cs
More file actions
217 lines (185 loc) · 6.73 KB
/
Copy pathPanelUIController.cs
File metadata and controls
217 lines (185 loc) · 6.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.Hands;
namespace NovaSamples.HandMenu
{
/// <summary>
/// The component responsible for positioning a hand-tracked menu and opening/closing various UI panels triggered by the hand menu.
/// </summary>
public class PanelUIController : MonoBehaviour
{
[SerializeField]
[Tooltip("The camera attached to the user's head.")]
private Camera headTrackedCamera = null;
[Header("Hand Tracking")]
[SerializeField]
[Tooltip("Unity's articulated hand-tracking event component.")]
private XRHandTrackingEvents hand = null;
[SerializeField]
[Tooltip("A transform at the center of the hand-tracked palm.")]
private Transform palmTransform = null;
[SerializeField]
[Tooltip("The threshold, in degrees, between the user's head and palm to activate/deactivate the Hand Launcher UI")]
private float showLauncherThreshold = 35f;
[Header("Panel Launching")]
[SerializeField]
[Tooltip("The controller responsible for displaying a list of buttons that, when selected, will launch a given Panel UI.")]
private HandLauncher handLauncher = null;
[SerializeField]
[Tooltip("The Transform used to position/rotate the Hand Launcher UI.")]
private Transform handLauncherPivot = null;
[SerializeField]
[Tooltip("The Transform providing a world location to pop up a Panel UI.")]
private Transform panelPopupLocation = null;
[SerializeField]
[Tooltip("The list of panels which can be launched from the Hand Launcher UI.")]
private List<Panel> Panels = null;
[Header("Lights")]
[SerializeField]
[Tooltip("The primary direction light in the scene.")]
private Light directionLight = null;
[SerializeField]
[Tooltip("A point light on one of the OVRHands index fingers.")]
private Light fingerTipPointLight = null;
/// <summary>
/// Is the hand launcher UI enabled?
/// </summary>
private bool handLauncherActive = false;
/// <summary>
/// Is the selected panel UI enabled?
/// </summary>
private bool selectedPanelActive = false;
/// <summary>
/// Is the user looking at their palm?
/// </summary>
private bool HandLauncherShouldBeActive
{
get
{
float angleBetweenHeadAndPalm = Vector3.Angle(-palmTransform.up, headTrackedCamera.transform.forward);
return Mathf.Abs(angleBetweenHeadAndPalm) < showLauncherThreshold;
}
}
private void Awake()
{
// Subscribe to panel open events
handLauncher.OnPanelSelected += HandlePanelSelected;
// Subscribe to panel close events
for (int i = 0; i < Panels.Count; i++)
{
Panels[i].OnClosed += HandleSelectedPanelClosed;
Panels[i].gameObject.SetActive(false);
}
// Start with the hand launcher inactive
handLauncher.gameObject.SetActive(false);
}
private void Update()
{
if (selectedPanelActive)
{
// Don't show hand launcher if a panel is active.
return;
}
if (!hand.handIsTracked)
{
// Hand isn't tracked, ensure hand launcher is hidden.
HideHandLauncher();
return;
}
if (handLauncherActive) // Currently active
{
if (!HandLauncherShouldBeActive) // Should be inactive
{
// Hide
HideHandLauncher();
}
else // Should be active
{
// Update position
RepositionMenu();
}
}
else if (HandLauncherShouldBeActive) // Not active, but it should be
{
// Open
ShowHandLauncher();
// Update position
RepositionMenu();
}
}
/// <summary>
/// Close the <see cref="handLauncher"/> UI.
/// </summary>
private void HideHandLauncher()
{
if (!handLauncherActive)
{
return;
}
handLauncherActive = false;
handLauncher.Hide();
}
/// <summary>
/// Open the <see cref="handLauncher"/> UI.
/// </summary>
private void ShowHandLauncher()
{
if (handLauncherActive)
{
return;
}
handLauncherActive = true;
handLauncher.Show();
}
/// <summary>
/// Handle panel closed event.
/// </summary>
private void HandleSelectedPanelClosed()
{
selectedPanelActive = false;
directionLight.enabled = true;
fingerTipPointLight.enabled = false;
}
/// <summary>
/// Open a given panel UI when it's selected from the <see cref="handLauncher"/>.
/// </summary>
/// <param name="item">The item clicked in the <see cref="handLauncher"/> UI.</param>
private void HandlePanelSelected(PanelItem item)
{
if (item.Panel == null)
{
// Nothing to open
return;
}
// Get the index of the selected panel.
int index = Panels.IndexOf(item.Panel);
if (index == -1)
{
// Not found, nothing to open.
return;
}
Panel panel = Panels[index];
// Panel requested Torch Pointer, so
// enable the point light and disable
// the primary direction light.
if (panel.UseTorchPointer)
{
directionLight.enabled = false;
fingerTipPointLight.enabled = true;
}
// Open the panel at the popup location
panel.Open(panelPopupLocation.position, panelPopupLocation.rotation);
// Indicate a panel is active, so we don't activate the handLauncher
selectedPanelActive = true;
// Close
HideHandLauncher();
}
/// <summary>
/// Reposition the <see cref="handLauncher"/> to a fixed offset from the user's hand.
/// </summary>
private void RepositionMenu()
{
handLauncher.transform.SetPositionAndRotation(handLauncherPivot.position, handLauncherPivot.rotation);
}
}
}