Files
dungeons/Assets/UltimateXR/Runtime/Scripts/Animation/Transforms/UxrLookAtLocalAvatar.cs
2024-08-06 21:58:35 +02:00

233 lines
8.4 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrLookAtLocalAvatar.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Avatar;
using UltimateXR.Core;
using UltimateXR.Core.Components;
using UltimateXR.Extensions.Unity;
using UnityEngine;
namespace UltimateXR.Animation.Transforms
{
/// <summary>
/// Component that allows to continuously orientate an object looking at the local avatar camera.
/// If there is no local avatar, it will use the first enabled camera.
/// </summary>
public class UxrLookAtLocalAvatar : UxrComponent
{
#region Inspector Properties/Serialized Fields
[SerializeField] private bool _allowRotateAroundY = true;
[SerializeField] private bool _allowRotateAroundX = true;
[SerializeField] private bool _invertedForwardAxis;
[SerializeField] private bool _onlyOnce;
#endregion
#region Public Types & Data
/// <summary>
/// Should the lookAt alter the rotation around the vertical axis?
/// </summary>
public bool AllowRotateAroundVerticalAxis
{
get => _allowRotateAroundY;
set => _allowRotateAroundY = value;
}
/// <summary>
/// Should the lookAt alter the rotation around the horizontal axis?
/// </summary>
public bool AllowRotateAroundHorizontalAxis
{
get => _allowRotateAroundX;
set => _allowRotateAroundX = value;
}
/// <summary>
/// If true, the target's forward axis will try to point at the opposite direction where the
/// avatar is. By default this is false, meaning the forward vector will try to point at
/// the avatar.
/// </summary>
public bool InvertedForwardAxis
{
get => _invertedForwardAxis;
set => _invertedForwardAxis = value;
}
/// <summary>
/// If true, will only perform the lookat the first time it is called. Useful for explosions
/// or similar effects in VR.
/// </summary>
public bool OnlyOnce
{
get => _onlyOnce;
set => _onlyOnce = true;
}
#endregion
#region Public Methods
/// <summary>
/// Makes an object look at the local avatar continuously over time.
/// </summary>
/// <param name="gameObject">The object that will look at the local avatar</param>
/// <param name="allowRotateAroundVerticalAxis">
/// Should the lookAt alter the rotation around the vertical axis?
/// </param>
/// <param name="allowRotateAroundHorizontalAxis">
/// Should the lookAt alter the rotation around the horizontal axis?
/// </param>
/// <param name="invertedForwardAxis">
/// If true, the target's forward axis will try to point at the opposite direction where the avatar is. By default this
/// is false, meaning the forward vector will try to point at the avatar
/// </param>
/// <returns>The look-at component</returns>
public UxrLookAtLocalAvatar MakeLookAt(GameObject gameObject, bool allowRotateAroundVerticalAxis, bool allowRotateAroundHorizontalAxis, bool invertedForwardAxis)
{
UxrLookAtLocalAvatar lookAtComponent = gameObject.GetOrAddComponent<UxrLookAtLocalAvatar>();
lookAtComponent._allowRotateAroundY = allowRotateAroundVerticalAxis;
lookAtComponent._allowRotateAroundX = allowRotateAroundHorizontalAxis;
lookAtComponent._invertedForwardAxis = invertedForwardAxis;
return lookAtComponent;
}
/// <summary>
/// Makes an object look at the local avatar a single time.
/// </summary>
/// <param name="gameObject">The object that will look at the local avatar</param>
/// <param name="allowRotateAroundVerticalAxis">
/// Should the lookAt alter the rotation around the vertical axis?
/// </param>
/// <param name="allowRotateAroundHorizontalAxis">
/// Should the lookAt alter the rotation around the horizontal axis?
/// </param>
/// <param name="invertedForwardAxis">
/// If true, the target's forward axis will try to point at the opposite direction where the avatar is. By default this
/// is false, meaning the forward vector will try to point at the avatar
/// </param>
public static void MakeLookAtOnlyOnce(GameObject gameObject, bool allowRotateAroundVerticalAxis, bool allowRotateAroundHorizontalAxis, bool invertedForwardAxis)
{
PerformLookAt(gameObject.transform, allowRotateAroundVerticalAxis, allowRotateAroundHorizontalAxis, invertedForwardAxis);
}
/// <summary>
/// Removes an UxrLookAtLocalAvatar component if it exists.
/// </summary>
/// <param name="gameObject">The GameObject to remove the component from</param>
public static void RemoveLookAt(GameObject gameObject)
{
if (gameObject)
{
UxrLookAtLocalAvatar lookAtComponent = gameObject.GetComponent<UxrLookAtLocalAvatar>();
if (lookAtComponent)
{
Destroy(lookAtComponent);
}
}
}
#endregion
#region Unity
/// <summary>
/// Subscribes to events.
/// </summary>
protected override void OnEnable()
{
base.OnEnable();
UxrManager.AvatarsUpdated += UxrManager_AvatarsUpdated;
}
/// <summary>
/// Unsubscribes from events.
/// </summary>
protected override void OnDisable()
{
base.OnDisable();
UxrManager.AvatarsUpdated -= UxrManager_AvatarsUpdated;
}
#endregion
#region Event Handling Methods
/// <summary>
/// Called after avatars are updated. Performs look at.
/// </summary>
private void UxrManager_AvatarsUpdated()
{
if (_repeat)
{
PerformLookAt(transform, _allowRotateAroundY, _allowRotateAroundX, _invertedForwardAxis);
if (_onlyOnce)
{
_repeat = false;
}
}
}
#endregion
#region Private Methods
/// <summary>
/// Performs look at.
/// </summary>
/// <param name="transform">The Transform that will look at the local avatar</param>
/// <param name="allowRotateAroundVerticalAxis">
/// Should the lookAt alter the rotation around the vertical axis?
/// </param>
/// <param name="allowRotateAroundHorizontalAxis">
/// Should the lookAt alter the rotation around the horizontal axis?
/// </param>
/// <param name="invertedForwardAxis">
/// If true, the target's forward axis will try to point at the opposite direction where the avatar is. By default this
/// is false, meaning the forward vector will try to point at the avatar
/// </param>
private static void PerformLookAt(Transform transform, bool allowRotateAroundVerticalAxis, bool allowRotateAroundHorizontalAxis, bool invertedForwardAxis)
{
Camera currentCamera = UxrAvatar.LocalOrFirstEnabledCamera;
if (currentCamera == null)
{
return;
}
Vector3 lookAt = currentCamera.transform.position - transform.position;
if (allowRotateAroundHorizontalAxis == false)
{
lookAt.y = 0.0f;
}
if (allowRotateAroundVerticalAxis == false)
{
lookAt = Vector3.ProjectOnPlane(lookAt, transform.right);
}
if (lookAt != Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(invertedForwardAxis ? -lookAt : lookAt);
}
}
#endregion
#region Private Types & Data
private bool _repeat = true;
#endregion
}
}