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]);
}
}
}