-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathControllerManager.cs
More file actions
356 lines (314 loc) · 12.4 KB
/
ControllerManager.cs
File metadata and controls
356 lines (314 loc) · 12.4 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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.Interaction.Toolkit;
[DefaultExecutionOrder(kControllerManagerUpdateOrder)]
public class ControllerManager : MonoBehaviour
{
// Slightly after the default, so that any actions such as release or grab can be processed *before* we switch controllers.
public const int kControllerManagerUpdateOrder = 10;
InputDevice m_RightController;
InputDevice m_LeftController;
[SerializeField]
[Tooltip("The buttons on the controller that will trigger a transition to the Teleport Controller.")]
List<InputHelpers.Button> m_ActivationButtons = new List<InputHelpers.Button>();
/// <summary>
/// The buttons on the controller that will trigger a transition to the Teleport Controller.
/// </summary>
public List<InputHelpers.Button> activationButtons { get { return m_ActivationButtons; } set { m_ActivationButtons = value; } }
[SerializeField]
[Tooltip("The buttons on the controller that will force a deactivation of the teleport option.")]
List<InputHelpers.Button> m_DeactivationButtons = new List<InputHelpers.Button>();
/// <summary>
/// The buttons on the controller that will trigger a transition to the Teleport Controller.
/// </summary>
public List<InputHelpers.Button> deactivationButtons { get { return m_DeactivationButtons; } set { m_DeactivationButtons = value; } }
[SerializeField]
[Tooltip("The Game Object which represents the left hand for normal interaction purposes.")]
GameObject m_LeftBaseController;
/// <summary>
/// The Game Object which represents the left hand for normal interaction purposes.
/// </summary>
public GameObject leftBaseController { get { return m_LeftBaseController; } set { m_LeftBaseController = value; } }
[SerializeField]
[Tooltip("The Game Object which represents the left hand when teleporting.")]
GameObject m_LeftTeleportController;
/// <summary>
/// The Game Object which represents the left hand when teleporting.
/// </summary>
public GameObject leftTeleportController { get { return m_LeftTeleportController; } set { m_LeftTeleportController = value; } }
[SerializeField]
[Tooltip("The Game Object which represents the right hand for normal interaction purposes.")]
GameObject m_RightBaseController;
/// <summary>
/// The Game Object which represents the right hand for normal interaction purposes.
/// </summary>
public GameObject rightBaseController { get { return m_RightBaseController; } set { m_RightBaseController = value; } }
[SerializeField]
[Tooltip("The Game Object which represents the right hand when teleporting.")]
GameObject m_RightTeleportController;
/// <summary>
/// The Game Object which represents the right hand when teleporting.
/// </summary>
public GameObject rightTeleportController { get { return m_RightTeleportController; } set { m_RightTeleportController = value; } }
bool m_LeftTeleportDeactivated = false;
bool m_RightTeleportDeactivated = false;
/// <summary>
/// A simple state machine which manages the three pieces of content that are used to represent
/// A controller state within the XR Interaction Toolkit
/// </summary>
struct InteractorController
{
/// <summary>
/// The game object that this state controls
/// </summary>
public GameObject m_GO;
/// <summary>
/// The XR Controller instance that is associated with this state
/// </summary>
public XRController m_XRController;
/// <summary>
/// The Line renderer that is associated with this state
/// </summary>
public XRInteractorLineVisual m_LineRenderer;
/// <summary>
/// The interactor instance that is associated with this state
/// </summary>
public XRBaseInteractor m_Interactor;
/// <summary>
/// When passed a gameObject, this function will scrape the game object for all valid components that we will
/// interact with by enabling/disabling as the state changes
/// </summary>
/// <param name="gameObject">The game object to scrape the various components from</param>
public void Attach(GameObject gameObject)
{
m_GO = gameObject;
if (m_GO != null)
{
m_XRController = m_GO.GetComponent<XRController>();
m_LineRenderer = m_GO.GetComponent<XRInteractorLineVisual>();
m_Interactor = m_GO.GetComponent<XRBaseInteractor>();
Leave();
}
}
/// <summary>
/// Enter this state, performs a set of changes to the associated components to enable things
/// </summary>
public void Enter()
{
if (m_LineRenderer)
{
m_LineRenderer.enabled = true;
}
if (m_XRController)
{
m_XRController.enableInputActions = true;
}
if (m_Interactor)
{
m_Interactor.enabled = true;
}
}
/// <summary>
/// Leaves this state, performs a set of changes to the associate components to disable things.
/// </summary>
public void Leave()
{
if (m_LineRenderer)
{
m_LineRenderer.enabled = false;
}
if (m_XRController)
{
m_XRController.enableInputActions = false;
}
if(m_Interactor)
{
m_Interactor.enabled = false;
}
}
}
/// <summary>
/// The states that we are currently modeling.
/// If you want to add more states, add them here!
/// </summary>
public enum ControllerStates
{
/// <summary>
/// the Select state is the "normal" interaction state for selecting and interacting with objects
/// </summary>
Select = 0,
/// <summary>
/// the Teleport state is used to interact with teleport interactors and queue teleportations.
/// </summary>
Teleport = 1,
/// <summary>
/// Maximum sentinel
/// </summary>
MAX = 2,
}
/// <summary>
/// Current status of a controller. there will be two instances of this (for left/right). and this allows
/// the system to change between different states on each controller independently.
/// </summary>
struct ControllerState
{
ControllerStates m_State;
InteractorController[] m_Interactors;
/// <summary>
/// Sets up the controller
/// </summary>
public void Initialize()
{
m_State = ControllerStates.MAX;
m_Interactors = new InteractorController[(int)ControllerStates.MAX];
}
/// <summary>
/// Exits from all states that are in the list, basically a reset.
/// </summary>
public void ClearAll()
{
if(m_Interactors == null)
return;
for(int i = 0; i < (int)ControllerStates.MAX; ++i)
{
m_Interactors[i].Leave();
}
}
/// <summary>
/// Attaches a game object that represents an interactor for a state, to a state.
/// </summary>
/// <param name="state">The state that we're attaching the game object to</param>
/// <param name="parentGamObject">The game object that represents the interactor for that state.</param>
public void SetGameObject(ControllerStates state, GameObject parentGamObject)
{
if ((state == ControllerStates.MAX) || (m_Interactors == null))
return;
m_Interactors[(int)state].Attach(parentGamObject);
}
/// <summary>
/// Attempts to set the current state of a controller.
/// </summary>
/// <param name="nextState">The state that we wish to transition to</param>
public void SetState(ControllerStates nextState)
{
if (nextState == m_State || nextState == ControllerStates.MAX)
{
return;
}
else
{
if (m_State != ControllerStates.MAX)
{
m_Interactors[(int)m_State].Leave();
}
m_State = nextState;
m_Interactors[(int)m_State].Enter();
}
}
}
ControllerState m_RightControllerState;
ControllerState m_LeftControllerState;
void OnEnable()
{
m_LeftTeleportDeactivated = false;
m_RightTeleportDeactivated = false;
m_RightControllerState.Initialize();
m_LeftControllerState.Initialize();
m_RightControllerState.SetGameObject(ControllerStates.Select, m_RightBaseController);
m_RightControllerState.SetGameObject(ControllerStates.Teleport, m_RightTeleportController);
m_LeftControllerState.SetGameObject(ControllerStates.Select, m_LeftBaseController);
m_LeftControllerState.SetGameObject(ControllerStates.Teleport, m_LeftTeleportController);
m_LeftControllerState.ClearAll();
m_RightControllerState.ClearAll();
InputDevices.deviceConnected += RegisterDevices;
List<InputDevice> devices = new List<InputDevice>();
InputDevices.GetDevices(devices);
for (int i = 0; i < devices.Count; i++)
RegisterDevices(devices[i]);
}
void OnDisable()
{
InputDevices.deviceConnected -= RegisterDevices;
}
void RegisterDevices(InputDevice connectedDevice)
{
if (connectedDevice.isValid)
{
#if UNITY_2019_3_OR_NEWER
if((connectedDevice.characteristics & InputDeviceCharacteristics.Left) != 0)
#else
if (connectedDevice.role == InputDeviceRole.LeftHanded)
#endif
{
m_LeftController = connectedDevice;
m_LeftControllerState.ClearAll();
m_LeftControllerState.SetState(ControllerStates.Select);
}
#if UNITY_2019_3_OR_NEWER
else if ((connectedDevice.characteristics & InputDeviceCharacteristics.Right) != 0)
#else
else if (connectedDevice.role == InputDeviceRole.RightHanded)
#endif
{
m_RightController = connectedDevice;
m_RightControllerState.ClearAll();
m_RightControllerState.SetState(ControllerStates.Select);
}
}
}
void Update()
{
if (m_LeftController.isValid)
{
bool activated = false;
foreach (var button in m_ActivationButtons)
{
m_LeftController.IsPressed(button, out bool value);
activated |= value;
}
foreach (var button in m_DeactivationButtons)
{
m_LeftController.IsPressed(button, out bool value);
m_LeftTeleportDeactivated |= value;
}
// if we're pressing the activation buttons, we transition to Teleport
if (activated && !m_LeftTeleportDeactivated)
{
m_LeftControllerState.SetState(ControllerStates.Teleport);
}
// otherwise we're in normal state.
else
{
m_LeftControllerState.SetState(ControllerStates.Select);
if(!activated)
m_LeftTeleportDeactivated = false;
}
}
if (m_RightController.isValid)
{
bool activated = false;
foreach (var button in m_ActivationButtons)
{
m_RightController.IsPressed(button, out bool value);
activated |= value;
}
foreach (var button in m_DeactivationButtons)
{
m_RightController.IsPressed(button, out bool value);
m_RightTeleportDeactivated |= value;
}
if (activated && !m_RightTeleportDeactivated)
{
m_RightControllerState.SetState(ControllerStates.Teleport);
}
else
{
m_RightControllerState.SetState(ControllerStates.Select);
if (!activated)
m_RightTeleportDeactivated = false;
}
}
}
}