using System;
using HurricaneVR.Framework.ControllerInput;
using HurricaneVR.Framework.Shared;
using UnityEngine;
namespace HurricaneVR.Framework.Components
{
///
/// Handles offsettings the physics hand target based on the connected device. Also offsets the target based on grab point settings if desired.
/// To manage custom offsets please use the SetMiscPositionOffset(Vector3 position, Vector3 rotation) and ResetGrabPointOffsets() functions.
///
public class HVRControllerOffset : MonoBehaviour
{
///
/// The hand that this controller offset represents.
///
public HVRHandSide HandSide;
///
/// The transform that aim's the teleport line, it will be counter rotated when a grabbable requests the hand to rotate when held.
///
[Tooltip("The transform that aim's the teleport line, it will be counter rotated when a grabbable requests the hand to rotate when held.")]
public Transform Teleport;
///
/// Smooth lerp speed to move towards the target grab point rotation offset
///
[Tooltip("Smooth lerp speed to move towards the target grab point rotation offset")]
public float GrabPointSmoothSpeed = 8f;
private HVRDevicePoseOffset _offsets;
public Vector3 ControllerPositionOffset => _offsets != null ? _offsets.Position : Vector3.zero;
public Vector3 ControllerRotationOffset => _offsets != null ? _offsets.Rotation : Vector3.zero;
[Header("Debugging")]
[Tooltip("Enable to test live updating of the Misc offset fields.")]
public bool LiveUpdateOffsets;
[SerializeField] private Vector3 TargetGrabPointPositionOffset;
[SerializeField] private Vector3 TargetGrabPointRotationOffset;
[SerializeField] private Vector3 GrabPointPositionOffset;
[SerializeField] private Vector3 GrabPointRotationOffset;
[SerializeField] private Vector3 MiscPositionOffset;
[SerializeField] private Vector3 MiscRotationOffset;
private Quaternion _teleportStartRotation;
public bool _updatingRotation;
public bool _updatingPosition;
protected virtual void Awake()
{
if (Teleport)
{
_teleportStartRotation = Teleport.localRotation;
}
}
private void Start()
{
if (HandSide == HVRHandSide.Left)
{
if (HVRInputManager.Instance.LeftController)
ControllerConnected(HVRInputManager.Instance.LeftController);
HVRInputManager.Instance.LeftControllerConnected.AddListener(ControllerConnected);
}
else
{
if (HVRInputManager.Instance.RightController)
ControllerConnected(HVRInputManager.Instance.RightController);
HVRInputManager.Instance.RightControllerConnected.AddListener(ControllerConnected);
}
}
public void Update()
{
if (_updatingRotation)
{
GrabPointRotationOffset = Vector3.Lerp(GrabPointRotationOffset, TargetGrabPointRotationOffset, GrabPointSmoothSpeed * Time.deltaTime);
if (Vector3.Distance(GrabPointRotationOffset, TargetGrabPointRotationOffset) < .01f)
{
_updatingRotation = false;
GrabPointRotationOffset = TargetGrabPointRotationOffset;
ApplyOffsets();
}
}
if (_updatingPosition)
{
GrabPointPositionOffset = Vector3.Lerp(GrabPointPositionOffset, TargetGrabPointPositionOffset, GrabPointSmoothSpeed * Time.deltaTime);
if (Vector3.Distance(GrabPointPositionOffset, TargetGrabPointPositionOffset) < .01f)
{
_updatingPosition = false;
GrabPointPositionOffset = TargetGrabPointPositionOffset;
ApplyOffsets();
}
}
if (LiveUpdateOffsets || _updatingPosition || _updatingRotation)
{
ApplyOffsets();
}
}
public void SetMiscPositionOffset(Vector3 position, Vector3 rotation)
{
MiscPositionOffset = position;
MiscRotationOffset = rotation;
ApplyOffsets();
}
public void SetGrabPointOffsets(Vector3 position, Vector3 rotation)
{
TargetGrabPointPositionOffset = position;
TargetGrabPointRotationOffset = rotation;
_updatingRotation = true;
_updatingPosition = true;
}
public void ResetGrabPointOffsets()
{
TargetGrabPointPositionOffset = Vector3.zero;
TargetGrabPointRotationOffset = Vector3.zero;
_updatingRotation = true;
_updatingPosition = true;
}
public void ApplyOffsets()
{
var position = ControllerPositionOffset + GrabPointPositionOffset + MiscPositionOffset;
if (HandSide == HVRHandSide.Left)
{
position.x *= -1f;
}
transform.localPosition = position;
var controllerRotation = Quaternion.Euler(ControllerRotationOffset);
var grabPointRotation = Quaternion.Euler(GrabPointRotationOffset);
var miscRotation = Quaternion.Euler(MiscRotationOffset);
var finalRotation = controllerRotation * grabPointRotation * miscRotation;
var angles = finalRotation.eulerAngles;
if (HandSide == HVRHandSide.Left)
{
angles.y *= -1f;
angles.z *= -1f;
}
if (Teleport)
{
Teleport.localRotation = _teleportStartRotation * Quaternion.Inverse(grabPointRotation);
}
transform.localEulerAngles = angles;
}
private void ControllerConnected(HVRController controller)
{
var offsets = HVRInputManager.Instance.ControllerOffsets;
if (!offsets)
{
Debug.LogWarning($"HVRInputManager.ControllerOffsets are not assigned.");
return;
}
_offsets = offsets.GetDeviceOffset(controller.Side);
ApplyOffsets();
}
}
}