using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
namespace ProjectX
{
public class InputTouch
{
public int fingerId = 0;
///
/// touch position on screen.
///
public Vector2 position = Vector2.zero;
///
/// delta position between this-touch and last-touch.
///
public Vector2 deltaPosition = Vector2.zero;
///
/// time at this touch occurred.
///
public float time = 0;
///
/// elapse from last-touch to this-touch.
///
public float deltaTime = 0;
///
/// input ray caster for this touch.
///
public InputCaster caster = null;
///
/// input event source.
///
public InputTarget source = null;
///
/// object which is hovered by this touch.
///
public InputTarget target = null;
///
/// input ray.
///
public Ray ray;
///
/// input ray cast hit.
///
public RaycastHit hit;
}
public class InputEvent
{
private System.Action mOnEvent = null;
public void Invoke(InputTouch touch)
{
if (this.mOnEvent != null)
{
this.mOnEvent(touch);
}
}
public void Attach(System.Action handler)
{
this.mOnEvent += handler;
}
public void Detach(System.Action handler)
{
this.mOnEvent -= handler;
}
}
public class InputDetection : MonoBehaviour
{
public static InputDetection instance { get; private set; }
public static List casters = new List();
public static List handlers = new List();
public static bool IsOverUI(int fingerId)
{
if (EventSystem.current == null)
return false;
if (Application.platform == RuntimePlatform.IPhonePlayer ||
Application.platform == RuntimePlatform.Android)
{
return EventSystem.current.IsPointerOverGameObject(fingerId);
}
else
{
return EventSystem.current.IsPointerOverGameObject();
}
}
public static bool IsOverUI(Vector2 screenpos)
{
if (EventSystem.current == null)
return false;
PointerEventData evt = new PointerEventData(EventSystem.current);
evt.position = screenpos;
List results = new List();
EventSystem.current.RaycastAll(evt, results);
return results.Count > 0;
}
public static bool IsOverUI(Canvas canvas, Vector2 screenpos)
{
if (EventSystem.current == null)
return false;
PointerEventData evt = new PointerEventData(EventSystem.current);
evt.position = screenpos;
List results = new List();
GraphicRaycaster raycaster = canvas.GetComponent();
raycaster.Raycast(evt, results);
return results.Count > 0;
}
///
/// open this option will not detecte the moving(dragging) events, but it will improve the performance.
///
public bool ignoreMove = false;
///
/// open this option will not detecte events on ui.
///
public bool ignoreUI = true;
///
/// open this option will not detecte event on trigger.
///
public bool ignoreTrigger = true;
public bool checkTarget = true;
///
/// minimum time in seconds for click.
///
public float clickTime = 0.2f;
///
/// minimum movement in pixels for click.
///
public float clickDistance = 10;
public InputEvent onPressAnyWhere = new InputEvent();
public InputEvent onReleaseAnyWhere = new InputEvent();
public InputEvent onMoveAnyWhere = new InputEvent();
private bool mIsMouseDown = false;
private Vector3 mLastMousePos = Vector3.zero;
// private Dictionary mPressTouches = new Dictionary();
// private Dictionary mLastTouches = new Dictionary();
private InputTouch[] mPressTouches = new InputTouch[10];
private InputTouch[] mLastTouches = new InputTouch[10];
void Awake()
{
instance = this;
}
void Start()
{
casters.Sort((c1, c2) => c2.camera.depth.CompareTo(c1.camera.depth));
}
void Update()
{
bool hasFakePhase = false;
TouchPhase fakePhase = TouchPhase.Began;
if (Application.platform != RuntimePlatform.IPhonePlayer &&
Application.platform != RuntimePlatform.Android)
{
if (Input.GetMouseButtonDown(0))
{
this.mIsMouseDown = true;
this.mLastMousePos = Input.mousePosition;
hasFakePhase = true;
fakePhase = TouchPhase.Began;
}
else if (Input.GetMouseButtonUp(0))
{
this.mIsMouseDown = false;
hasFakePhase = true;
fakePhase = TouchPhase.Ended;
}
else if (this.mIsMouseDown)
{
if (Input.mousePosition != this.mLastMousePos)
{
this.mLastMousePos = Input.mousePosition;
fakePhase = TouchPhase.Moved;
}
else
{
fakePhase = TouchPhase.Stationary;
}
hasFakePhase = true;
}
}
// process each touch
Touch[] touches = Input.touches;
for (int i = 0; i < touches.Length; i++)
{
this.ProcessTouchAt(touches[i].position, touches[i].phase, touches[i].fingerId);
}
// process fake touch if there is one
if (hasFakePhase)
{
this.ProcessTouchAt(Input.mousePosition, fakePhase, 0);
}
}
private void ProcessTouchAt(Vector2 position, TouchPhase phase, int fingerId)
{
// Ignore stationary phase
if (phase == TouchPhase.Stationary)
return;
// Ignore canceled phase
if (phase == TouchPhase.Canceled)
return;
bool touchDown = phase == TouchPhase.Began;
bool touchUp = phase == TouchPhase.Ended;
// dont check move if not pressed.
if (this.ignoreMove && !touchDown && !touchUp)
return;
// dont check ui events if press on ui
if (this.ignoreUI && touchDown && IsOverUI(fingerId))
return;
// press & last touch on this finger
InputTouch pressTouch = this.mPressTouches[fingerId];
InputTouch lastTouch = this.mLastTouches[fingerId];
// new touch in this frame
InputTouch touch = new InputTouch();
touch.fingerId = fingerId;
touch.position = position;
touch.deltaPosition = lastTouch != null ? position - lastTouch.position : position;
touch.time = Time.realtimeSinceStartup;
touch.deltaTime = lastTouch != null ? touch.time - lastTouch.time : touch.time;
this.Raycast(position, out touch.ray, out touch.hit, out touch.caster, out touch.target);
touch.source = touch.target;
if (touchDown)
{
this.mPressTouches[touch.fingerId] = touch;
this.TriggerEvent(this.onPressAnyWhere, touch);
if (touch.source != null)
{
this.TriggerEvent(touch.source.onPress, touch);
}
}
else if (touchUp)
{
this.TriggerEvent(this.onReleaseAnyWhere, touch);
if (touch.source != null)
{
this.TriggerEvent(touch.source.onRelease, touch);
if (pressTouch != null && pressTouch.source == touch.source)
{
float timeSincePress = touch.time - pressTouch.time;
Vector2 moveSincePress = position - pressTouch.position;
if (timeSincePress <= this.clickTime && moveSincePress.sqrMagnitude <= this.clickDistance * this.clickDistance)
{
this.TriggerEvent(touch.source.onClick, touch);
}
}
}
this.mPressTouches[fingerId] = null;
}
else // move
{
this.TriggerEvent(this.onMoveAnyWhere, touch);
if (touch.source != null)
{
this.TriggerEvent(touch.source.onMove, touch);
}
}
this.mLastTouches[touch.fingerId] = touch;
}
private bool Raycast(Vector3 position, out Ray ray, out RaycastHit hitInfo, out InputCaster hitCaster, out InputTarget hitTarget)
{
ray = default(Ray);
hitInfo = default(RaycastHit);
hitCaster = null;
hitTarget = null;
for (int i = 0; i < casters.Count; i++)
{
var caster = casters[i];
if (!caster.enabled)
continue;
hitCaster = caster;
if(caster.Cast(position,
out ray,
out hitInfo,
out hitTarget,
this.checkTarget, this.ignoreTrigger))
{
return true;
}
}
return false;
}
public void TriggerEvent(InputEvent evt, InputTouch touch)
{
evt.Invoke(touch);
}
}
}