2025-06-04 22:49:37 +08:00
/ *
* @author Valentin Simonov / http : //va.lent.in/
* /
using System ;
using System.Collections.Generic ;
using TouchScript.Hit ;
using TouchScript.Layers ;
using TouchScript.Pointers ;
using UnityEngine ;
namespace TouchScript.Core
{
/// <summary>
/// Internal implementation of <see cref="ILayerManager"/>.
/// </summary>
internal sealed class LayerManagerInstance : MonoBehaviour , ILayerManager
{
#region Public properties
/// <summary>
/// Gets the instance of GestureManager singleton.
/// </summary>
public static ILayerManager Instance
{
get
{
2025-08-24 18:59:40 +08:00
if ( object . Equals ( instance , null ) )
2025-06-04 22:49:37 +08:00
{
2025-08-24 18:59:40 +08:00
// Create an instance if it hasn't been created yet.
// Don't recreate it if the instance was destroyed.
// Should happen only when the app is closing or editor is exiting Play Mode.
2025-06-04 22:49:37 +08:00
if ( ! Application . isPlaying ) return null ;
var objects = FindObjectsOfType < LayerManagerInstance > ( ) ;
if ( objects . Length = = 0 )
{
2025-08-24 18:59:40 +08:00
var go = new GameObject ( "LayerManager Instance" ) ;
2025-06-04 22:49:37 +08:00
instance = go . AddComponent < LayerManagerInstance > ( ) ;
}
else if ( objects . Length > = 1 )
{
instance = objects [ 0 ] ;
}
}
return instance ;
}
}
/// <inheritdoc />
public IList < TouchLayer > Layers
{
get { return new List < TouchLayer > ( layers ) ; }
}
/// <inheritdoc />
public int LayerCount
{
get { return layerCount ; }
}
/// <inheritdoc />
public bool HasExclusive
{
get { return exclusiveCount > 0 ; }
}
# endregion
#region Private variables
private static LayerManagerInstance instance ;
2025-08-24 18:59:40 +08:00
private ITouchManager touchManager ;
2025-06-04 22:49:37 +08:00
private List < TouchLayer > layers = new List < TouchLayer > ( 10 ) ;
private int layerCount = 0 ;
private HashSet < int > exclusive = new HashSet < int > ( ) ;
private int exclusiveCount = 0 ;
private int clearExclusiveDelay = - 1 ;
# endregion
#region Temporary variables
// Used in SetExclusive().
private List < Transform > tmpList = new List < Transform > ( 20 ) ;
# endregion
#region Public methods
/// <inheritdoc />
public bool AddLayer ( TouchLayer layer , int index = - 1 , bool addIfExists = true )
{
if ( layer = = null ) return false ;
var i = layers . IndexOf ( layer ) ;
if ( i ! = - 1 )
{
if ( ! addIfExists ) return false ;
layers . RemoveAt ( i ) ;
layerCount - - ;
}
if ( index = = 0 )
{
layers . Insert ( 0 , layer ) ;
layerCount + + ;
return i = = - 1 ;
}
if ( index = = - 1 | | index > = layerCount )
{
layers . Add ( layer ) ;
layerCount + + ;
return i = = - 1 ;
}
if ( i ! = - 1 )
{
if ( index < i ) layers . Insert ( index , layer ) ;
else layers . Insert ( index - 1 , layer ) ;
layerCount + + ;
return false ;
}
layers . Insert ( index , layer ) ;
layerCount + + ;
return true ;
}
/// <inheritdoc />
public bool RemoveLayer ( TouchLayer layer )
{
if ( layer = = null ) return false ;
var result = layers . Remove ( layer ) ;
if ( result ) layerCount - - ;
return result ;
}
/// <inheritdoc />
public void ChangeLayerIndex ( int at , int to )
{
if ( at < 0 | | at > = layerCount ) return ;
if ( to < 0 | | to > = layerCount ) return ;
var data = layers [ at ] ;
layers . RemoveAt ( at ) ;
layers . Insert ( to , data ) ;
}
/// <inheritdoc />
public void ForEach ( Func < TouchLayer , bool > action )
{
for ( var i = 0 ; i < layerCount ; i + + )
{
if ( ! action ( layers [ i ] ) ) break ;
}
}
/// <inheritdoc />
public bool GetHitTarget ( IPointer pointer , out HitData hit )
{
hit = default ( HitData ) ;
for ( var i = 0 ; i < layerCount ; i + + )
{
var touchLayer = layers [ i ] ;
if ( touchLayer = = null ) continue ;
var result = touchLayer . Hit ( pointer , out hit ) ;
switch ( result )
{
case HitResult . Hit :
return true ;
case HitResult . Discard :
return false ;
}
}
return false ;
}
/// <inheritdoc />
public void SetExclusive ( Transform target , bool includeChildren = false )
{
if ( target = = null ) return ;
exclusive . Clear ( ) ;
clearExclusiveDelay = - 1 ;
exclusive . Add ( target . GetHashCode ( ) ) ;
exclusiveCount = 1 ;
if ( includeChildren )
{
target . GetComponentsInChildren ( tmpList ) ;
foreach ( var t in tmpList ) exclusive . Add ( t . GetHashCode ( ) ) ;
exclusiveCount + = tmpList . Count ;
}
}
/// <inheritdoc />
public void SetExclusive ( IEnumerable < Transform > targets )
{
if ( targets = = null ) return ;
exclusive . Clear ( ) ;
clearExclusiveDelay = - 1 ;
foreach ( var t in targets )
{
exclusive . Add ( t . GetHashCode ( ) ) ;
exclusiveCount + + ;
}
}
/// <inheritdoc />
public bool IsExclusive ( Transform target )
{
return exclusive . Contains ( target . GetHashCode ( ) ) ;
}
/// <inheritdoc />
public void ClearExclusive ( )
{
// It is incorrect to just set exclusiveCount to zero since the exclusive list is actually needed the next frame. Only after the next frame's FrameEnded event the list can be cleared.
// If we are inside the Pointer Frame, we need to wait for the second FrameEnded (this frame's event included). Otherwise, we need to wait for the next FrameEnded event.
2025-08-24 18:59:40 +08:00
clearExclusiveDelay = ( touchManager ! = null & & touchManager . IsInsidePointerFrame ) ? 2 : 1 ;
2025-06-04 22:49:37 +08:00
}
# endregion
#region Unity
private void Awake ( )
{
if ( instance = = null )
{
instance = this ;
}
else if ( instance ! = this )
{
Destroy ( this ) ;
return ;
}
2025-08-24 18:59:40 +08:00
touchManager = TouchManager . Instance ;
2025-06-04 22:49:37 +08:00
gameObject . hideFlags = HideFlags . HideInHierarchy ;
DontDestroyOnLoad ( gameObject ) ;
}
private void OnEnable ( )
{
2025-08-24 18:59:40 +08:00
if ( touchManager ! = null ) touchManager . FrameFinished + = frameFinishedHandler ;
2025-06-04 22:49:37 +08:00
}
private void OnDisable ( )
{
2025-08-24 18:59:40 +08:00
if ( touchManager ! = null ) touchManager . FrameFinished - = frameFinishedHandler ;
2025-06-04 22:49:37 +08:00
}
# endregion
#region Private functions
# endregion
#region Event handlers
private void frameFinishedHandler ( object sender , EventArgs eventArgs )
{
clearExclusiveDelay - - ;
if ( clearExclusiveDelay = = 0 )
{
exclusive . Clear ( ) ;
exclusiveCount = 0 ;
}
}
# endregion
}
}