ProximityDetector.cs
7 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
/******************************************************************************
* Copyright (C) Leap Motion, Inc. 2011-2017. *
* Leap Motion proprietary and confidential. *
* *
* Use subject to the terms of the Leap Motion SDK Agreement available at *
* https://developer.leapmotion.com/sdk_agreement, or another agreement *
* between Leap Motion and you, your company or other organization. *
******************************************************************************/
using UnityEngine;
using UnityEngine.Events;
using System.Collections;
using System.Collections.Generic;
using Leap.Unity.Attributes;
namespace Leap.Unity{
/**
* Detects when the parent GameObject is within the specified distance
* of one of the target objects.
* @since 4.1.2
*/
public class ProximityDetector : Detector {
/**
* Dispatched when the proximity check succeeds.
* The ProximityEvent object provides a reference to the proximate GameObject.
* @since 4.1.2
*/
[Tooltip("Dispatched when close enough to a target.")]
public ProximityEvent OnProximity;
/**
* The interval at which to check palm direction.
* @since 4.1.2
*/
[Units("seconds")]
[MinValue(0)]
[Tooltip("The interval in seconds at which to check this detector's conditions.")]
public float Period = .1f; //seconds
/**
* The list of objects which can activate the detector by proximity.
* @since 4.1.2
*/
[Header("Detector Targets")]
[Tooltip("The list of target objects.")]
[DisableIf("UseLayersNotList", true)]
public GameObject[] TargetObjects;
/**
* Include objects with the specified tag in the list of target objects.
* Objects are not added dynamically, however, so objects spawned with the tag will
* not be included.
* @since 4.1.3
*/
[Tooltip("Objects with this tag are added to the list of targets.")]
[DisableIf("UseLayersNotList", true)]
public string TagName = "";
[Tooltip("Use a Layer instead of the target list.")]
public bool UseLayersNotList = false;
[Tooltip("The Layer containing the objects to check.")]
[DisableIf("UseLayersNotList", false)]
public LayerMask Layer;
/**
* The distance in meters between this game object and the target game object that
* will pass the proximity check.
* @since 4.1.2
*/
[Header("Distance Settings")]
[Tooltip("The target distance in meters to activate the detector.")]
[MinValue(0)]
public float OnDistance = .01f; //meters
/**
* The distance in meters between this game object and the target game object that
* will turn off the detector.
* @since 4.1.2
*/
[Tooltip("The distance in meters at which to deactivate the detector.")]
public float OffDistance = .015f; //meters
/**
* The object that is close to the activated detector.
*
* If more than one target object is within the required distance, it is
* undefined which object will be current. Set to null when no targets
* are close enough.
* @since 4.1.2
*/
public GameObject CurrentObject { get { return _currentObj; } }
/** Whether to draw the detector's Gizmos for debugging. (Not every detector provides gizmos.)
* @since 4.1.2
*/
[Header("")]
[Tooltip("Draw this detector's Gizmos, if any. (Gizmos must be on in Unity edtor, too.)")]
public bool ShowGizmos = true;
private IEnumerator proximityWatcherCoroutine;
private GameObject _currentObj = null;
protected virtual void OnValidate() {
//Activate value cannot be less than deactivate value
if (OffDistance < OnDistance) {
OffDistance = OnDistance;
}
}
void Awake() {
proximityWatcherCoroutine = proximityWatcher();
if (TagName != "") {
GameObject[] taggedObjects = GameObject.FindGameObjectsWithTag(TagName);
List<GameObject> targets = new List<GameObject>(taggedObjects.Length + TargetObjects.Length);
for (int t = 0; t < TargetObjects.Length; t++) {
targets.Add(TargetObjects[t]);
}
for (int t = 0; t < taggedObjects.Length; t++) {
targets.Add(taggedObjects[t]);
}
TargetObjects = targets.ToArray();
}
}
void OnEnable () {
StopCoroutine(proximityWatcherCoroutine);
StartCoroutine(proximityWatcherCoroutine);
}
void OnDisable () {
StopCoroutine(proximityWatcherCoroutine);
Deactivate();
}
IEnumerator proximityWatcher(){
bool proximityState = false;
float onSquared, offSquared; //Use squared distances to avoid taking square roots
while(true){
onSquared = OnDistance * OnDistance;
offSquared = OffDistance * OffDistance;
if(_currentObj != null){
if(distanceSquared(_currentObj) > offSquared){
_currentObj = null;
proximityState = false;
}
} else {
if (UseLayersNotList) {
Collider[] nearby = Physics.OverlapSphere(transform.position, OnDistance, Layer);
if(nearby.Length > 0) {
_currentObj = nearby[0].gameObject;
proximityState = true;
OnProximity.Invoke(_currentObj);
}
} else {
for (int obj = 0; obj < TargetObjects.Length; obj++) {
GameObject target = TargetObjects[obj];
if (distanceSquared(target) < onSquared) {
_currentObj = target;
proximityState = true;
OnProximity.Invoke(_currentObj);
break; // pick first match
}
}
}
}
if(proximityState){
Activate();
} else {
Deactivate();
}
yield return new WaitForSeconds(Period);
}
}
private float distanceSquared(GameObject target){
Collider targetCollider = target.GetComponent<Collider>();
Vector3 closestPoint;
if(targetCollider != null){
closestPoint = targetCollider.ClosestPointOnBounds(transform.position);
} else {
closestPoint = target.transform.position;
}
return (closestPoint - transform.position).sqrMagnitude;
}
#if UNITY_EDITOR
void OnDrawGizmos() {
if (ShowGizmos) {
if (IsActive) {
Gizmos.color = Color.green;
} else {
Gizmos.color = Color.red;
}
Gizmos.DrawWireSphere(transform.position, OnDistance);
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(transform.position, OffDistance);
}
}
#endif
}
/**
* An event class that is dispatched by a ProximityDetector when the detector's
* game object comes close enough to a game object in its target list.
* The event parameters provide the proximate game object.
* @since 4.1.2
*/
[System.Serializable]
public class ProximityEvent : UnityEvent <GameObject> {}
}