Skip to content

Commit

Permalink
feat(Pointer): allow pointers to interact with interactable objects
Browse files Browse the repository at this point in the history
A new option on a World Pointer has been added `interactWithObjects`
that adds a new collider to the controller that the pointer is
associated with that tracks the position of the tip of the pointer.

This means that the new collider will be used in the compound
colliders of the controller and therefore anything the pointer is
touching will be as if the controller is touching it. This means that
the pointer will be able to highlight objects on touch, but also when
grabbing will snap the item to the controller and will also allow
the use action to be triggered remotely using the mapped `Use` button
on the controller.

The `pointerActivatesUseAction` on the interactable object is still
a valid mechanism as it initiates the use action on an interactable
object when the pointer is enabled and disabled and does not need the
`Use` button on the controller pressing. It also prevents teleporting
when this option is checked, whereas just using the pointer as an
extension of the controller wouldn't surpress the teleport event by
default.
  • Loading branch information
thestonefox committed Sep 30, 2016
1 parent 4adf75d commit ae31ddd
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 14 deletions.
48 changes: 46 additions & 2 deletions Assets/VRTK/Scripts/Abstractions/VRTK_WorldPointer.cs
Expand Up @@ -35,12 +35,14 @@ public enum pointerVisibilityStates
public Color pointerHitColor = new Color(0f, 0.5f, 0f, 1f);
[Tooltip("The colour of the beam when it is not hitting a valid target. It can be set to a different colour for each controller.")]
public Color pointerMissColor = new Color(0.8f, 0f, 0f, 1f);
[Tooltip("Determines when the pointer beam should be displayed.")]
public pointerVisibilityStates pointerVisibility = pointerVisibilityStates.On_When_Active;
[Tooltip("If this is checked then the pointer will be an extension of the controller and able to interact with Interactable Objects.")]
public bool interactWithObjects = false;
[Tooltip("If this is checked then the pointer beam will be activated on first press of the pointer alias button and will stay active until the pointer alias button is pressed again. The destination set event is emitted when the beam is deactivated on the second button press.")]
public bool holdButtonToActivate = true;
[Tooltip("The time in seconds to delay the pointer beam being able to be active again. Useful for preventing constant teleportation.")]
public float activateDelay = 0f;
[Tooltip("Determines when the pointer beam should be displayed.")]
public pointerVisibilityStates pointerVisibility = pointerVisibilityStates.On_When_Active;
[Tooltip("The layers to ignore when raycasting.")]
public LayerMask layersToIgnore = Physics.IgnoreRaycastLayer;

Expand All @@ -51,6 +53,7 @@ public enum pointerVisibilityStates
protected uint controllerIndex;
protected VRTK_PlayAreaCursor playAreaCursor;
protected Color currentPointerColor;
protected GameObject objectInteractor;

private bool isActive;
private bool destinationSetActive;
Expand Down Expand Up @@ -124,12 +127,18 @@ protected override void OnEnable()
pointerMaterial.color = pointerMissColor;

playAreaCursor = (GetComponent<VRTK_PlayAreaCursor>() ?? GetComponent<VRTK_PlayAreaCursor>());

if (interactWithObjects)
{
CreateObjectInteractor();
}
}

