namespace Zinnia.Tracking.Collision
{
using System.Collections.Generic;
using UnityEngine;
using Zinnia.Data.Collection.List;
using Zinnia.Extension;
///
/// Ignores the collisions between the source colliders and the target colliders.
///
public class CollisionIgnorer : MonoBehaviour
{
[Tooltip("The sources to ignore colliders from.")]
[SerializeField]
private GameObjectObservableList sources;
///
/// The sources to ignore colliders from.
///
public GameObjectObservableList Sources
{
get
{
return sources;
}
set
{
if (this.IsMemberChangeAllowed())
{
OnBeforeSourcesChange();
}
sources = value;
if (this.IsMemberChangeAllowed())
{
OnAfterSourcesChange();
}
}
}
[Tooltip("The targets to ignore colliders with.")]
[SerializeField]
private GameObjectObservableList targets;
///
/// The targets to ignore colliders with.
///
public GameObjectObservableList Targets
{
get
{
return targets;
}
set
{
if (this.IsMemberChangeAllowed())
{
OnBeforeTargetsChange();
}
targets = value;
if (this.IsMemberChangeAllowed())
{
OnAfterTargetsChange();
}
}
}
[Tooltip("Whether to process inactive GameObjects when ignoring or resuming collisions.")]
[SerializeField]
private bool processInactiveGameObjects;
///
/// Whether to process inactive s when ignoring or resuming collisions.
///
public bool ProcessInactiveGameObjects
{
get
{
return processInactiveGameObjects;
}
set
{
processInactiveGameObjects = value;
}
}
///
/// A reused instance to store the collection belonging to the .
///
protected List sourceColliders = new List();
///
/// A reused instance to store the collection belonging to the .
///
protected List targetColliders = new List();
protected virtual void OnEnable()
{
RegisterSourceListeners();
RegisterTargetListeners();
ToggleCollisions(true);
}
protected virtual void OnDisable()
{
UnregisterSourceListeners();
UnregisterTargetListeners();
ToggleCollisions(false);
}
///
/// Registers the listeners for elements that are added or removed from .
///
protected virtual void RegisterSourceListeners()
{
if (Sources == null)
{
return;
}
Sources.Added.AddListener(OnSourceAdded);
Sources.Removed.AddListener(OnSourceRemoved);
}
///
/// Unregisters the listeners for elements that are added or removed from .
///
protected virtual void UnregisterSourceListeners()
{
if (Sources == null)
{
return;
}
Sources.Added.RemoveListener(OnSourceAdded);
Sources.Removed.RemoveListener(OnSourceRemoved);
}
///
/// Registers the listeners for elements that are added or removed from .
///
protected virtual void RegisterTargetListeners()
{
if (Targets == null)
{
return;
}
Targets.Added.AddListener(OnTargetAdded);
Targets.Removed.AddListener(OnTargetRemoved);
}
///
/// Unregisters the listeners for elements that are added or removed from .
///
protected virtual void UnregisterTargetListeners()
{
if (Targets == null)
{
return;
}
Targets.Added.RemoveListener(OnTargetAdded);
Targets.Removed.RemoveListener(OnTargetRemoved);
}
///
/// Responds to a being added to and ignores all collisions against .
///
/// The source to ignore collisions from.
protected virtual void OnSourceAdded(GameObject source)
{
ToggleCollisions(source, Sources, Targets, true);
}
///
/// Responds to a being removed from and resumes all collisions against .
///
/// The source to restore collisions with.
protected virtual void OnSourceRemoved(GameObject source)
{
ToggleCollisions(source, Sources, Targets, false);
}
///
/// Responds to a being added to and ignores all collisions against .
///
/// The target to ignore collisions on.
protected virtual void OnTargetAdded(GameObject target)
{
ToggleCollisions(target, Targets, Sources, true);
}
///
/// Responds to a being removed from and resumes all collisions against .
///
/// The target to restore collisions on.
protected virtual void OnTargetRemoved(GameObject target)
{
ToggleCollisions(target, Targets, Sources, false);
}
///
/// Sets the collision state between and .
///
/// Whether to ignore collisions or not.
protected virtual void ToggleCollisions(bool state)
{
foreach (GameObject source in Sources.SubscribableElements)
{
ToggleCollisions(source, Sources, Targets, state);
}
}
///
/// Sets the collision state between the source and targets.
///
/// The source to set the collision state on.
/// A collection of sources to check if the given belongs to.
/// A collection of targets to set the collision state on.
/// Whether to ignore collisions or not.
protected virtual void ToggleCollisions(GameObject source, GameObjectObservableList sources, GameObjectObservableList targets, bool state)
{
if (source == null || (!state && this.CheckIsActiveAndEnabled() && sources.Contains(source)))
{
return;
}
source.GetComponentsInChildren(ProcessInactiveGameObjects, sourceColliders);
foreach (GameObject target in targets.SubscribableElements)
{
if (target == null)
{
continue;
}
target.GetComponentsInChildren(ProcessInactiveGameObjects, targetColliders);
foreach (Collider sourceCollider in sourceColliders)
{
foreach (Collider targetCollider in targetColliders)
{
Physics.IgnoreCollision(sourceCollider, targetCollider, state);
}
}
}
}
///
/// Called before has been changed.
///
protected virtual void OnBeforeSourcesChange()
{
if (Sources != null)
{
UnregisterSourceListeners();
ToggleCollisions(false);
}
}
///
/// Called after has been changed.
///
protected virtual void OnAfterSourcesChange()
{
if (Sources != null)
{
RegisterSourceListeners();
ToggleCollisions(true);
}
}
///
/// Called before has been changed.
///
protected virtual void OnBeforeTargetsChange()
{
if (Targets != null)
{
UnregisterTargetListeners();
ToggleCollisions(false);
}
}
///
/// Called after has been changed.
///
protected virtual void OnAfterTargetsChange()
{
if (Targets != null)
{
RegisterTargetListeners();
ToggleCollisions(true);
}
}
}
}