namespace Zinnia.Tracking.Follow
{
using System;
using UnityEngine;
using UnityEngine.Events;
using Zinnia.Data.Collection.List;
using Zinnia.Extension;
using Zinnia.Process.Component;
using Zinnia.Tracking.Follow.Modifier;
///
/// Mirrors the properties of another based on the given .
///
public class ObjectFollower : GameObjectSourceTargetProcessor
{
///
/// Holds data about a event.
///
[Serializable]
public class EventData
{
[Tooltip("The source utilize within the Modifier.FollowModifier.")]
[SerializeField]
private GameObject eventSource;
///
/// The source utilize within the .
///
public GameObject EventSource
{
get
{
return eventSource;
}
set
{
eventSource = value;
}
}
[Tooltip("The target to apply the Modifier.FollowModifier on.")]
[SerializeField]
private GameObject eventTarget;
///
/// The target to apply the on.
///
public GameObject EventTarget
{
get
{
return eventTarget;
}
set
{
eventTarget = value;
}
}
[Tooltip("The optional offset the target follow against the source.")]
[SerializeField]
private GameObject eventTargetOffset;
///
/// The optional offset the target follow against the source.
///
public GameObject EventTargetOffset
{
get
{
return eventTargetOffset;
}
set
{
eventTargetOffset = value;
}
}
///
/// Clears .
///
public virtual void ClearEventSource()
{
EventSource = default;
}
///
/// Clears .
///
public virtual void ClearEventTarget()
{
EventTarget = default;
}
///
/// Clears .
///
public virtual void ClearEventTargetOffset()
{
EventTargetOffset = default;
}
public EventData Set(EventData source)
{
return Set(source.EventSource, source.EventTarget, source.EventTargetOffset);
}
public EventData Set(GameObject source, GameObject target, GameObject targetOffset = null)
{
EventSource = source;
EventTarget = target;
EventTargetOffset = targetOffset;
return this;
}
public void Clear()
{
Set(default, default, default);
}
}
///
/// Defines the event with the .
///
[Serializable]
public class FollowEvent : UnityEvent { }
[Tooltip("A GameObject collection of target offsets to offset the GameObjectSourceTargetProcessor.Targets against the source whilst following. The GameObject for the target offset must be a child of the corresponding target.")]
[SerializeField]
private GameObjectObservableList targetOffsets;
///
/// A collection of target offsets to offset the against the source whilst following. The for the target offset must be a child of the corresponding target.
///
public GameObjectObservableList TargetOffsets
{
get
{
return targetOffsets;
}
set
{
targetOffsets = value;
}
}
[Header("Follow Settings")]
[Tooltip("The Modifier.FollowModifier to apply.")]
[SerializeField]
private FollowModifier followModifier;
///
/// The to apply.
///
public FollowModifier FollowModifier
{
get
{
return followModifier;
}
set
{
followModifier = value;
}
}
///
/// Emitted before any processing.
///
public UnityEvent Preprocessed = new UnityEvent();
///
/// Emitted after all processing is complete.
///
public UnityEvent Processed = new UnityEvent();
///
/// Clears .
///
public virtual void ClearTargetOffsets()
{
if (!this.IsValidState())
{
return;
}
TargetOffsets = default;
}
///
/// Clears .
///
public virtual void ClearFollowModifier()
{
if (!this.IsValidState())
{
return;
}
FollowModifier = default;
}
///
public override void Process()
{
if (!this.IsValidState())
{
return;
}
Preprocessed?.Invoke();
base.Process();
Processed?.Invoke();
}
///
/// Applies the follow modification of the given source to the given target.
///
/// The source to take the follow data from.
/// The target to apply the follow data to.
protected override void ApplySourceToTarget(GameObject source, GameObject target)
{
GameObject followOffset = GetFollowOffset();
if (followOffset != null && !followOffset.transform.IsChildOf(Targets.NonSubscribableElements[Targets.CurrentIndex].transform))
{
throw new ArgumentException($"The `TargetOffsets` at index [{Targets.CurrentIndex}] must be a child of the GameObject at `Targets` index [{Targets.CurrentIndex}].");
}
FollowModifier.Modify(source, target, followOffset);
}
///
/// Gets the Follow Offset for the current target offset based on the current target index.
///
///
protected virtual GameObject GetFollowOffset()
{
if (Targets == null || TargetOffsets == null || Targets.NonSubscribableElements.Count == 0 || TargetOffsets.NonSubscribableElements.Count == 0)
{
return null;
}
int currentIndexTargets = TargetOffsets.NonSubscribableElements.ClampIndex(Targets.CurrentIndex);
return TargetOffsets.NonSubscribableElements[currentIndexTargets];
}
}
}