namespace VRTK.Prefabs.Interactions.Interactables.Touch
{
using UnityEngine;
using System.Collections.Generic;
using Malimbe.XmlDocumentationAttribute;
using Malimbe.PropertySerializationAttribute;
using Zinnia.Extension;
using Zinnia.Event.Proxy;
using Zinnia.Data.Attribute;
using Zinnia.Data.Collection.List;
using Zinnia.Tracking.Collision;
using Zinnia.Tracking.Collision.Active;
using Zinnia.Tracking.Collision.Active.Operation.Extraction;
using VRTK.Prefabs.Interactions.Interactors;
public class TouchInteractableConfigurator : MonoBehaviour
{
#region Facade Settings
///
/// The public interface facade.
///
[Serialized]
[field: Header("Facade Settings"), DocumentedByXml, Restricted]
public InteractableFacade Facade { get; protected set; }
#endregion
#region Touch Consumer Settings
///
/// The that listens for the touch payload.
///
[Serialized]
[field: Header("Touch Consumer Settings"), DocumentedByXml, Restricted]
public ActiveCollisionConsumer TouchConsumer { get; protected set; }
///
/// The that listens for the untouch payload.
///
[Serialized]
[field: DocumentedByXml, Restricted]
public ActiveCollisionConsumer UntouchConsumer { get; protected set; }
#endregion
#region Touch Settings
///
/// The that holds the current touching objects data.
///
[Serialized]
[field: Header("Touch Settings"), DocumentedByXml, Restricted]
public GameObjectObservableList CurrentTouchingObjects { get; protected set; }
///
/// The used to determine the touch validity.
///
[Serialized]
[field: DocumentedByXml, Restricted]
public GameObjectEventProxyEmitter TouchValidity { get; set; }
#endregion
#region Interactor Settings
///
/// The for potential interactors.
///
[Serialized]
[field: Header("Interactor Settings"), DocumentedByXml, Restricted]
public ActiveCollisionsContainer PotentialInteractors { get; protected set; }
///
/// The for adding active interactors.
///
[Serialized]
[field: DocumentedByXml, Restricted]
public NotifierContainerExtractor AddActiveInteractor { get; protected set; }
///
/// The for removing active interactors.
///
[Serialized]
[field: DocumentedByXml, Restricted]
public NotifierContainerExtractor RemoveActiveInteractor { get; protected set; }
#endregion
///
/// A collection of Interactors that are currently touching the Interactable.
///
public IReadOnlyList TouchingInteractors => GetTouchingInteractors();
///
/// A reusable collection to hold the returned touching interactors.
///
protected readonly List touchingInteractors = new List();
///
/// Notifies that the Interactable is being touched.
///
/// The touching object.
public virtual void NotifyTouch(GameObject data)
{
InteractorFacade interactor = data.TryGetComponent(true, true);
if (interactor != null)
{
if (Facade.TouchingInteractors.Count == 1)
{
Facade.FirstTouched?.Invoke(interactor);
}
Facade.Touched?.Invoke(interactor);
interactor.NotifyOfTouch(Facade);
}
}
///
/// Notifies that the Interactable is being no longer touched.
///
/// The previous touching object.
public virtual void NotifyUntouch(GameObject data)
{
InteractorFacade interactor = data.TryGetComponent(true, true);
if (interactor != null)
{
Facade.Untouched?.Invoke(interactor);
interactor.NotifyOfUntouch(Facade);
if (Facade.TouchingInteractors.Count == 0)
{
Facade.LastUntouched?.Invoke(interactor);
}
}
}
///
/// Sets the consumer containers to the current active container.
///
public virtual void ConfigureContainer()
{
TouchConsumer.Container = Facade.ConsumerContainer;
UntouchConsumer.Container = Facade.ConsumerContainer;
}
///
/// Retrieves a collection of Interactors that are touching the Interactable.
///
/// The touching Interactors.
protected virtual IReadOnlyList GetTouchingInteractors()
{
touchingInteractors.Clear();
if (CurrentTouchingObjects == null)
{
return touchingInteractors;
}
foreach (GameObject element in CurrentTouchingObjects.NonSubscribableElements)
{
InteractorFacade interactor = element.TryGetComponent(true, true);
if (interactor != null)
{
touchingInteractors.Add(interactor);
}
}
return touchingInteractors;
}
protected virtual void OnEnable()
{
ConfigureContainer();
TouchValidity.ReceiveValidity = Facade.DisallowedTouchInteractors;
LinkActiveInteractorCollisions();
}
protected virtual void OnDisable()
{
UnlinkActiveInteractorCollisions();
}
///
/// Links the to the potential and active interactor logic.
///
protected virtual void LinkActiveInteractorCollisions()
{
Facade.CollisionNotifier.CollisionStarted.AddListener(PotentialInteractors.Add);
Facade.CollisionNotifier.CollisionStarted.AddListener(AddActiveInteractor.DoExtract);
Facade.CollisionNotifier.CollisionChanged.AddListener(ProcessPotentialInteractorContentChange);
Facade.CollisionNotifier.CollisionStopped.AddListener(PotentialInteractors.Remove);
Facade.CollisionNotifier.CollisionStopped.AddListener(RemoveActiveInteractor.DoExtract);
}
///
/// Unlinks the to the potential and active interactor logic.
///
protected virtual void UnlinkActiveInteractorCollisions()
{
Facade.CollisionNotifier.CollisionStarted.RemoveListener(PotentialInteractors.Add);
Facade.CollisionNotifier.CollisionStarted.RemoveListener(AddActiveInteractor.DoExtract);
Facade.CollisionNotifier.CollisionChanged.RemoveListener(ProcessPotentialInteractorContentChange);
Facade.CollisionNotifier.CollisionStopped.RemoveListener(PotentialInteractors.Remove);
Facade.CollisionNotifier.CollisionStopped.RemoveListener(RemoveActiveInteractor.DoExtract);
}
///
/// Handles any change of collision contents.
///
/// The changed collision data.
protected virtual void ProcessPotentialInteractorContentChange(CollisionNotifier.EventData data)
{
PotentialInteractors.ProcessContentsChanged();
}
}
}