Skip to content

Commit 15bf1d2

Browse files
committed
feat(Interaction): service pack for 3D controls
This patch is the result of adapting the first set of controls to a real game scene. So far only the drawer allowed to set an optional content object. This was now refactored into the control and now also the door and chest can profit from the same logic. In addition objects that were taken out of a drawer would disappear again if the drawer was closed even if the objects were outside. This needed to be handled with custom logic. Now there is a helper script that will manage reparenting automatically. In addition some code cleanup was done and where already applicable the direction was extracted with the ultimate goal to have only one direction enum. Finally the button contains a small bug fix to define the force in a much more reliable way.
1 parent b24ffe9 commit 15bf1d2

File tree

14 files changed

+1127
-291
lines changed

14 files changed

+1127
-291
lines changed

Assets/SteamVR_Unity_Toolkit/Examples/025_Controls_Overview.unity

Lines changed: 879 additions & 160 deletions
Large diffs are not rendered by default.

Assets/SteamVR_Unity_Toolkit/Scripts/Controls/3D/Utilities.meta

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
namespace VRTK
2+
{
3+
using UnityEngine;
4+
5+
/// <summary>
6+
/// This script will make objects inside of control contents properly interactable by reparenting them.
7+
/// Otherwise they would disappear if e.g. a drawer is closed even if the object was outside the drawer.
8+
/// We need to go through collisions instead of hooking to the Ungrabbed event since ungrabbing will most likely happen above the inside causing the object to drop first.
9+
/// This approach is much more stable and allows for many more scenarios.
10+
/// Not supported yet: detect if an object is taken from one content manager and dropped into another one.
11+
/// </summary>
12+
public class VRTK_ContentHandler : MonoBehaviour
13+
{
14+
public VRTK_Control control;
15+
public Transform inside;
16+
public Transform outside;
17+
18+
private void Start()
19+
{
20+
VRTK_InteractableObject io = GetComponent<VRTK_InteractableObject>();
21+
if (io == null)
22+
{
23+
// treat as parent and assign to all children
24+
foreach (VRTK_InteractableObject childIo in GetComponentsInChildren<VRTK_InteractableObject>())
25+
{
26+
if (childIo.GetComponent<VRTK_ContentHandler>() == null)
27+
{
28+
VRTK_ContentHandler ch = childIo.gameObject.AddComponent<VRTK_ContentHandler>();
29+
ch.control = control;
30+
ch.inside = inside;
31+
ch.outside = outside;
32+
}
33+
}
34+
}
35+
}
36+
37+
private void OnCollisionEnter(Collision collision)
38+
{
39+
Bounds insideBounds = Utilities.GetBounds(inside, null, control.GetContent().transform);
40+
Bounds objBounds = Utilities.GetBounds(transform);
41+
42+
if (objBounds.Intersects(insideBounds))
43+
{
44+
transform.parent = control.GetContent().transform;
45+
}
46+
else
47+
{
48+
transform.parent = outside;
49+
}
50+
}
51+
52+
}
53+
}

Assets/SteamVR_Unity_Toolkit/Scripts/Controls/3D/Utilities/VRTK_ContentHandler.cs.meta

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Assets/SteamVR_Unity_Toolkit/Scripts/Controls/3D/VRTK_Button.cs

Lines changed: 32 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ public class ButtonEvents
1111
public UnityEvent OnPush;
1212
}
1313

14-
public enum Direction
14+
public enum ButtonDirection
1515
{
1616
autodetect, x, y, z, negX, negY, negZ
1717
}
1818

1919
public ButtonEvents events;
2020

21-
public Direction direction = Direction.autodetect;
21+
public ButtonDirection direction = ButtonDirection.autodetect;
2222
public float activationDistance = 1.0f;
2323
public float buttonStrength = 5.0f;
2424

2525
private static float MAX_AUTODETECT_ACTIVATION_LENGTH = 4; // full hight of button
2626

27-
private Direction finalDirection;
27+
private ButtonDirection finalDirection;
2828
private Vector3 initialPosition;
2929
private Vector3 activationPoint;
3030

@@ -70,13 +70,13 @@ protected override void InitRequiredComponents()
7070

