// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using UltimateXR.Core;
using UltimateXR.Core.Components.Composite;
using UltimateXR.Devices;
using UltimateXR.Locomotion;
using UltimateXR.Manipulation;
using UnityEngine;
namespace UltimateXR.Avatar.Controllers
{
///
/// Base class for controllers. components are responsible
/// for updating the avatar. UltimateXR provides the which has great
/// functionality. For flexibility and scalability, different avatar controllers can be created if required.
///
///
/// components require the component in the same
/// or any of its parents. Only one component type can
/// be active at the same time.
///
[DisallowMultipleComponent]
[RequireComponent(typeof(UxrAvatar))]
public abstract class UxrAvatarController : UxrAvatarComponent, IUxrAvatarControllerUpdater
{
#region Inspector Properties/Serialized Fields
[SerializeField] private bool _allowHandTracking = true;
#endregion
#region Public Types & Data
///
/// Gets whether the avatar controller finished startup and can be updated.
///
public abstract bool Initialized { get; }
///
/// 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".
///
public abstract bool UsesSmoothLocomotion { get; }
///
/// Gets or sets whether hand tracking is used when available.
///
public bool AllowHandTracking
{
get => _allowHandTracking;
set => _allowHandTracking = value;
}
#endregion
#region Explicit IUxrAvatarControllerUpdater
///
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();
}
///
void IUxrAvatarControllerUpdater.UpdateAvatarUsingTrackingDevices()
{
UpdateAvatarUsingTrackingDevices();
}
///
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();
}
///
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();
}
///
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
///
/// 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.
///
/// Which hand to check
/// Whether the given handed can interact with user interfaces
public virtual bool CanHandInteractWithUI(UxrHandSide handSide)
{
return true;
}
#endregion
#region Protected Methods
///
/// 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 (), to make sure it is performed in the
/// right order right after Unity has updated the built-in animation components such as .
///
protected virtual void UpdateAvatar()
{
}
///
/// Executes the avatar manipulation actions based on user input.
///
protected virtual void UpdateAvatarManipulation()
{
}
///
/// Updates the animation and rig transforms for the given frame. It is performed in a later stage than
/// to make sure the transforms override the transforms that Unity may have updated using
/// built-in components such as .
///
protected virtual void UpdateAvatarAnimation()
{
}
///
/// Updates the avatar for a given frame, at the end of all stages and UltimateXR manager updates such as the
/// . It can be used to perform operations that require to be executed at the end of all
/// stages, such as Inverse Kinematics.
///
protected virtual void UpdateAvatarPostProcess()
{
}
///
/// Updates the currently enabled input devices.
///
protected void UpdateInputDevice()
{
foreach (UxrControllerInput controllerInput in Avatar.EnabledControllerInputs)
{
// Call method using internal interface
((IUxrControllerInputUpdater)controllerInput).UpdateInput();
}
// Refresh render mode
Avatar.RenderMode = Avatar.RenderMode;
}
///
/// Updates the tracking devices.
///
protected void UpdateTrackingDevices()
{
foreach (UxrTrackingDevice trackingDevice in Avatar.TrackingDevices)
{
if (trackingDevice && trackingDevice.enabled)
{
// Update tracking by calling internal interface
((IUxrTrackingUpdater)trackingDevice).UpdateSensors();
}
}
}
///
/// Updates the avatar using the current tracking data.
///
protected void UpdateAvatarUsingTrackingDevices()
{
foreach (UxrTrackingDevice trackingDevice in Avatar.TrackingDevices)
{
if (trackingDevice && trackingDevice.enabled)
{
// Update avatar by calling internal interface
((IUxrTrackingUpdater)trackingDevice).UpdateAvatar();
}
}
}
///
/// Updates the enabled locomotion components in the avatar.
///
protected void UpdateLocomotion()
{
foreach (UxrLocomotion locomotion in UxrLocomotion.GetComponents(Avatar))
{
if (locomotion.gameObject.activeInHierarchy && locomotion.enabled)
{
((IUxrLocomotionUpdater)locomotion).UpdateLocomotion();
}
}
}
#endregion
}
}