// Touchpad Walking|Locomotion|20090
namespace VRTK
{
using UnityEngine;
using System;
///
/// The ability to move the play area around the game world by sliding a finger over the touchpad is achieved using this script.
///
///
/// The Touchpad Walking script adds a rigidbody and a box collider to the user's position to prevent them from walking through other collidable game objects.
///
///
/// `VRTK/Examples/017_CameraRig_TouchpadWalking` has a collection of walls and slopes that can be traversed by the user with the touchpad. There is also an area that can only be traversed if the user is crouching.
///
[Obsolete("`VRTK_TouchpadWalking` has been replaced with `VRTK_TouchpadControl`. This script will be removed in a future version of VRTK.")]
public class VRTK_TouchpadWalking : MonoBehaviour
{
[Tooltip("If this is checked then the left controller touchpad will be enabled to move the play area.")]
public bool leftController = true;
[Tooltip("If this is checked then the right controller touchpad will be enabled to move the play area.")]
public bool rightController = true;
[Tooltip("The maximum speed the play area will be moved when the touchpad is being touched at the extremes of the axis. If a lower part of the touchpad axis is touched (nearer the centre) then the walk speed is slower.")]
public float maxWalkSpeed = 3f;
[Tooltip("The speed in which the play area slows down to a complete stop when the user is no longer touching the touchpad. This deceleration effect can ease any motion sickness that may be suffered.")]
public float deceleration = 0.1f;
[Tooltip("If a button is defined then movement will only occur when the specified button is being held down and the touchpad axis changes.")]
public VRTK_ControllerEvents.ButtonAlias moveOnButtonPress = VRTK_ControllerEvents.ButtonAlias.Undefined;
[Tooltip("The direction that will be moved in is the direction of this device.")]
public VRTK_DeviceFinder.Devices deviceForDirection = VRTK_DeviceFinder.Devices.Headset;
[Tooltip("If the defined speed multiplier button is pressed then the current movement speed will be multiplied by the `Speed Multiplier` value.")]
public VRTK_ControllerEvents.ButtonAlias speedMultiplierButton = VRTK_ControllerEvents.ButtonAlias.Undefined;
[Tooltip("The amount to mmultiply the movement speed by if the `Speed Multiplier Button` is pressed.")]
public float speedMultiplier = 1f;
private GameObject controllerLeftHand;
private GameObject controllerRightHand;
private Transform playArea;
private Vector2 touchAxis;
private float movementSpeed;
private float strafeSpeed;
private bool leftSubscribed;
private bool rightSubscribed;
private ControllerInteractionEventHandler touchpadAxisChanged;
private ControllerInteractionEventHandler touchpadUntouched;
private bool multiplySpeed;
private VRTK_ControllerEvents controllerEvents;
private VRTK_BodyPhysics bodyPhysics;
private bool wasFalling;
private bool previousLeftControllerState;
private bool previousRightControllerState;
protected virtual void Awake()
{
VRTK_SDKManager.instance.AddBehaviourToToggleOnLoadedSetupChange(this);
}
protected virtual void OnEnable()
{
touchpadAxisChanged = new ControllerInteractionEventHandler(DoTouchpadAxisChanged);
touchpadUntouched = new ControllerInteractionEventHandler(DoTouchpadTouchEnd);
playArea = VRTK_DeviceFinder.PlayAreaTransform();
controllerLeftHand = VRTK_DeviceFinder.GetControllerLeftHand();
controllerRightHand = VRTK_DeviceFinder.GetControllerRightHand();
if (!playArea)
{
VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.SDK_OBJECT_NOT_FOUND, "PlayArea", "Boundaries SDK"));
}
VRTK_PlayerObject.SetPlayerObject(gameObject, VRTK_PlayerObject.ObjectTypes.CameraRig);
SetControllerListeners(controllerLeftHand, leftController, ref leftSubscribed);
SetControllerListeners(controllerRightHand, rightController, ref rightSubscribed);
bodyPhysics = GetComponent();
movementSpeed = 0f;
strafeSpeed = 0f;
multiplySpeed = false;
}
protected virtual void OnDisable()
{
SetControllerListeners(controllerLeftHand, leftController, ref leftSubscribed, true);
SetControllerListeners(controllerRightHand, rightController, ref rightSubscribed, true);
bodyPhysics = null;
}
protected virtual void OnDestroy()
{
VRTK_SDKManager.instance.RemoveBehaviourToToggleOnLoadedSetupChange(this);
}
protected virtual void Update()
{
multiplySpeed = (controllerEvents && speedMultiplierButton != VRTK_ControllerEvents.ButtonAlias.Undefined && controllerEvents.IsButtonPressed(speedMultiplierButton));
CheckControllerState(controllerLeftHand, leftController, ref leftSubscribed, ref previousLeftControllerState);
CheckControllerState(controllerRightHand, rightController, ref rightSubscribed, ref previousRightControllerState);
}
protected virtual void FixedUpdate()
{
HandleFalling();
CalculateSpeed(ref movementSpeed, touchAxis.y);
CalculateSpeed(ref strafeSpeed, touchAxis.x);
Move();
}
protected virtual void HandleFalling()
{
if (bodyPhysics && bodyPhysics.IsFalling())
{
touchAxis = Vector2.zero;
wasFalling = true;
}
if (bodyPhysics && !bodyPhysics.IsFalling() && wasFalling)
{
touchAxis = Vector2.zero;
wasFalling = false;
strafeSpeed = 0f;
movementSpeed = 0f;
}
}
protected virtual void CheckControllerState(GameObject controller, bool controllerState, ref bool subscribedState, ref bool previousState)
{
if (controllerState != previousState)
{
SetControllerListeners(controller, controllerState, ref subscribedState);
}
previousState = controllerState;
}
private void DoTouchpadAxisChanged(object sender, ControllerInteractionEventArgs e)
{
controllerEvents = (VRTK_ControllerEvents)sender;
if (moveOnButtonPress != VRTK_ControllerEvents.ButtonAlias.Undefined && !controllerEvents.IsButtonPressed(moveOnButtonPress))
{
touchAxis = Vector2.zero;
controllerEvents = null;
return;
}
touchAxis = e.touchpadAxis;
}
private void DoTouchpadTouchEnd(object sender, ControllerInteractionEventArgs e)
{
touchAxis = Vector2.zero;
controllerEvents = null;
}
private void CalculateSpeed(ref float speed, float inputValue)
{
if (inputValue != 0f)
{
speed = (maxWalkSpeed * inputValue);
speed = (multiplySpeed ? speed * speedMultiplier : speed);
}
else
{
Decelerate(ref speed);
}
}
private void Decelerate(ref float speed)
{
if (speed > 0)
{
speed -= Mathf.Lerp(deceleration, maxWalkSpeed, 0f);
}
else if (speed < 0)
{
speed += Mathf.Lerp(deceleration, -maxWalkSpeed, 0f);
}
else
{
speed = 0;
}
float deadzone = 0.1f;
if (speed < deadzone && speed > -deadzone)
{
speed = 0;
}
}
private void Move()
{
var deviceDirector = VRTK_DeviceFinder.DeviceTransform(deviceForDirection);
if (deviceDirector)
{
var movement = deviceDirector.forward * movementSpeed * Time.deltaTime;
var strafe = deviceDirector.right * strafeSpeed * Time.deltaTime;
float fixY = playArea.position.y;
playArea.position += (movement + strafe);
playArea.position = new Vector3(playArea.position.x, fixY, playArea.position.z);
}
}
private void SetControllerListeners(GameObject controller, bool controllerState, ref bool subscribedState, bool forceDisabled = false)
{
if (controller)
{
bool toggleState = (forceDisabled ? false : controllerState);
ToggleControllerListeners(controller, toggleState, ref subscribedState);
}
}
private void ToggleControllerListeners(GameObject controller, bool toggle, ref bool subscribed)
{
var controllerEvent = controller.GetComponent();
if (controllerEvent && toggle && !subscribed)
{
controllerEvent.TouchpadAxisChanged += touchpadAxisChanged;
controllerEvent.TouchpadTouchEnd += touchpadUntouched;
subscribed = true;
}
else if (controllerEvent && !toggle && subscribed)
{
controllerEvent.TouchpadAxisChanged -= touchpadAxisChanged;
controllerEvent.TouchpadTouchEnd -= touchpadUntouched;
touchAxis = Vector2.zero;
subscribed = false;
}
}
}
}