// Object Control|Locomotion|20060
namespace VRTK
{
using UnityEngine;
///
/// Event Payload
///
/// The GameObject that is going to be affected.
/// The device that is used for the direction.
/// The axis that is being affected.
/// 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 struct ObjectControlEventArgs
{
public GameObject controlledGameObject;
public Transform directionDevice;
public Vector3 axisDirection;
public float axis;
public float deadzone;
public bool currentlyFalling;
public bool modifierActive;
}
///
/// Event Payload
///
/// this object
///
public delegate void ObjectControlEventHandler(object sender, ObjectControlEventArgs e);
///
/// Provides a base that all object control locomotions can inherit from.
///
///
/// **Script Usage:**
/// > This is an abstract class that is to be inherited to a concrete class that provides object control locomotion functionality, therefore this script should not be directly used.
///
public abstract class VRTK_ObjectControl : MonoBehaviour
{
///
/// Devices for providing direction.
///
public enum DirectionDevices
{
///
/// The headset device.
///
Headset,
///
/// The left controller device.
///
LeftController,
///
/// The right controller device.
///
RightController,
///
/// The controlled object.
///
ControlledObject
}
[Header("Control Settings")]
[Tooltip("The direction that will be moved in is the direction of this device.")]
public DirectionDevices deviceForDirection = DirectionDevices.Headset;
[Tooltip("If this is checked then whenever the axis on the attached controller is being changed, all other object control scripts of the same type on other controllers will be disabled.")]
public bool disableOtherControlsOnActive = true;
[Tooltip("If a `VRTK_BodyPhysics` script is present and this is checked, then the object control will affect the play area whilst it is falling.")]
public bool affectOnFalling = false;
[Tooltip("An optional game object to apply the object control to. If this is blank then the PlayArea will be controlled.")]
public GameObject controlOverrideObject;
[Header("Custom Settings")]
[Tooltip("The controller to read the controller events from. If this is blank then it will attempt to get a controller events script from the same GameObject.")]
public VRTK_ControllerEvents controller;
[Tooltip("An optional Body Physics script to check for potential collisions in the moving direction.")]
public VRTK_BodyPhysics bodyPhysics;
///
/// Emitted when the X Axis Changes.
///
public event ObjectControlEventHandler XAxisChanged;
///
/// Emitted when the Y Axis Changes.
///
public event ObjectControlEventHandler YAxisChanged;
protected VRTK_ControllerEvents controllerEvents;
protected VRTK_ObjectControl otherObjectControl;
protected GameObject controlledGameObject;
protected GameObject setControlOverrideObject;
protected Transform directionDevice;
protected DirectionDevices previousDeviceForDirection;
protected Vector2 currentAxis;
protected Vector2 storedAxis;
protected bool currentlyFalling = false;
protected bool modifierActive = false;
protected float controlledGameObjectPreviousY = 0f;
protected float controlledGameObjectPreviousYOffset = 0.01f;
public virtual void OnXAxisChanged(ObjectControlEventArgs e)
{
if (XAxisChanged != null)
{
XAxisChanged(this, e);
}
}
public virtual void OnYAxisChanged(ObjectControlEventArgs e)
{
if (YAxisChanged != null)
{
YAxisChanged(this, e);
}
}
protected abstract void ControlFixedUpdate();
protected abstract VRTK_ObjectControl GetOtherControl();
protected abstract bool IsInAction();
protected abstract void SetListeners(bool state);
protected virtual void Awake()
{
VRTK_SDKManager.AttemptAddBehaviourToToggleOnLoadedSetupChange(this);
}
protected virtual void OnEnable()
{
currentAxis = Vector2.zero;
storedAxis = Vector2.zero;
controllerEvents = (controller != null ? controller : GetComponentInParent());
if (!controllerEvents)
{
VRTK_Logger.Error(VRTK_Logger.GetCommonMessage(VRTK_Logger.CommonMessageKeys.REQUIRED_COMPONENT_MISSING_NOT_INJECTED, "VRTK_ObjectControl", "VRTK_ControllerEvents", "controller", "the same"));
return;
}
SetControlledObject();
bodyPhysics = (!controlOverrideObject ? (bodyPhysics != null ? bodyPhysics : FindObjectOfType()) : null);
directionDevice = GetDirectionDevice();
SetListeners(true);
otherObjectControl = GetOtherControl();
}
protected virtual void OnDisable()
{
SetListeners(false);
}
protected virtual void OnDestroy()
{
VRTK_SDKManager.AttemptRemoveBehaviourToToggleOnLoadedSetupChange(this);
}
protected virtual void Update()
{
if (controlOverrideObject != setControlOverrideObject)
{
SetControlledObject();
}
}
protected virtual void FixedUpdate()
{
CheckDirectionDevice();
CheckFalling();
ControlFixedUpdate();
}
protected virtual ObjectControlEventArgs SetEventArguements(Vector3 axisDirection, float axis, float axisDeadzone)
{
ObjectControlEventArgs e;
e.controlledGameObject = controlledGameObject;
e.directionDevice = directionDevice;
e.axisDirection = axisDirection;
e.axis = axis;
e.deadzone = axisDeadzone;
e.currentlyFalling = currentlyFalling;
e.modifierActive = modifierActive;
return e;
}
protected virtual void SetControlledObject()
{
Transform playArea = VRTK_DeviceFinder.PlayAreaTransform();
setControlOverrideObject = controlOverrideObject;
controlledGameObject = (controlOverrideObject ? controlOverrideObject : (playArea != null ? playArea.gameObject : null));
if (controlledGameObject != null)
{
controlledGameObjectPreviousY = controlledGameObject.transform.position.y;
}
}
protected virtual void CheckFalling()
{
if (bodyPhysics != null && bodyPhysics.IsFalling() && ObjectHeightChange())
{
if (!affectOnFalling)
{
if (storedAxis == Vector2.zero)
{
storedAxis = new Vector2(currentAxis.x, currentAxis.y);
}
currentAxis = Vector2.zero;
}
currentlyFalling = true;
}
if (bodyPhysics != null && !bodyPhysics.IsFalling() && currentlyFalling)
{
currentAxis = (IsInAction() ? storedAxis : Vector2.zero);
storedAxis = Vector2.zero;
currentlyFalling = false;
}
}
protected virtual bool ObjectHeightChange()
{
bool heightChanged = ((controlledGameObjectPreviousY - controlledGameObjectPreviousYOffset) > controlledGameObject.transform.position.y);
controlledGameObjectPreviousY = controlledGameObject.transform.position.y;
return heightChanged;
}
protected virtual Transform GetDirectionDevice()
{
switch (deviceForDirection)
{
case DirectionDevices.ControlledObject:
return controlledGameObject.transform;
case DirectionDevices.Headset:
return VRTK_DeviceFinder.HeadsetTransform();
case DirectionDevices.LeftController:
return VRTK_DeviceFinder.GetControllerLeftHand(true).transform;
case DirectionDevices.RightController:
return VRTK_DeviceFinder.GetControllerRightHand(true).transform;
}
return null;
}
protected virtual void CheckDirectionDevice()
{
if (previousDeviceForDirection != deviceForDirection)
{
directionDevice = GetDirectionDevice();
}
previousDeviceForDirection = deviceForDirection;
}
}
}