using UnityEngine; using System.Collections.Generic; using Lean.Common; namespace Lean.Touch { /// This class stores information about a single touch (or simulated touch). public class LeanFinger { /// This is the hardware ID of the finger. /// NOTE: Simulated fingers will use hardware ID -1 and -2. public int Index; /// This tells you how long this finger has been active (or inactive) in seconds. public float Age; /// Is this finger currently touching the screen? public bool Set; /// This tells you the 'Set' value of the last frame. public bool LastSet; /// Did this finger just tap the screen? public bool Tap; /// This tells you how many times this finger has been tapped. public int TapCount; /// Did this finger just swipe the screen? public bool Swipe; /// If this finger has been touching the screen for more than TapThreshold, this will be true. public bool Old; /// If this finger has been inactive for more than TapThreshold, this will be true. public bool Expired; /// This tells you the Pressure value last frame. public float LastPressure; /// This tells you the current pressure of this finger (NOTE: only some devices support this). public float Pressure; /// This tells you the 'ScreenPosition' value of this finger when it began touching the screen. public Vector2 StartScreenPosition; /// This tells you the last screen position of the finger. public Vector2 LastScreenPosition; /// This tells you the current screen position of the finger in pixels, where 0,0 = bottom left. public Vector2 ScreenPosition; /// This tells you if the current finger had 'IsOverGui' set to true when it began touching the screen. public bool StartedOverGui; /// Used to store position snapshots, enable RecordFingers in LeanTouch to use this. public List Snapshots = new List(1000); /// This will return true if this finger is currently touching the screen. public bool IsActive { get { return LeanTouch.Fingers.Contains(this); } } /// This will tell you how many seconds of snapshot footage is stored for this finger. public float SnapshotDuration { get { if (Snapshots.Count > 0) { return Age - Snapshots[0].Age; } return 0.0f; } } /// This will return true if the current finger is over any Unity GUI elements. public bool IsOverGui { get { return LeanTouch.PointOverGui(ScreenPosition); } } /// Did this finger begin touching the screen this frame? public bool Down { get { return Set == true && LastSet == false; } } /// Did the finger stop touching the screen this frame? public bool Up { get { return Set == false && LastSet == true; } } /// This will return how far in pixels the finger has moved since the last recorded snapshot. public Vector2 LastSnapshotScreenDelta { get { var snapshotCount = Snapshots.Count; if (snapshotCount > 0) { var snapshot = Snapshots[snapshotCount - 1]; if (snapshot != null) { return ScreenPosition - snapshot.ScreenPosition; } } return Vector2.zero; } } /// This returns a resolution-independent 'LastSnapshotScreenDelta' value. public Vector2 LastSnapshotScaledDelta { get { return LastSnapshotScreenDelta * LeanTouch.ScalingFactor; } } /// This will return how far in pixels the finger has moved since the last frame. public Vector2 ScreenDelta { get { return ScreenPosition - LastScreenPosition; } } /// This returns a resolution-independent 'ScreenDelta' value. public Vector2 ScaledDelta { get { return ScreenDelta * LeanTouch.ScalingFactor; } } /// This tells you how far this finger has moved since it began touching the screen. public Vector2 SwipeScreenDelta { get { return ScreenPosition - StartScreenPosition; } } /// This returns a resolution-independent 'SwipeScreenDelta' value. public Vector2 SwipeScaledDelta { get { return SwipeScreenDelta * LeanTouch.ScalingFactor; } } /// This returns a smooth point between the previous and current screen position based on a 0..1 progress value. public Vector2 GetSmoothScreenPosition(float t) { if (Snapshots.Count > 0 && Set == true) { var d = Snapshots[Mathf.Max(0, Snapshots.Count - 4)].ScreenPosition; var c = Snapshots[Mathf.Max(0, Snapshots.Count - 3)].ScreenPosition; var b = Snapshots[Mathf.Max(0, Snapshots.Count - 2)].ScreenPosition; var a = Snapshots[Mathf.Max(0, Snapshots.Count - 1)].ScreenPosition; return LeanHelper.Hermite(d, c, b, a, t); } return Vector2.LerpUnclamped(LastScreenPosition, ScreenPosition, t); } /// This returns the screen space distance between the 0 and 1 smooth screen positions. public float SmoothScreenPositionDelta { get { if (Snapshots.Count > 0 && Set == true) { var c = Snapshots[Mathf.Max(0, Snapshots.Count - 3)].ScreenPosition; var b = Snapshots[Mathf.Max(0, Snapshots.Count - 2)].ScreenPosition; return Vector2.Distance(c, b); } return Vector2.Distance(LastScreenPosition, ScreenPosition); } } /// This will return the ray of the finger's current position relative to the specified camera (none/null = Main Camera). public Ray GetRay(Camera camera = null) { // Make sure the camera exists camera = LeanHelper.GetCamera(camera); if (camera != null) { return camera.ScreenPointToRay(ScreenPosition); } else { Debug.LogError("Failed to find camera. Either tag your cameras MainCamera, or set one in this component."); } return default(Ray); } /// This will return the ray of the finger's start position relative to the specified camera (none/null = Main Camera). public Ray GetStartRay(Camera camera = null) { // Make sure the camera exists camera = LeanHelper.GetCamera(camera); if (camera != null) { return camera.ScreenPointToRay(StartScreenPosition); } else { Debug.LogError("Failed to find camera. Either tag your cameras MainCamera, or set one in this component."); } return default(Ray); } /// This will tell you how far the finger has moved in the past 'deltaTime' seconds. public Vector2 GetSnapshotScreenDelta(float deltaTime) { return ScreenPosition - GetSnapshotScreenPosition(Age - deltaTime); } /// This returns a resolution-independent 'GetSnapshotScreenDelta' value. public Vector2 GetSnapshotScaledDelta(float deltaTime) { return GetSnapshotScreenDelta(deltaTime) * LeanTouch.ScalingFactor; } /// This will return the recorded position of the current finger when it was at 'targetAge'. public Vector2 GetSnapshotScreenPosition(float targetAge) { var screenPosition = ScreenPosition; LeanSnapshot.TryGetScreenPosition(Snapshots, targetAge, ref screenPosition); return screenPosition; } /// This will return the recorded world of the current finger when it was at 'targetAge'. public Vector3 GetSnapshotWorldPosition(float targetAge, float distance, Camera camera = null) { // Make sure the camera exists camera = LeanHelper.GetCamera(camera); if (camera != null) { var screenPosition = GetSnapshotScreenPosition(targetAge); var point = new Vector3(screenPosition.x, screenPosition.y, distance); return camera.ScreenToWorldPoint(point); } else { Debug.LogError("Failed to find camera. Either tag your cameras MainCamera, or set one in this component."); } return default(Vector3); } /// This will return the angle between the finger and the reference point, relative to the screen. public float GetRadians(Vector2 referencePoint) { return Mathf.Atan2(ScreenPosition.x - referencePoint.x, ScreenPosition.y - referencePoint.y); } /// This will return the angle between the finger and the reference point, relative to the screen. public float GetDegrees(Vector2 referencePoint) { return GetRadians(referencePoint) * Mathf.Rad2Deg; } /// This will return the angle between the last finger position and the reference point, relative to the screen. public float GetLastRadians(Vector2 referencePoint) { return Mathf.Atan2(LastScreenPosition.x - referencePoint.x, LastScreenPosition.y - referencePoint.y); } /// This will return the angle between the last finger position and the reference point, relative to the screen. public float GetLastDegrees(Vector2 referencePoint) { return GetLastRadians(referencePoint) * Mathf.Rad2Deg; } /// This will return the delta angle between the last and current finger position relative to the reference point. public float GetDeltaRadians(Vector2 referencePoint) { return GetDeltaRadians(referencePoint, referencePoint); } /// This will return the delta angle between the last and current finger position relative to the reference point and the last reference point. public float GetDeltaRadians(Vector2 referencePoint, Vector2 lastReferencePoint) { var a = GetLastRadians(lastReferencePoint); var b = GetRadians(referencePoint); var d = Mathf.Repeat(a - b, Mathf.PI * 2.0f); if (d > Mathf.PI) { d -= Mathf.PI * 2.0f; } return d; } /// This will return the delta angle between the last and current finger position relative to the reference point. public float GetDeltaDegrees(Vector2 referencePoint) { return GetDeltaRadians(referencePoint, referencePoint) * Mathf.Rad2Deg; } /// This will return the delta angle between the last and current finger position relative to the reference point and the last reference point. public float GetDeltaDegrees(Vector2 referencePoint, Vector2 lastReferencePoint) { return GetDeltaRadians(referencePoint, lastReferencePoint) * Mathf.Rad2Deg; } /// This will return the distance between the finger and the reference point. public float GetScreenDistance(Vector2 point) { return Vector2.Distance(ScreenPosition, point); } /// This returns a resolution-independent 'GetScreenDistance' value. public float GetScaledDistance(Vector2 point) { return GetScreenDistance(point) * LeanTouch.ScalingFactor; } /// This will return the distance between the last finger and the reference point. public float GetLastScreenDistance(Vector2 point) { return Vector2.Distance(LastScreenPosition, point); } /// This returns a resolution-independent 'GetLastScreenDistance' value. public float GetLastScaledDistance(Vector2 point) { return GetLastScreenDistance(point) * LeanTouch.ScalingFactor; } /// This will return the distance between the start finger and the reference point. public float GetStartScreenDistance(Vector2 point) { return Vector2.Distance(StartScreenPosition, point); } /// This returns a resolution-independent 'GetStartScreenDistance' value. public float GetStartScaledDistance(Vector2 point) { return GetStartScreenDistance(point) * LeanTouch.ScalingFactor; } /// This will return the start world position of this finger based on the distance from the camera. public Vector3 GetStartWorldPosition(float distance, Camera camera = null) { // Make sure the camera exists camera = LeanHelper.GetCamera(camera); if (camera != null) { var point = new Vector3(StartScreenPosition.x, StartScreenPosition.y, distance); return camera.ScreenToWorldPoint(point); } else { Debug.LogError("Failed to find camera. Either tag your cameras MainCamera, or set one in this component."); } return default(Vector3); } /// This will return the last world position of this finger based on the distance from the camera. public Vector3 GetLastWorldPosition(float distance, Camera camera = null) { // Make sure the camera exists camera = LeanHelper.GetCamera(camera); if (camera != null) { var point = new Vector3(LastScreenPosition.x, LastScreenPosition.y, distance); return camera.ScreenToWorldPoint(point); } else { Debug.LogError("Failed to find camera. Either tag your cameras MainCamera, or set one in this component."); } return default(Vector3); } /// This will return the world position of this finger based on the distance from the camera. public Vector3 GetWorldPosition(float distance, Camera camera = null) { // Make sure the camera exists camera = LeanHelper.GetCamera(camera); if (camera != null) { var point = new Vector3(ScreenPosition.x, ScreenPosition.y, distance); return camera.ScreenToWorldPoint(point); } else { Debug.LogError("Failed to find camera. Either tag your cameras MainCamera, or set one in this component."); } return default(Vector3); } /// This will return the change in world position of this finger based on the distance from the camera. public Vector3 GetWorldDelta(float distance, Camera camera = null) { return GetWorldDelta(distance, distance, camera); } /// This will return the change in world position of this finger based on the last and current distance from the camera. public Vector3 GetWorldDelta(float lastDistance, float distance, Camera camera = null) { // Make sure the camera exists camera = LeanHelper.GetCamera(camera); if (camera != null) { return GetWorldPosition(distance, camera) - GetLastWorldPosition(lastDistance, camera); } else { Debug.LogError("Failed to find camera. Either tag your cameras MainCamera, or set one in this component."); } return default(Vector3); } /// This will clear all snapshots for this finger and pool them, count = -1 for all. public void ClearSnapshots(int count = -1) { // Clear old ones only? if (count > 0 && count <= Snapshots.Count) { for (var i = 0; i < count; i++) { LeanSnapshot.InactiveSnapshots.Add(Snapshots[i]); } Snapshots.RemoveRange(0, count); } // Clear all? else if (count < 0) { LeanSnapshot.InactiveSnapshots.AddRange(Snapshots); Snapshots.Clear(); } } /// Calling this will instantly store a snapshot of the current finger position. public void RecordSnapshot() { // Get an unused snapshot and set it up var snapshot = LeanSnapshot.Pop(); snapshot.Age = Age; snapshot.ScreenPosition = ScreenPosition; // Add to list Snapshots.Add(snapshot); } } }