diff --git a/Assets/VRTK/Scripts/Locomotion/TouchpadControlActions/VRTK_SnapRotateTouchpadControlAction.cs b/Assets/VRTK/Scripts/Locomotion/TouchpadControlActions/VRTK_SnapRotateTouchpadControlAction.cs new file mode 100644 index 000000000..1181ec31c --- /dev/null +++ b/Assets/VRTK/Scripts/Locomotion/TouchpadControlActions/VRTK_SnapRotateTouchpadControlAction.cs @@ -0,0 +1,115 @@ +// Snap Rotate Touchpad Control Action|TouchpadControlActions|25030 +namespace VRTK +{ + using UnityEngine; + + /// + /// The Snap Rotate Touchpad Control Action script is used to snap rotate the controlled GameObject around the up vector when changing the touchpad axis. + /// + /// + /// The effect is a immediate snap rotation to quickly face in a new direction. + /// + public class VRTK_SnapRotateTouchpadControlAction : VRTK_BaseTouchpadControlAction + { + [Tooltip("The angle to rotate for each snap.")] + public float anglePerSnap = 30f; + [Tooltip("The snap angle multiplier to be applied when the modifier button is pressed.")] + public float angleMultiplier = 1.5f; + [Tooltip("The amount of time required to pass before another snap rotation can be carried out.")] + public float snapDelay = 0.5f; + [Tooltip("The speed for the headset to fade out and back in. Having a blink between rotations can reduce nausia.")] + public float blinkTransitionSpeed = 0.6f; + + private Collider centerCollider; + private Transform controlledTransform; + private Transform playArea; + private float snapDelayTimer = 0f; + + /// + /// The ProcessFixedUpdate method is run for every FixedUpdate on the Touchpad Control script. + /// + /// The GameObject that is going to be affected. + /// The device that is used for the direction. + /// The axis that is being affected from the touchpad. + /// The value of the current touchpad touch point based across the axis direction. + /// The value of the deadzone based across the axis direction. + /// Whether the controlled GameObject is currently falling. + /// Whether the modifier button is pressed. + public override void ProcessFixedUpdate(GameObject controlledGameObject, Transform directionDevice, Vector3 axisDirection, float axis, float deadzone, bool currentlyFalling, bool modifierActive) + { + if (snapDelayTimer < Time.timeSinceLevelLoad) + { + float angle = Rotate(axis, modifierActive); + if (angle != 0f) + { + Blink(); + RotateAroundPlayer(controlledGameObject, angle); + } + } + } + + protected virtual void OnEnable() + { + playArea = VRTK_DeviceFinder.PlayAreaTransform(); + } + + protected virtual void RotateAroundPlayer(GameObject controlledGameObject, float angle) + { + Vector3 objectCenter = GetObjectCenter(controlledGameObject.transform); + Vector3 objectPosition = controlledGameObject.transform.TransformPoint(objectCenter); + controlledGameObject.transform.Rotate(Vector3.up, angle); + objectPosition -= controlledGameObject.transform.TransformPoint(objectCenter); + controlledGameObject.transform.position += objectPosition; + } + + protected virtual float Rotate(float axis, bool modifierActive) + { + snapDelayTimer = Time.timeSinceLevelLoad + snapDelay; + int axisDirection = 0; + if (axis < 0) + { + axisDirection = -1; + } + else if (axis > 0) + { + axisDirection = 1; + } + return (anglePerSnap * (modifierActive ? angleMultiplier : 1)) * axisDirection; + } + + protected virtual void Blink() + { + if (blinkTransitionSpeed > 0f) + { + VRTK_SDK_Bridge.HeadsetFade(Color.black, 0); + Invoke("ReleaseBlink", 0.01f); + } + } + + protected virtual void ReleaseBlink() + { + VRTK_SDK_Bridge.HeadsetFade(Color.clear, blinkTransitionSpeed); + } + + protected virtual Vector3 GetObjectCenter(Transform checkObject) + { + if (centerCollider == null || checkObject != controlledTransform) + { + controlledTransform = checkObject; + + if (checkObject == playArea) + { + CapsuleCollider playAreaCollider = playArea.GetComponent(); + centerCollider = playAreaCollider; + return playAreaCollider.center; + } + else + { + centerCollider = checkObject.GetComponent(); + } + } + + return Vector3.zero; + } + } +} \ No newline at end of file diff --git a/Assets/VRTK/Scripts/Locomotion/TouchpadControlActions/VRTK_SnapRotateTouchpadControlAction.cs.meta b/Assets/VRTK/Scripts/Locomotion/TouchpadControlActions/VRTK_SnapRotateTouchpadControlAction.cs.meta new file mode 100644 index 000000000..a07e9bff0 --- /dev/null +++ b/Assets/VRTK/Scripts/Locomotion/TouchpadControlActions/VRTK_SnapRotateTouchpadControlAction.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 11c28f695996f534b8a8e4935ae2a651 +timeCreated: 1485957999 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/VRTK/Scripts/Locomotion/VRTK_TouchpadControl.cs b/Assets/VRTK/Scripts/Locomotion/VRTK_TouchpadControl.cs index d2fa7dd27..5b7ccdd66 100644 --- a/Assets/VRTK/Scripts/Locomotion/VRTK_TouchpadControl.cs +++ b/Assets/VRTK/Scripts/Locomotion/VRTK_TouchpadControl.cs @@ -98,17 +98,22 @@ protected virtual void FixedUpdate() CheckDirectionDevice(); CheckFalling(); ModifierButtonActive(); - if (xAxisActionScript && xAxisActionScript.enabled) + if (xAxisActionScript && xAxisActionScript.enabled && OutsideDeadzone(touchpadAxis.x, axisDeadzone.x)) { xAxisActionScript.ProcessFixedUpdate(controlledGameObject, directionDevice, directionDevice.right, touchpadAxis.x, axisDeadzone.x, currentlyFalling, modifierActive); } - if (yAxisActionScript && yAxisActionScript.enabled) + if (yAxisActionScript && yAxisActionScript.enabled && OutsideDeadzone(touchpadAxis.y, axisDeadzone.y)) { yAxisActionScript.ProcessFixedUpdate(controlledGameObject, directionDevice, directionDevice.forward, touchpadAxis.y, axisDeadzone.y, currentlyFalling, modifierActive); } } + protected virtual bool OutsideDeadzone(float axisValue, float deadzoneThreshold) + { + return (axisValue > deadzoneThreshold || axisValue < -deadzoneThreshold); + } + protected virtual void CheckSetupControlAction() { if (xAxisActionScript && yAxisActionScript && xAxisActionScript.GetInstanceID() == yAxisActionScript.GetInstanceID()) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index a61df6343..1b74bce23 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -1281,6 +1281,7 @@ This directory contains scripts that are used to provide different actions when * [Base Touchpad Control Action](#base-touchpad-control-action-vrtk_basetouchpadcontrolaction) * [Slide Touchpad Control Action](#slide-touchpad-control-action-vrtk_slidetouchpadcontrolaction) * [Rotate Touchpad Control Action](#rotate-touchpad-control-action-vrtk_rotatetouchpadcontrolaction) + * [Snap Rotate Touchpad Control Action](#snap-rotate-touchpad-control-action-vrtk_snaprotatetouchpadcontrolaction) --- @@ -1393,6 +1394,43 @@ The ProcessFixedUpdate method is run for every FixedUpdate on the Touchpad Contr --- +## Snap Rotate Touchpad Control Action (VRTK_SnapRotateTouchpadControlAction) + > extends [VRTK_BaseTouchpadControlAction](#base-touchpad-control-action-vrtk_basetouchpadcontrolaction) + +### Overview + +The Snap Rotate Touchpad Control Action script is used to snap rotate the controlled GameObject around the up vector when changing the touchpad axis. + +The effect is a immediate snap rotation to quickly face in a new direction. + +### Inspector Parameters + + * **Angle Per Snap:** The angle to rotate for each snap. + * **Angle Multiplier:** The snap angle multiplier to be applied when the modifier button is pressed. + * **Snap Delay:** The amount of time required to pass before another snap rotation can be carried out. + * **Blink Transition Speed:** The speed for the headset to fade out and back in. Having a blink between rotations can reduce nausia. + +### Class Methods + +#### ProcessFixedUpdate/7 + + > `public override void ProcessFixedUpdate(GameObject controlledGameObject, Transform directionDevice, Vector3 axisDirection, float axis, float deadzone, bool currentlyFalling, bool modifierActive)` + + * Parameters + * `GameObject controlledGameObject` - The GameObject that is going to be affected. + * `Transform directionDevice` - The device that is used for the direction. + * `Vector3 axisDirection` - The axis that is being affected from the touchpad. + * `float axis` - The value of the current touchpad touch point based across the axis direction. + * `float deadzone` - The value of the deadzone based across the axis direction. + * `bool currentlyFalling` - Whether the controlled GameObject is currently falling. + * `bool modifierActive` - Whether the modifier button is pressed. + * Returns + * _none_ + +The ProcessFixedUpdate method is run for every FixedUpdate on the Touchpad Control script. + +--- + # Interactions (VRTK/Scripts/Interactions) A collection of scripts that provide the ability to interact with game objects with the controllers.