// Object Control|Locomotion|20060
|
|
namespace VRTK
|
|
{
|
|
using UnityEngine;
|
|
|
|
/// <summary>
|
|
/// Event Payload
|
|
/// </summary>
|
|
/// <param name="controlledGameObject">The GameObject that is going to be affected.</param>
|
|
/// <param name="directionDevice">The device that is used for the direction.</param>
|
|
/// <param name="axisDirection">The axis that is being affected.</param>
|
|
/// <param name="axis">The value of the current touchpad touch point based across the axis direction.</param>
|
|
/// <param name="deadzone">The value of the deadzone based across the axis direction.</param>
|
|
/// <param name="currentlyFalling">Whether the controlled GameObject is currently falling.</param>
|
|
/// <param name="modifierActive">Whether the modifier button is pressed.</param>
|
|
public struct ObjectControlEventArgs
|
|
{
|
|
public GameObject controlledGameObject;
|
|
public Transform directionDevice;
|
|
public Vector3 axisDirection;
|
|
public float axis;
|
|
public float deadzone;
|
|
public bool currentlyFalling;
|
|
public bool modifierActive;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Event Payload
|
|
/// </summary>
|
|
/// <param name="sender">this object</param>
|
|
/// <param name="e"><see cref="ObjectControlEventArgs"/></param>
|
|
public delegate void ObjectControlEventHandler(object sender, ObjectControlEventArgs e);
|
|
|
|
/// <summary>
|
|
/// Provides a base that all object control locomotions can inherit from.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// **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.
|
|
/// </remarks>
|
|
public abstract class VRTK_ObjectControl : MonoBehaviour
|
|
{
|
|
/// <summary>
|
|
/// Devices for providing direction.
|
|
/// </summary>
|
|
public enum DirectionDevices
|
|
{
|
|
/// <summary>
|
|
/// The headset device.
|
|
/// </summary>
|
|
Headset,
|
|
/// <summary>
|
|
/// The left controller device.
|
|
/// </summary>
|
|
LeftController,
|
|
/// <summary>
|
|
/// The right controller device.
|
|
/// </summary>
|
|
RightController,
|
|
/// <summary>
|
|
/// The controlled object.
|
|
/// </summary>
|
|
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;
|
|
|
|
/// <summary>
|
|
/// Emitted when the X Axis Changes.
|
|
/// </summary>
|
|
public event ObjectControlEventHandler XAxisChanged;
|
|
|
|
/// <summary>
|
|
/// Emitted when the Y Axis Changes.
|
|
/// </summary>
|
|
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<VRTK_ControllerEvents>());
|
|
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<VRTK_BodyPhysics>()) : 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;
|
|
}
|
|
}
|
|
}
|