protected override void OnDisable()
{
base.OnDisable();
DisableBeam();
Destroy(objectInteractor);
destinationSetActive = false;
pointerContactDistance = 0f;
pointerContactTarget = null;
Expand All @@ -142,6 +151,15 @@ protected override void OnDisable()

protected virtual void Update()
{
if (interactWithObjects && objectInteractor.activeInHierarchy)
{
UpdateObjectInteractor();
}
}

protected virtual void UpdateObjectInteractor()
{
objectInteractor.transform.position = destinationPosition;
}

protected virtual void InitPointer()
Expand Down Expand Up @@ -228,6 +246,11 @@ protected virtual void PointerSet()

protected virtual void TogglePointer(bool state)
{
if (interactWithObjects)
{
objectInteractor.SetActive(state);
}

if (playAreaCursor)
{
playAreaCursor.SetHeadsetPositionCompensation(headsetPositionCompensation);
Expand Down Expand Up @@ -294,6 +317,27 @@ protected virtual bool ValidDestination(Transform target, Vector3 destinationPos
return (validNavMeshLocation && target && !(Utilities.TagOrScriptCheck(target.gameObject, invalidTagOrScriptListPolicy, invalidTargetWithTagOrClass)));
}

protected virtual void CreateObjectInteractor()
{
objectInteractor = new GameObject(string.Format("[{0}]WorldPointer_ObjectIneractor_Holder", gameObject.name));
objectInteractor.transform.SetParent(controller.transform);
objectInteractor.transform.localPosition = Vector3.zero;
objectInteractor.layer = LayerMask.NameToLayer("Ignore Raycast");
Utilities.SetPlayerObject(objectInteractor, VRTK_PlayerObject.ObjectTypes.Pointer);

var objectInteractorCollider = new GameObject(string.Format("[{0}]WorldPointer_ObjectIneractor_Collider", gameObject.name));
objectInteractorCollider.transform.SetParent(objectInteractor.transform);
objectInteractorCollider.transform.localPosition = Vector3.zero;
objectInteractorCollider.layer = LayerMask.NameToLayer("Ignore Raycast");
var tmpCollider = objectInteractorCollider.AddComponent<SphereCollider>();
tmpCollider.isTrigger = true;
Utilities.SetPlayerObject(objectInteractorCollider, VRTK_PlayerObject.ObjectTypes.Pointer);

var objectInteractorScale = 0.025f;
objectInteractor.transform.localScale = new Vector3(objectInteractorScale, objectInteractorScale, objectInteractorScale);
objectInteractor.SetActive(false);
}

private bool InvalidConstantBeam()
{
var equalToggleSet = controller.pointerToggleButton == controller.pointerSetButton;
Expand Down
26 changes: 15 additions & 11 deletions Assets/VRTK/Scripts/VRTK_InteractTouch.cs
Expand Up @@ -59,6 +59,8 @@ public class VRTK_InteractTouch : MonoBehaviour
private GameObject controllerCollisionDetector;
private bool triggerRumble;
private bool destroyColliderOnDisable;
private bool triggerIsColliding = false;
private bool triggerWasColliding = false;
private Rigidbody touchRigidBody;
private Object defaultColliderPrefab;
private VRTK_ControllerEvents.ButtonAlias originalGrabAlias;
Expand Down Expand Up @@ -263,6 +265,7 @@ private void CheckRumbleController(VRTK_InteractableObject touchedObjectScript)

private void OnTriggerEnter(Collider collider)
{
triggerIsColliding = true;
AddActiveCollider(collider);

var colliderInteractableObject = GetColliderInteractableObject(collider);
Expand All @@ -275,8 +278,17 @@ private void OnTriggerEnter(Collider collider)
}
}

private void OnTriggerExit(Collider collider)
{
if (touchedObjectActiveColliders.Contains(collider))
{
touchedObjectActiveColliders.Remove(collider);
}
}

private void OnTriggerStay(Collider collider)
{
triggerIsColliding = true;
AddActiveCollider(collider);

var colliderInteractableObject = GetColliderInteractableObject(collider);
Expand All @@ -291,7 +303,6 @@ private void OnTriggerStay(Collider collider)
CleanupEndTouch();
return;
}

StoreTouchedObjectColliders(collider);
CheckButtonOverrides(touchedObjectScript);

Expand All @@ -305,20 +316,14 @@ private void OnTriggerStay(Collider collider)
}
}

private void OnTriggerExit(Collider collider)
{
if (touchedObjectActiveColliders.Contains(collider))
{
touchedObjectActiveColliders.Remove(collider);
}
}

private void LateUpdate()
{
if (touchedObject != null && touchedObjectActiveColliders.Count == 0)
if (touchedObject != null && (touchedObjectActiveColliders.Count == 0 || (!triggerIsColliding && !triggerWasColliding)))
{
StopTouching(touchedObject);
}
triggerWasColliding = triggerIsColliding;
triggerIsColliding = false;
}

private void CheckButtonOverrides(VRTK_InteractableObject touchedObjectScript)
Expand Down Expand Up @@ -364,7 +369,6 @@ private void StopTouching(GameObject untouched)

var untouchedObjectScript = untouched.GetComponent<VRTK_InteractableObject>();
untouchedObjectScript.StopTouching(gameObject);

if (!untouchedObjectScript.IsTouched())
{
untouchedObjectScript.ToggleHighlight(false);
Expand Down
5 changes: 5 additions & 0 deletions Assets/VRTK/Scripts/VRTK_SimplePointer.cs
Expand Up @@ -105,6 +105,11 @@ protected override void InitPointer()

base.InitPointer();

if (showPointerTip && objectInteractor)
{
objectInteractor.transform.localScale = pointerTip.transform.localScale * 1.05f;
}

SetPointerTransform(pointerLength, pointerThickness);
TogglePointer(false);
}
Expand Down
3 changes: 2 additions & 1 deletion DOCUMENTATION.md
Expand Up @@ -332,9 +332,10 @@ The play area collider does not work well with terrains as they are uneven and c

* **Controller:** The controller that will be used to toggle the pointer. If the script is being applied onto a controller then this parameter can be left blank as it will be auto populated by the controller the script is on at runtime.
* **Pointer Material:** The material to use on the rendered version of the pointer. If no material is selected then the default `WorldPointer` material will be used.
* **Pointer Visibility:** Determines when the pointer beam should be displayed.
* **Interact With Objects:** If this is checked then the pointer will be an extension of the controller and able to interact with Interactable Objects.
* **Hold Button To Activate:** If this is checked then the pointer beam will be activated on first press of the pointer alias button and will stay active until the pointer alias button is pressed again. The destination set event is emitted when the beam is deactivated on the second button press.
* **Activate Delay:** The time in seconds to delay the pointer beam being able to be active again. Useful for preventing constant teleportation.
* **Pointer Visibility:** Determines when the pointer beam should be displayed.
* **Layers To Ignore:** The layers to ignore when raycasting.

### Class Variables
Expand Down

0 comments on commit ae31ddd

Please sign in to comment.