/* * @author Valentin Simonov / http://va.lent.in/ */ using System; using TouchScript.Hit; using TouchScript.Utils; using UnityEngine; using System.Collections; using System.Collections.Generic; using TouchScript.Pointers; namespace TouchScript.Layers { /// /// Base class for all pointer layers. Used to check if some object is hit by a pointer. /// /// /// /// /// /// In TouchScript it's a layer's job to determine if a pointer on the screen hits anything in Unity's 3d/2d world. /// keeps a sorted list of all layers in which it queries when a new pointer appears. It's a layer's job to return if this pointer hits an object. Layers can even be used to "hit" objects outside of Unity's 3d world, for example Scaleform integration is implemented this way. /// Layers can be configured in a scene using or from code using API. /// If you want to route pointers and manually control which objects they should "pointer" it's better to create a new layer extending . /// [ExecuteInEditMode] public abstract class TouchLayer : MonoBehaviour { #region Events /// /// Occurs when layer determines that a pointer has hit something. /// public event EventHandler PointerBegan { add { pointerPressInvoker += value; } remove { pointerPressInvoker -= value; } } // Needed to overcome iOS AOT limitations private EventHandler pointerPressInvoker; #endregion #region Public properties /// /// Pointer layer's name. /// public string Name; /// /// Layers screen to world projection normal. /// public virtual Vector3 WorldProjectionNormal { get { return transform.forward; } } /// /// Gets or sets an object implementing to be asked for layer specific actions. /// /// The delegate. public ILayerDelegate Delegate { get; set; } #endregion #region Private variables /// /// The layer projection parameters. /// protected ProjectionParams layerProjectionParams; /// /// Layer manager. /// protected ILayerManager manager; #endregion #region Temporary variables private List tmpHitTestList = new List(10); #endregion #region Public methods /// /// Gets the projection parameters of this layer which might depend on a specific pointer data. /// /// Pointer to retrieve projection parameters for. /// public virtual ProjectionParams GetProjectionParams(Pointer pointer) { return layerProjectionParams; } /// /// Checks if a point in screen coordinates hits something in this layer. /// /// Pointer. /// Hit result. /// true, if an object is hit, ; false otherwise. public virtual HitResult Hit(IPointer pointer, out HitData hit) { hit = default(HitData); if (enabled == false || gameObject.activeInHierarchy == false) return HitResult.Miss; if (Delegate != null) { if (Delegate.ShouldReceivePointer(this, pointer)) return HitResult.Hit; return HitResult.Miss; } return HitResult.Hit; } #endregion #region Unity methods /// /// Unity Awake callback. /// protected virtual void Awake() { setName(); if (!Application.isPlaying) return; manager = LayerManager.Instance; layerProjectionParams = createProjectionParams(); StartCoroutine(lateAwake()); } private IEnumerator lateAwake() { yield return null; // Add ourselves after TouchManager finished adding layers in order manager.AddLayer(this, -1, false); } // To be able to turn layers off private void Start() {} /// /// Unity OnDestroy callback. /// protected virtual void OnDestroy() { if (!Application.isPlaying || TouchManager.Instance == null) return; StopAllCoroutines(); manager.RemoveLayer(this); } #endregion #region Internal methods internal void INTERNAL_AddPointer(Pointer pointer) { addPointer(pointer); } internal void INTERNAL_UpdatePointer(Pointer pointer) { updatePointer(pointer); } internal bool INTERNAL_PressPointer(Pointer pointer) { pressPointer(pointer); if (pointerPressInvoker != null) pointerPressInvoker.InvokeHandleExceptions(this, new TouchLayerEventArgs(pointer)); return true; } internal void INTERNAL_ReleasePointer(Pointer pointer) { releasePointer(pointer); } internal void INTERNAL_RemovePointer(Pointer pointer) { removePointer(pointer); } internal void INTERNAL_CancelPointer(Pointer pointer) { cancelPointer(pointer); } #endregion #region Protected functions /// /// Checks the hit filters. /// /// The pointer. /// HitData for the pointer. /// protected HitResult checkHitFilters(IPointer pointer, HitData hit) { hit.Target.GetComponents(tmpHitTestList); var count = tmpHitTestList.Count; if (count == 0) return HitResult.Hit; var hitResult = HitResult.Hit; for (var i = 0; i < count; i++) { var test = tmpHitTestList[i]; if (!test.enabled) continue; hitResult = test.IsHit(pointer, hit); if (hitResult != HitResult.Hit) break; } return hitResult; } /// /// Updates pointer layers's name. /// protected virtual void setName() { if (string.IsNullOrEmpty(Name)) Name = "Layer"; } /// /// Called when a pointer is added. /// /// Pointer. /// This method may also be used to update some internal state or resend this event somewhere. protected virtual void addPointer(Pointer pointer) {} /// /// Called when a layer is pressed over an object detected by this layer. /// /// Pointer. /// This method may also be used to update some internal state or resend this event somewhere. protected virtual void pressPointer(Pointer pointer) {} /// /// Called when a pointer is moved. /// /// Pointer. /// This method may also be used to update some internal state or resend this event somewhere. protected virtual void updatePointer(Pointer pointer) {} /// /// Called when a pointer is released. /// /// Pointer. /// This method may also be used to update some internal state or resend this event somewhere. protected virtual void releasePointer(Pointer pointer) {} /// /// Called when a pointer is removed. /// /// Pointer. /// This method may also be used to update some internal state or resend this event somewhere. protected virtual void removePointer(Pointer pointer) {} /// /// Called when a pointer is cancelled. /// /// Pointer. /// This method may also be used to update some internal state or resend this event somewhere. protected virtual void cancelPointer(Pointer pointer) {} /// /// Creates projection parameters. /// /// Created instance. protected virtual ProjectionParams createProjectionParams() { return new ProjectionParams(); } #endregion } /// /// Arguments used with events. /// public class TouchLayerEventArgs : EventArgs { /// /// Gets the pointer associated with the event. /// public Pointer Pointer { get; private set; } /// /// Initializes a new instance of the class. /// /// The pointer associated with the event. public TouchLayerEventArgs(Pointer pointer) : base() { Pointer = pointer; } } }