// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UltimateXR.Core.Components;
using UnityEngine;
namespace UltimateXR.Mechanics.CyborgAvatar
{
///
/// Component that rotates the Cyborg shoulder so that the opening points in the arm direction to leave it
/// more space.
///
public class RotateShoulder : UxrComponent
{
#region Inspector Properties/Serialized Fields
[SerializeField] private Transform _rotatingShoulder;
[SerializeField] private Vector3 _rotatingShoulderAxis;
[SerializeField] private Vector3 _rotatingShoulderOpeningAxis;
[SerializeField] private Transform _arm;
[SerializeField] private Vector3 _armLocalForward;
[SerializeField] private float _rotationDampingMin = 1.0f;
[SerializeField] private float _rotationDampingMax = 0.2f;
[SerializeField] private float _armAngleToRotateMin = 30.0f;
[SerializeField] private float _armAngleToRotateMax = 60.0f;
#endregion
#region Unity
///
/// Subscribes to events.
///
protected override void OnEnable()
{
base.OnEnable();
UxrManager.AvatarsUpdated += UxrManager_AvatarsUpdated;
}
///
/// Unsubscribes from events.
///
protected override void OnDisable()
{
base.OnDisable();
UxrManager.AvatarsUpdated -= UxrManager_AvatarsUpdated;
}
#endregion
#region Event Handling Methods
///
/// Performs the shoulder rotation.
///
private void UxrManager_AvatarsUpdated()
{
Vector3 armForward = _arm.TransformDirection(_armLocalForward);
Vector3 rotatingShoulderAxis = _rotatingShoulder.TransformDirection(_rotatingShoulderAxis);
float armAngle = Vector3.Angle(armForward, rotatingShoulderAxis);
if (armAngle > _armAngleToRotateMin)
{
float t = Mathf.Clamp01((armAngle - _armAngleToRotateMin) / (_armAngleToRotateMax - _armAngleToRotateMin));
Vector3 openingCurrent = _rotatingShoulder.TransformDirection(_rotatingShoulderOpeningAxis);
Vector3 openingTarget = Vector3.ProjectOnPlane(armForward, rotatingShoulderAxis);
float currentAngle = Vector3.SignedAngle(openingCurrent, openingTarget, rotatingShoulderAxis);
float dampedAngle = Mathf.SmoothDampAngle(currentAngle, 0.0f, ref _currentAngleVelocity, Mathf.Lerp(_rotationDampingMin, _rotationDampingMax, t));
_rotatingShoulder.Rotate(_rotatingShoulderAxis, currentAngle - dampedAngle, Space.Self);
}
else
{
_currentAngleVelocity = 0.0f;
}
}
#endregion
#region Private Types & Data
private float _currentAngleVelocity;
#endregion
}
}