7171
protected override bool DetectSetup()
7272
{
73-
finalDirection = (direction == Direction.autodetect) ? DetectDirection() : direction;
74-
if (finalDirection == Direction.autodetect)
73+
finalDirection = (direction == ButtonDirection.autodetect) ? DetectDirection() : direction;
74+
if (finalDirection == ButtonDirection.autodetect)
7575
{
7676
activationPoint = transform.position;
7777
return false;
7878
}
79-
if (direction != Direction.autodetect)
79+
if (direction != ButtonDirection.autodetect)
8080
{
8181
activationPoint = CalculateActivationPoint();
8282
}
@@ -110,8 +110,8 @@ protected override bool DetectSetup()
110110

111111
switch (finalDirection)
112112
{
113-
case Direction.x:
114-
case Direction.negX:
113+
case ButtonDirection.x:
114+
case ButtonDirection.negX:
115115
if (Mathf.RoundToInt(Mathf.Abs(transform.right.x)) == 1)
116116
{
117117
cj.xMotion = ConfigurableJointMotion.Limited;
@@ -125,8 +125,8 @@ protected override bool DetectSetup()
125125
cj.zMotion = ConfigurableJointMotion.Limited;
126126
}
127127
break;
128-
case Direction.y:
129-
case Direction.negY:
128+
case ButtonDirection.y:
129+
case ButtonDirection.negY:
130130
if (Mathf.RoundToInt(Mathf.Abs(transform.right.y)) == 1)
131131
{
132132
cj.xMotion = ConfigurableJointMotion.Limited;
@@ -140,8 +140,8 @@ protected override bool DetectSetup()
140140
cj.zMotion = ConfigurableJointMotion.Limited;
141141
}
142142
break;
143-
case Direction.z:
144-
case Direction.negZ:
143+
case ButtonDirection.z:
144+
case ButtonDirection.negZ:
145145
if (Mathf.RoundToInt(Mathf.Abs(transform.right.z)) == 1)
146146
{
147147
cj.xMotion = ConfigurableJointMotion.Limited;
@@ -179,9 +179,9 @@ protected override void HandleUpdate()
179179
}
180180
}
181181

182-
private Direction DetectDirection()
182+
private ButtonDirection DetectDirection()
183183
{
184-
Direction direction = Direction.autodetect;
184+
ButtonDirection direction = ButtonDirection.autodetect;
185185
Bounds bounds = Utilities.GetBounds(transform);
186186

187187
// shoot rays from the center of the button to learn about surroundings
@@ -210,48 +210,48 @@ private Direction DetectDirection()
210210
Vector3 hitPoint = Vector3.zero;
211211
if (Utilities.IsLowest(lengthX, new float[] { lengthY, lengthZ, lengthNegX, lengthNegY, lengthNegZ }))
212212
{
213-
direction = Direction.negX;
213+
direction = ButtonDirection.negX;
214214
hitPoint = hitRight.point;
215215
extents = bounds.extents.x;
216216
}
217217
else if (Utilities.IsLowest(lengthY, new float[] { lengthX, lengthZ, lengthNegX, lengthNegY, lengthNegZ }))
218218
{
219-
direction = Direction.y;
219+
direction = ButtonDirection.y;
220220
hitPoint = hitDown.point;
221221
extents = bounds.extents.y;
222222
}
223223
else if (Utilities.IsLowest(lengthZ, new float[] { lengthX, lengthY, lengthNegX, lengthNegY, lengthNegZ }))
224224
{
225-
direction = Direction.z;
225+
direction = ButtonDirection.z;
226226
hitPoint = hitBack.point;
227227
extents = bounds.extents.z;
228228
}
229229
else if (Utilities.IsLowest(lengthNegX, new float[] { lengthX, lengthY, lengthZ, lengthNegY, lengthNegZ }))
230230
{
231-
direction = Direction.x;
231+
direction = ButtonDirection.x;
232232
hitPoint = hitLeft.point;
233233
extents = bounds.extents.x;
234234
}
235235
else if (Utilities.IsLowest(lengthNegY, new float[] { lengthX, lengthY, lengthZ, lengthNegX, lengthNegZ }))
236236
{
237-
direction = Direction.negY;
237+
direction = ButtonDirection.negY;
238238
hitPoint = hitUp.point;
239239
extents = bounds.extents.y;
240240
}
241241
else if (Utilities.IsLowest(lengthNegZ, new float[] { lengthX, lengthY, lengthZ, lengthNegX, lengthNegY }))
242242
{
243-
direction = Direction.negZ;
243+
direction = ButtonDirection.negZ;
244244
hitPoint = hitForward.point;
245245
extents = bounds.extents.z;
246246
}
247247

248248
// determin activation distance
249249
activationDistance = (Vector3.Distance(hitPoint, bounds.center) - extents) * 0.95f;
250250

251-
if (direction == Direction.autodetect || activationDistance < 0.001f)
251+
if (direction == ButtonDirection.autodetect || activationDistance < 0.001f)
252252
{
253253
// auto-detection was not possible or colliding with object already
254-
direction = Direction.autodetect;
254+
direction = ButtonDirection.autodetect;
255255
activationDistance = 0;
256256
}
257257
else
@@ -271,8 +271,8 @@ private Vector3 CalculateActivationPoint()
271271
float extents = 0;
272272
switch (direction)
273273
{
274-
case Direction.x:
275-
case Direction.negX:
274+
case ButtonDirection.x:
275+
case ButtonDirection.negX:
276276
if (Mathf.RoundToInt(Mathf.Abs(transform.right.x)) == 1)
277277
{
278278
buttonDirection = transform.right;
@@ -288,10 +288,10 @@ private Vector3 CalculateActivationPoint()
288288
buttonDirection = transform.forward;
289289
extents = bounds.extents.z;
290290
}
291-
buttonDirection *= (direction == Direction.x) ? -1 : 1;
291+
buttonDirection *= (direction == ButtonDirection.x) ? -1 : 1;
292292
break;
293-
case Direction.y:
294-
case Direction.negY:
293+
case ButtonDirection.y:
294+
case ButtonDirection.negY:
295295
if (Mathf.RoundToInt(Mathf.Abs(transform.right.y)) == 1)
296296
{
297297
buttonDirection = transform.right;
@@ -307,10 +307,10 @@ private Vector3 CalculateActivationPoint()
307307
buttonDirection = transform.forward;
308308
extents = bounds.extents.z;
309309
}
310-
buttonDirection *= (direction == Direction.y) ? -1 : 1;
310+
buttonDirection *= (direction == ButtonDirection.y) ? -1 : 1;
311311
break;
312-
case Direction.z:
313-
case Direction.negZ:
312+
case ButtonDirection.z:
313+
case ButtonDirection.negZ:
314314
if (Mathf.RoundToInt(Mathf.Abs(transform.right.z)) == 1)
315315
{
316316
buttonDirection = transform.right;
@@ -326,7 +326,7 @@ private Vector3 CalculateActivationPoint()
326326
buttonDirection = transform.forward;
327327
extents = bounds.extents.z;
328328
}
329-
buttonDirection *= (direction == Direction.z) ? -1 : 1;
329+
buttonDirection *= (direction == ButtonDirection.z) ? -1 : 1;
330330
break;
331331
}
332332

@@ -341,23 +341,7 @@ private bool ReachedActivationDistance()
341341

342342
private Vector3 GetForceVector()
343343
{
344-
switch (finalDirection)
345-
{
346-
case Direction.x:
347-
return new Vector3(buttonStrength, 0, 0);
348-
case Direction.y:
349-
return new Vector3(0, buttonStrength, 0);
350-
case Direction.z:
351-
return new Vector3(0, 0, buttonStrength);
352-
case Direction.negX:
353-
return new Vector3(-buttonStrength, 0, 0);
354-
case Direction.negY:
355-
return new Vector3(0, -buttonStrength, 0);
356-
case Direction.negZ:
357-
return new Vector3(0, 0, -buttonStrength);
358-
default:
359-
return new Vector3(0, 0, 0);
360-
}
344+
return -(activationPoint - Utilities.GetBounds(transform).center).normalized * buttonStrength;
361345
}
362346
}
363347
}

