// -------------------------------------------------------------------------------------------------------------------- // // 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 } }