Files
dungeons/Assets/UltimateXR/Runtime/Scripts/Avatar/Controllers/UxrAvatarController.cs
2024-08-06 21:58:35 +02:00

216 lines
8.4 KiB
C#

// --------------------------------------------------------------------------------------------------------------------
// <copyright file="UxrAvatarController.cs" company="VRMADA">
// Copyright (c) VRMADA, All rights reserved.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UltimateXR.Core.Components.Composite;
using UltimateXR.Devices;
using UltimateXR.Locomotion;
using UltimateXR.Manipulation;
using UnityEngine;
namespace UltimateXR.Avatar.Controllers
{
/// <summary>
/// Base class for <see cref="UxrAvatar" /> controllers. <see cref="UxrAvatarController" /> components are responsible
/// for updating the avatar. UltimateXR provides the <see cref="UxrStandardAvatarController" /> which has great
/// functionality. For flexibility and scalability, different avatar controllers can be created if required.
/// </summary>
/// <remarks>
/// <see cref="UxrAvatarController" /> components require the <see cref="UxrAvatar" /> component in the same
/// <see cref="GameObject" /> or any of its parents. Only one <see cref="UxrAvatarController" /> component type can
/// be active at the same time.
/// </remarks>
[DisallowMultipleComponent]
[RequireComponent(typeof(UxrAvatar))]
public abstract class UxrAvatarController : UxrAvatarComponent<UxrAvatarController>, IUxrAvatarControllerUpdater
{
#region Inspector Properties/Serialized Fields
[SerializeField] private bool _allowHandTracking = true;
#endregion
#region Public Types & Data
/// <summary>
/// Gets whether the avatar controller finished startup and can be updated.
/// </summary>
public abstract bool Initialized { get; }
/// <summary>
/// Gets whether the avatar is using smooth locomotion. Smooth locomotion updates the position every
/// frame, whereas non-smooth locomotion will move the avatar from one place to another in "jumps".
/// </summary>
public abstract bool UsesSmoothLocomotion { get; }
/// <summary>
/// Gets or sets whether hand tracking is used when available.
/// </summary>
public bool AllowHandTracking
{
get => _allowHandTracking;
set => _allowHandTracking = value;
}
#endregion
#region Explicit IUxrAvatarControllerUpdater
/// <inheritdoc />
void IUxrAvatarControllerUpdater.UpdateAvatar()
{
// Will call the protected method, which is allowed to be overriden by child classes while
// hiding the functionality so that it is handled by the framework in the correct order.
UpdateAvatar();
}
/// <inheritdoc />
void IUxrAvatarControllerUpdater.UpdateAvatarUsingTrackingDevices()
{
UpdateAvatarUsingTrackingDevices();
}
/// <inheritdoc />
void IUxrAvatarControllerUpdater.UpdateAvatarManipulation()
{
// Will call the protected method, which is allowed to be overriden by child classes while
// hiding the functionality so that it is handled by the framework in the correct order.
UpdateAvatarManipulation();
}
/// <inheritdoc />
void IUxrAvatarControllerUpdater.UpdateAvatarAnimation()
{
// Will call the protected method, which is allowed to be overriden by child classes while
// hiding the functionality so that it is handled by the framework in the correct order.
UpdateAvatarAnimation();
}
/// <inheritdoc />
void IUxrAvatarControllerUpdater.UpdateAvatarPostProcess()
{
// Will call the protected method, which is allowed to be overriden by child classes while
// hiding the functionality so that it is handled by the framework in the correct order.
UpdateAvatarPostProcess();
}
#endregion
#region Public Methods
/// <summary>
/// Gets if the hand is available to interact with UI elements, such as pressing buttons. This is used by the UI
/// interaction system to ignore the hand for these events.
/// For example, when the hand is holding an object it could be desirable to not let it interact inadvertently with any
/// user interface.
/// </summary>
/// <param name="handSide">Which hand to check</param>
/// <returns>Whether the given handed can interact with user interfaces</returns>
public virtual bool CanHandInteractWithUI(UxrHandSide handSide)
{
return true;
}
#endregion
#region Protected Methods
/// <summary>
/// Updates the avatar for the given frame. This is normally in charge of updating input devices, tracking devices and
/// locomotion.
/// Animation is left for a later stage (<see cref="UpdateAvatarAnimation" />), to make sure it is performed in the
/// right order right after Unity has updated the built-in animation components such as <see cref="Animator" />.
/// </summary>
protected virtual void UpdateAvatar()
{
}
/// <summary>
/// Executes the avatar manipulation actions based on user input.
/// </summary>
protected virtual void UpdateAvatarManipulation()
{
}
/// <summary>
/// Updates the animation and rig transforms for the given frame. It is performed in a later stage than
/// <see cref="UpdateAvatar" /> to make sure the transforms override the transforms that Unity may have updated using
/// built-in components such as <see cref="Animator" />.
/// </summary>
protected virtual void UpdateAvatarAnimation()
{
}
/// <summary>
/// Updates the avatar for a given frame, at the end of all stages and UltimateXR manager updates such as the
/// <see cref="UxrGrabManager" />. It can be used to perform operations that require to be executed at the end of all
/// stages, such as Inverse Kinematics.
/// </summary>
protected virtual void UpdateAvatarPostProcess()
{
}
/// <summary>
/// Updates the currently enabled input devices.
/// </summary>
protected void UpdateInputDevice()
{
foreach (UxrControllerInput controllerInput in Avatar.EnabledControllerInputs)
{
// Call method using internal interface
((IUxrControllerInputUpdater)controllerInput).UpdateInput();
}
// Refresh render mode
Avatar.RenderMode = Avatar.RenderMode;
}
/// <summary>
/// Updates the tracking devices.
/// </summary>
protected void UpdateTrackingDevices()
{
foreach (UxrTrackingDevice trackingDevice in Avatar.TrackingDevices)
{
if (trackingDevice && trackingDevice.enabled)
{
// Update tracking by calling internal interface
((IUxrTrackingUpdater)trackingDevice).UpdateSensors();
}
}
}
/// <summary>
/// Updates the avatar using the current tracking data.
/// </summary>
protected void UpdateAvatarUsingTrackingDevices()
{
foreach (UxrTrackingDevice trackingDevice in Avatar.TrackingDevices)
{
if (trackingDevice && trackingDevice.enabled)
{
// Update avatar by calling internal interface
((IUxrTrackingUpdater)trackingDevice).UpdateAvatar();
}
}
}
/// <summary>
/// Updates the enabled locomotion components in the avatar.
/// </summary>
protected void UpdateLocomotion()
{
foreach (UxrLocomotion locomotion in UxrLocomotion.GetComponents<UxrLocomotion>(Avatar))
{
if (locomotion.gameObject.activeInHierarchy && locomotion.enabled)
{
((IUxrLocomotionUpdater)locomotion).UpdateLocomotion();
}
}
}
#endregion
}
}