namespace VRTK.Prefabs.Locomotion.Movement.Climb { using UnityEngine; using System.Collections.Generic; using Malimbe.XmlDocumentationAttribute; using Malimbe.PropertySerializationAttribute; using Zinnia.Data.Attribute; using Zinnia.Data.Collection.List; using Zinnia.Tracking.Follow; using Zinnia.Tracking.Velocity; using Zinnia.Data.Operation.Mutation; using Zinnia.Data.Type.Transformation.Aggregation; using VRTK.Prefabs.Locomotion.BodyRepresentation; /// /// Sets up the Climb prefab based on the provided user settings. /// public class ClimbVelocityApplier : MonoBehaviour { #region Facade Settings /// /// The public interface facade. /// [Serialized] [field: Header("Facade Settings"), DocumentedByXml, Restricted] public ClimbFacade Facade { get; protected set; } #endregion #region Reference Settings /// /// The objects defining the sources of movement. /// [Serialized] [field: Header("Reference Settings"), DocumentedByXml, Restricted] public GameObjectObservableList Interactors { get; protected set; } /// /// The objects defining the offsets of movement. /// [Serialized] [field: DocumentedByXml, Restricted] public GameObjectObservableList Interactables { get; protected set; } /// /// The component for obtaining velocity data. /// [Serialized] [field: DocumentedByXml, Restricted] public ComponentTrackerProxy VelocityProxy { get; protected set; } /// /// The component for multiplying velocity data. /// [Serialized] [field: DocumentedByXml, Restricted] public Vector3Multiplier VelocityMultiplier { get; protected set; } /// /// The component for the source. /// [Serialized] [field: DocumentedByXml, Restricted] public ObjectDistanceComparator SourceDistanceComparator { get; protected set; } /// /// The component for the offset. /// [Serialized] [field: DocumentedByXml, Restricted] public ObjectDistanceComparator OffsetDistanceComparator { get; protected set; } /// /// The component for the offset. /// [Serialized] [field: DocumentedByXml, Restricted] public TransformPositionMutator TargetPositionProperty { get; protected set; } /// /// The component for emitting velocity data. /// [Serialized] [field: DocumentedByXml, Restricted] public VelocityEmitter VelocityEmitter { get; protected set; } #endregion /// /// Applies velocity to the . /// public virtual void ApplyVelocity() { if (!isActiveAndEnabled || Interactors.NonSubscribableElements.Count > 0 || VelocityProxy.ProxySource == null) { return; } VelocityEmitter.EmitVelocity(); Facade.BodyRepresentationFacade.ListenToRigidbodyMovement(); Facade.BodyRepresentationFacade.PhysicsBody.velocity += VelocityMultiplier.Result; VelocityProxy.ProxySource = null; } /// /// Configures the based on the facade settings. /// public virtual void ConfigureTargetPositionProperty() { TargetPositionProperty.Target = Facade.BodyRepresentationFacade.Offset == null ? Facade.BodyRepresentationFacade.Source : Facade.BodyRepresentationFacade.Offset; } protected virtual void OnEnable() { Interactors.Populated.AddListener(OnListBecamePopulated); Interactors.Added.AddListener(OnInteractorAdded); Interactors.Removed.AddListener(OnInteractorRemoved); Interactors.Emptied.AddListener(OnListBecameEmpty); Interactables.Added.AddListener(OnInteractableAdded); Interactables.Removed.AddListener(OnInteractableRemoved); SourceDistanceComparator.enabled = false; OffsetDistanceComparator.enabled = false; ConfigureTargetPositionProperty(); } protected virtual void OnDisable() { TargetPositionProperty.Target = null; OffsetDistanceComparator.enabled = false; SourceDistanceComparator.enabled = false; Interactables.Removed.RemoveListener(OnInteractableRemoved); Interactables.Added.RemoveListener(OnInteractableAdded); Interactors.Emptied.RemoveListener(OnListBecameEmpty); Interactors.Removed.RemoveListener(OnInteractorRemoved); Interactors.Added.RemoveListener(OnInteractorAdded); Interactors.Populated.RemoveListener(OnListBecamePopulated); } /// /// Emits a climb started event when the list becomes populated. /// /// The element added. protected virtual void OnListBecamePopulated(GameObject addedElement) { if (Interactors.NonSubscribableElements.Count > 0 || Interactables.NonSubscribableElements.Count > 0) { Facade.ClimbStarted?.Invoke(); } } /// /// Emits a climb stopped event when the list becomes empty. /// /// The element removed. protected virtual void OnListBecameEmpty(GameObject removedElement) { if (Interactors.NonSubscribableElements.Count == 0 && Interactables.NonSubscribableElements.Count == 0) { Facade.ClimbStopped?.Invoke(); } } /// /// Configures the when an interactor is added. /// /// The added interactor. protected virtual void OnInteractorAdded(GameObject interactor) { SourceDistanceComparator.Source = interactor; SourceDistanceComparator.Target = interactor; SourceDistanceComparator.enabled = interactor != null; SourceDistanceComparator.SavePosition(); if (interactor != null) { Facade.BodyRepresentationFacade.Interest = BodyRepresentationProcessor.MovementInterest.CharacterController; } } /// /// Configures the when an interactor is removed. /// /// The removed interactor. protected virtual void OnInteractorRemoved(GameObject interactor) { IReadOnlyList elements = Interactors.NonSubscribableElements; OnInteractorAdded(elements.Count == 0 ? null : elements[elements.Count - 1]); } /// /// Configures the when an interactable is added. /// /// The added interactable. protected virtual void OnInteractableAdded(GameObject interactable) { OffsetDistanceComparator.Source = interactable; OffsetDistanceComparator.Target = interactable; OffsetDistanceComparator.enabled = interactable != null; OffsetDistanceComparator.SavePosition(); if (interactable != null) { Facade.BodyRepresentationFacade.Interest = BodyRepresentationProcessor.MovementInterest.CharacterController; } } /// /// Configures the when an interactable is removed. /// /// The removed interactable. protected virtual void OnInteractableRemoved(GameObject interactable) { IReadOnlyList elements = Interactables.NonSubscribableElements; OnInteractableAdded(elements.Count == 0 ? null : elements[elements.Count - 1]); } } }