-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathInteractor.cs
153 lines (129 loc) · 4.2 KB
/
Interactor.cs
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
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.InputSystem;
namespace VitrivrVR.Interaction.System
{
public class Interactor : MonoBehaviour
{
public InputAction interact;
public InputAction grab;
public InputActionReference uiClickAction;
public int clickBindingIndex;
public InputActionReference uiPointAction;
public int pointBindingIndex;
public GameObject uiLine;
private readonly HashSet<Interactable> _interactables = new();
private HashSet<Interactable> _grabbed;
private HashSet<Interactable> _interacting;
private bool _uiPointerActive = true;
private void Awake()
{
interact.started += context => Interact(context.ReadValueAsButton());
interact.canceled += context => Interact(context.ReadValueAsButton());
grab.started += context => Grab(context.ReadValueAsButton());
grab.canceled += context => Grab(context.ReadValueAsButton());
}
private void OnEnable()
{
interact.Enable();
grab.Enable();
}
private void OnDisable()
{
interact.Disable();
grab.Disable();
}
public void Interact(bool start)
{
RemoveDisabledOrDestroyed();
if (start)
{
_interacting = new HashSet<Interactable>(_interactables);
foreach (var interactable in _interactables)
{
interactable.OnInteraction(transform, true);
}
}
else
{
foreach (var interactable in _interacting)
{
interactable.OnInteraction(transform, false);
_interacting = null;
}
}
}
public void Grab(bool start)
{
RemoveDisabledOrDestroyed();
if (start)
{
_grabbed = new HashSet<Interactable>(_interactables);
foreach (var interactable in _interactables)
{
interactable.OnGrab(transform, true);
}
}
else
{
foreach (var interactable in _grabbed.Where(interactable => interactable))
{
interactable.OnGrab(transform, false);
}
_grabbed = null;
}
}
private static bool GetInteractable(Collider collider, out Interactable interactable)
{
// Check collider for interactable, then check attached rigidbody
return collider.TryGetComponent(out interactable) || collider.attachedRigidbody.TryGetComponent(out interactable);
}
private void OnTriggerEnter(Collider other)
{
if (!GetInteractable(other, out var interactable)) return;
if (!_interactables.Add(interactable)) return;
interactable.OnHoverEnter(transform);
UpdateUIPointer();
}
private void OnTriggerExit(Collider other)
{
if (!GetInteractable(other, out var interactable)) return;
if (!_interactables.Remove(interactable)) return;
interactable.OnHoverExit(transform);
UpdateUIPointer();
}
private void FixedUpdate()
{
// Reduce chance of interactables containing an interactable this interactor is no longer over
RemoveDisabledOrDestroyed();
UpdateUIPointer();
}
private void RemoveDisabledOrDestroyed()
{
_interactables.RemoveWhere(interactable => interactable == null);
_interactables.RemoveWhere(interactable => !interactable.gameObject.activeInHierarchy);
_grabbed?.RemoveWhere(interactable => interactable == null);
_interacting?.RemoveWhere(interactable => interactable == null);
}
private void UpdateUIPointer()
{
var shouldBeDisabled = _interactables.Any(interactable => interactable.disablesPointer);
switch (shouldBeDisabled)
{
case true when _uiPointerActive:
uiClickAction.action.ApplyBindingOverride(clickBindingIndex, string.Empty);
uiPointAction.action.ApplyBindingOverride(pointBindingIndex, string.Empty);
_uiPointerActive = false;
uiLine.SetActive(false);
break;
case false when !_uiPointerActive:
uiClickAction.action.RemoveBindingOverride(clickBindingIndex);
uiPointAction.action.RemoveBindingOverride(pointBindingIndex);
_uiPointerActive = true;
uiLine.SetActive(true);
break;
}
}
}
}