using UnityEngine;
/// <remarks>
/// This script disables colliders that are outside of a UIPanel's clipping range
/// or enables them if they intersect it. This only works for UIPanels that are not dragged around.
/// </remarks>
public class UIColliderClipper : MonoBehaviour
{
#region Inspector Data
/// <summary>
/// Indicates the number of frames that need to
/// pass before updating the colliders
/// </summary>
public int UpdateRate = 5;
/// <summary>
/// The panel that contains the clipping range
/// </summary>
public UIPanel ClippingPanel;
/// <summary>
/// The transform of the parent that contains the colliders
/// </summary>
public Transform Container;
#endregion
#region Data
private int _frames;
private Bounds _panelBounds;
private Vector3 _lastContainerPosition;
private int _widgetCount;
#endregion
/// <summary>
/// Initialization
/// </summary>
void Start()
{
_panelBounds = GetPanelBounds();
_lastContainerPosition
= new Vector3
( Mathf
.Infinity, Mathf
.Infinity, Mathf
.Infinity ); _widgetCount = ClippingPanel.widgets.size;
}
/// <summary>
/// Disables / Enables colliders based on their collider bounds in respect to the clipping range
/// </summary>
void Update ()
{
_frames++;
if ( _frames < UpdateRate )
return;
_frames = 0;
// check if the parent container has moved...
if ( !Approximately( Container.localPosition, _lastContainerPosition ) )
{
_lastContainerPosition = Container.localPosition;
}
else
{
//... or if new children were added to the panel
if( _widgetCount != ClippingPanel.widgets.size )
{
_widgetCount = ClippingPanel.widgets.size;
}
else
{
return;
}
}
// update colliders
var widgetColliders = GetComponentsInChildren<BoxCollider>();
for ( int i = 0; i < widgetColliders.Length; i++ )
{
var bounds = GetWidgetBounds( widgetColliders[i] );
widgetColliders[i].enabled = bounds.Intersects( _panelBounds );
}
}
/// <summary>
/// Returns true if the two vectors are approximately equal
/// </summary>
private static bool Approximately( Vector3 lhs, Vector3 rhs )
{
if ( Mathf.Approximately( lhs.x, rhs.x ) &&
Mathf.Approximately( lhs.y, rhs.y ) &&
Mathf.Approximately( lhs.z, rhs.z ) )
{
return true;
}
return false;
}
/// <summary>
/// Gets the bounds of a transform based on a center and a size
/// in local coordinates
/// </summary>
private static Bounds GetBounds( Transform transform, Vector3 localCenter, Vector3 localSize )
{
var center = transform.position;
center += Vector3.Scale( transform.lossyScale, localCenter);
center.z = 0;
var size = Vector3.Scale( transform.lossyScale, localSize);
size.z = 0;
return new Bounds
( center, size
); }
/// <summary>
/// Gets the bounds of the UIPanel
/// </summary>
/// <returns></returns>
private Bounds GetPanelBounds()
{
return GetBounds( ClippingPanel.cachedTransform,
new Vector3
( ClippingPanel
.clipRange.x, ClippingPanel
.clipRange.y,
0 ),
new Vector3
( ClippingPanel
.clipRange.z, ClippingPanel
.clipRange.w ) ); }
/// <summary>
/// Gets the bounds of a widget
/// </summary>
private Bounds GetWidgetBounds( BoxCollider widgetCollider )
{
return GetBounds( widgetCollider.transform, widgetCollider.center, widgetCollider.size );
}
}