Assets/SteamVR_Unity_Toolkit/Scripts/Controls/3D/VRTK_Chest.cs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,16 @@
44

55
public class VRTK_Chest : VRTK_Control
66
{
7-
public enum Direction
8-
{
9-
autodetect, x, z // no support for y at this point in time
10-
}
11-
127
public Direction direction = Direction.autodetect;
13-
public float maxAngle = 160f;
148

159
public GameObject lid;
1610
public GameObject body;
1711
public GameObject handle;
12+
[Tooltip("An optional game object that is the parent of the content inside the chest. If set all interactables will become managed so that they only react if the lid is wide enough open.")]
13+
public GameObject content;
14+
[Tooltip("Will make the content invisible if the chest is closed. This way players cannot peak into it by moving the camera.")]
15+
public bool hideContent = true;
16+
public float maxAngle = 160f;
1817

1918
private float minAngle = 0f;
2019
private float stepSize = 1f;
@@ -47,6 +46,9 @@ public override void OnDrawGizmos()
4746
case Direction.x:
4847
point += transform.right.normalized * (length / 2f) * subDirection;
4948
break;
49+
case Direction.y:
50+
point += transform.up.normalized * (length / 2f) * subDirection;
51+
break;
5052
case Direction.z:
5153
point += transform.forward.normalized * (length / 2f) * subDirection;
5254
break;
@@ -61,6 +63,8 @@ protected override void InitRequiredComponents()
6163
InitBody();
6264
InitLid();
6365
InitHandle();
66+
67+
SetContent(content, hideContent);
6468
}
6569

6670
protected override bool DetectSetup()
@@ -84,6 +88,9 @@ protected override bool DetectSetup()
8488
case Direction.x:
8589
subDirection = (handleBounds.center.x > lidBounds.center.x) ? -1 : 1;
8690
break;
91+
case Direction.y:
92+
subDirection = (handleBounds.center.y > lidBounds.center.y) ? -1 : 1;
93+
break;
8794
case Direction.z:
8895
subDirection = (handleBounds.center.z > lidBounds.center.z) ? -1 : 1;
8996
break;
@@ -119,6 +126,20 @@ protected override bool DetectSetup()
119126
limits.max = maxAngle;
120127
}
121128
break;
129+
case Direction.y:
130+
lidHj.anchor = new Vector3(0, subDirection * lidBounds.extents.y, 0);
131+
lidHj.axis = new Vector3(0, 1, 0);
132+
if (subDirection > 0)
133+
{
134+
limits.min = -maxAngle;
135+
limits.max = minAngle;
136+
}
137+
else
138+
{
139+
limits.min = minAngle;
140+
limits.max = maxAngle;
141+
}
142+
break;
122143
case Direction.z:
123144
lidHj.anchor = new Vector3(0, 0, subDirection * lidBounds.extents.z);
124145
lidHj.axis = new Vector3(1, 0, 0);

0 commit comments

Comments
 (0)