diff --git a/Assets/Scenes/Test.unity b/Assets/Scenes/Test.unity index b9c2a6b1..7eed30de 100644 --- a/Assets/Scenes/Test.unity +++ b/Assets/Scenes/Test.unity @@ -294,12 +294,6 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 4 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!224 &1060448221 stripped -RectTransform: - m_CorrespondingSourceObject: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - m_PrefabInstance: {fileID: 9117638845534694547} - m_PrefabAsset: {fileID: 0} --- !u!1 &1079865532 GameObject: m_ObjectHideFlags: 0 @@ -343,6 +337,91 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 5 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1223993129 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1223993130} + - component: {fileID: 1223993132} + - component: {fileID: 1223993131} + - component: {fileID: 1223993133} + m_Layer: 5 + m_Name: RawImage + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1223993130 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1223993129} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1900454698} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 100, y: 100} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1223993131 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1223993129} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!222 &1223993132 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1223993129} + m_CullTransparentMesh: 0 +--- !u!114 &1223993133 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1223993129} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 17cb27f144f572748a0f161b829b3e2c, type: 3} + m_Name: + m_EditorClassIdentifier: + image: {fileID: 0} --- !u!1 &1362042230 GameObject: m_ObjectHideFlags: 0 @@ -479,7 +558,7 @@ RectTransform: m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 0, y: 0, z: 0} m_Children: - - {fileID: 1060448221} + - {fileID: 1900454698} m_Father: {fileID: 0} m_RootOrder: 3 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} @@ -496,6 +575,81 @@ CanvasRenderer: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1678571397} m_CullTransparentMesh: 0 +--- !u!1 &1900454697 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1900454698} + - component: {fileID: 1900454700} + - component: {fileID: 1900454699} + m_Layer: 5 + m_Name: Panel + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1900454698 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1900454697} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 1223993130} + m_Father: {fileID: 1678571401} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &1900454699 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1900454697} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.392} + m_RaycastTarget: 1 + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10907, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!222 &1900454700 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1900454697} + m_CullTransparentMesh: 0 --- !u!1 &1944211662 GameObject: m_ObjectHideFlags: 0 @@ -579,122 +733,3 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 0 m_LocalEulerAnglesHint: {x: 48.593002, y: -4.8190002, z: -6.4140005} ---- !u!1001 &9117638845534694547 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 1678571401} - m_Modifications: - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_Pivot.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_Pivot.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_RootOrder - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_AnchorMax.x - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_AnchorMin.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_AnchorMin.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_SizeDelta.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_SizeDelta.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_AnchoredPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_AnchoredPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165518, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 9117638846523165519, guid: f850039b33d2c7143b5bf186fd762e3a, - type: 3} - propertyPath: m_Name - value: CountDown - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: f850039b33d2c7143b5bf186fd762e3a, type: 3} diff --git a/Assets/Scripts/UI/Prefab/Panel/EditUserController.cs b/Assets/Scripts/UI/Prefab/Panel/EditUserController.cs index 93728daf..e25d08c9 100644 --- a/Assets/Scripts/UI/Prefab/Panel/EditUserController.cs +++ b/Assets/Scripts/UI/Prefab/Panel/EditUserController.cs @@ -77,6 +77,16 @@ public class EditUserController : PFUIPanel, INativeOnMobileImageSelect g1.color1 = Utils.HexToColorHtml("#353543"); g1.color2 = Utils.HexToColorHtml("#474759"); }); + TKPanRecognizer pan = new TKPanRecognizer(); + var delta = Vector3.zero; + pan.gestureRecognizedEvent += (r) => + { + delta = pan.deltaTranslation; + delta.x = 0; + delta.z = 0; + panel.transform.position += delta; + //Debug.Log("pan recognizer fired: " + image.transform.position); + }; #endif mID = panel.Find("IDNumber").Find("input").Find("Text").GetComponent(); mSexDropdown = panel.Find("SexDropdown").GetComponent(); diff --git a/Assets/TestTK.cs b/Assets/TestTK.cs new file mode 100644 index 00000000..d556d721 --- /dev/null +++ b/Assets/TestTK.cs @@ -0,0 +1,33 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class TestTK : MonoBehaviour +{ + public RawImage image; + private Vector3 delta = Vector3.zero; + + void Start() + { + image = GetComponent(); + TKPanRecognizer pan = new TKPanRecognizer(); + pan.gestureRecognizedEvent += (r) => + { + delta = pan.deltaTranslation; + delta.y = 0; + delta.z = 0; + image.transform.position += delta; + Debug.Log("pan recognizer fired: " + image.transform.position); + }; + TouchKit.addGestureRecognizer(pan); + + TKPinchRecognizer pinch = new TKPinchRecognizer(); + pinch.gestureRecognizedEvent += (r) => + { + image.transform.localScale += Vector3.one * pinch.deltaScale; + Debug.Log("pinch recognizer fired: " + r); + }; + TouchKit.addGestureRecognizer(pinch); + } +} diff --git a/Assets/TestTK.cs.meta b/Assets/TestTK.cs.meta new file mode 100644 index 00000000..fcbf8108 --- /dev/null +++ b/Assets/TestTK.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 17cb27f144f572748a0f161b829b3e2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TouchKit.meta b/Assets/TouchKit.meta new file mode 100644 index 00000000..dbade80f --- /dev/null +++ b/Assets/TouchKit.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7d5e93b6ca979f547b45cd3d5b09b609 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TouchKit/Gizmos.meta b/Assets/TouchKit/Gizmos.meta new file mode 100644 index 00000000..eb0e0d45 --- /dev/null +++ b/Assets/TouchKit/Gizmos.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a3e707925459f48489ed24ad464efc8a diff --git a/Assets/TouchKit/Gizmos/greenPoint.png b/Assets/TouchKit/Gizmos/greenPoint.png new file mode 100644 index 00000000..073bccc6 Binary files /dev/null and b/Assets/TouchKit/Gizmos/greenPoint.png differ diff --git a/Assets/TouchKit/Gizmos/greenPoint.png.meta b/Assets/TouchKit/Gizmos/greenPoint.png.meta new file mode 100644 index 00000000..3a9f4bfd --- /dev/null +++ b/Assets/TouchKit/Gizmos/greenPoint.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: b4b48a368ff3f41679810429e9f90886 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: -1 + buildTargetSettings: [] diff --git a/Assets/TouchKit/Gizmos/redPoint.png b/Assets/TouchKit/Gizmos/redPoint.png new file mode 100644 index 00000000..9ef8bfa9 Binary files /dev/null and b/Assets/TouchKit/Gizmos/redPoint.png differ diff --git a/Assets/TouchKit/Gizmos/redPoint.png.meta b/Assets/TouchKit/Gizmos/redPoint.png.meta new file mode 100644 index 00000000..055e8fee --- /dev/null +++ b/Assets/TouchKit/Gizmos/redPoint.png.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 7ab653de870f5429398f1093bd6ba312 +TextureImporter: + serializedVersion: 2 + mipmaps: + mipMapMode: 0 + enableMipMap: 1 + linearTexture: 0 + correctGamma: 0 + fadeOut: 0 + borderMipMap: 0 + mipMapFadeDistanceStart: 1 + mipMapFadeDistanceEnd: 3 + bumpmap: + convertToNormalMap: 0 + externalNormalMap: 0 + heightScale: .25 + normalMapFilter: 0 + isReadable: 0 + grayScaleToAlpha: 0 + generateCubemap: 0 + textureFormat: -1 + maxTextureSize: 1024 + textureSettings: + filterMode: -1 + aniso: -1 + mipBias: -1 + wrapMode: -1 + nPOTScale: 1 + lightmap: 0 + compressionQuality: 50 + textureType: -1 + buildTargetSettings: [] diff --git a/Assets/TouchKit/TouchKit.meta b/Assets/TouchKit/TouchKit.meta new file mode 100644 index 00000000..6d3091ed --- /dev/null +++ b/Assets/TouchKit/TouchKit.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 92b055eb506d543dc9424787fd626061 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKit/Editor.meta b/Assets/TouchKit/TouchKit/Editor.meta new file mode 100644 index 00000000..1b64cb84 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 34c845883c036418db85a57ce0664fe3 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKit/Editor/TouchKitEditor.cs b/Assets/TouchKit/TouchKit/Editor/TouchKitEditor.cs new file mode 100644 index 00000000..2b2929c5 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Editor/TouchKitEditor.cs @@ -0,0 +1,44 @@ +#if UNITY_EDITOR +using UnityEngine; +using UnityEditor; +using System.Collections; + + +[CustomEditor( typeof( TouchKit ) )] +public class TouchKitEditor : Editor +{ + private bool showDebug = true; + private string status = "Touch Debugging"; + + + public override void OnInspectorGUI() + { + DrawDefaultInspector(); + + showDebug = EditorGUILayout.Foldout( showDebug, status ); + if( showDebug ) + { + TouchKit touchKit = (TouchKit)target; + touchKit.drawDebugBoundaryFrames = EditorGUILayout.Toggle( "Draw boundary frames", touchKit.drawDebugBoundaryFrames ); + touchKit.drawTouches = EditorGUILayout.Toggle( "Draw touches", touchKit.drawTouches ); + touchKit.simulateTouches = EditorGUILayout.Toggle( "Simulate touches", touchKit.simulateTouches ); + + GUI.enabled = touchKit.simulateTouches; + if( GUI.enabled || true ) + { + var helpText = "Touches can be simulated in the editor or on the desktop with mouse clicks."; + if( touchKit.simulateMultitouch ) + helpText += "\nTo simulate a two-finger gesture, press and hold the left alt key and move your mouse around. Shift the touches by additionally holding down left shift."; + + EditorGUILayout.HelpBox( helpText, MessageType.Info, true ); + } + + touchKit.simulateMultitouch = EditorGUILayout.Toggle( "Simulate multitouch", touchKit.simulateMultitouch ); + } + + if( GUI.changed ) + EditorUtility.SetDirty( target ); + } + +} +#endif \ No newline at end of file diff --git a/Assets/TouchKit/TouchKit/Editor/TouchKitEditor.cs.meta b/Assets/TouchKit/TouchKit/Editor/TouchKitEditor.cs.meta new file mode 100644 index 00000000..46622fb2 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Editor/TouchKitEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6e5c8365f45374e259a591b8b76af04a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Helpers.meta b/Assets/TouchKit/TouchKit/Helpers.meta new file mode 100644 index 00000000..63fe5089 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Helpers.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: c88906649098c4a669eace1b1c825a02 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKit/Helpers/TKRect.cs b/Assets/TouchKit/TouchKit/Helpers/TKRect.cs new file mode 100644 index 00000000..e1fc3dcf --- /dev/null +++ b/Assets/TouchKit/TouchKit/Helpers/TKRect.cs @@ -0,0 +1,94 @@ +using UnityEngine; +using System.Collections; + + + +/// +/// replacement for the Unity Rect class that is TouchKit and resolution-aware. Creating one will automatically scale all values +/// if TouchKit autoScaleRectsAndDistances is true based on your designTimeResolution. +/// +/// Note the TKRects use the bottom-left as the origin. +/// +public struct TKRect +{ + public float x; + public float y; + public float width; + public float height; + + public float xMin { get { return x; } } + public float xMax { get { return x + width; } } + public float yMin { get { return y; } } + public float yMax { get { return y + height; } } + public Vector2 center { get { return new Vector2( x + ( width / 2f ), y + ( height / 2f ) ); } } + + + public TKRect( float x, float y, float width, float height ) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + updateRectWithRuntimeScaleModifier(); + } + + + public TKRect( float width, float height, Vector2 center ) + { + this.width = width; + this.height = height; + this.x = center.x - width / 2f; + this.y = center.y - height / 2f; + + updateRectWithRuntimeScaleModifier(); + } + + + private void updateRectWithRuntimeScaleModifier() + { + var multiplier = TouchKit.instance.runtimeScaleModifier; + + x *= multiplier.x; + y *= multiplier.y; + width = width * multiplier.x; + height = height * multiplier.y; + } + + + public TKRect copyWithExpansion( float allSidesExpansion ) + { + return copyWithExpansion( allSidesExpansion, allSidesExpansion ); + } + + + public TKRect copyWithExpansion( float xExpansion, float yExpansion ) + { + xExpansion *= TouchKit.instance.runtimeScaleModifier.x; + yExpansion *= TouchKit.instance.runtimeScaleModifier.y; + + var rect = new TKRect(); + rect.x = this.x - xExpansion; + rect.y = this.y - yExpansion; + rect.width = this.width + ( xExpansion * 2f ); + rect.height = this.height + ( yExpansion * 2f ); + + return rect; + } + + + public bool contains( Vector2 point ) + { + if( x <= point.x && y <= point.y && xMax >= point.x && yMax >= point.y ) + return true; + return false; + } + + + public override string ToString() + { + return string.Format( "TKRect: x: {0}, xMax: {1}, y: {2}, yMax: {3}, width: {4}, height: {5}, center: {6}", + x, xMax, y, yMax, width, height, center ); + } + +} diff --git a/Assets/TouchKit/TouchKit/Helpers/TKRect.cs.meta b/Assets/TouchKit/TouchKit/Helpers/TKRect.cs.meta new file mode 100644 index 00000000..00f0d072 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Helpers/TKRect.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4f68dd8df2e674a94939789235fb9b28 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Helpers/TKTouch.cs b/Assets/TouchKit/TouchKit/Helpers/TKTouch.cs new file mode 100644 index 00000000..bcf7ee61 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Helpers/TKTouch.cs @@ -0,0 +1,130 @@ +using UnityEngine; +using System.Collections; + + +public class TKTouch +{ + public readonly int fingerId; + public Vector2 position; + public Vector2 startPosition; + public Vector2 deltaPosition; + public float deltaTime; + public int tapCount; + public TouchPhase phase = TouchPhase.Ended; + + public Vector2 previousPosition + { + get { return position - deltaPosition; } + } + +#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + // used to track mouse movement and fake touches + private Vector2? _lastPosition; + private double _lastClickTime; + private double _multipleClickInterval = 0.2; +#endif + + + public TKTouch( int fingerId ) + { + // lock this TKTouch to the fingerId + this.fingerId = fingerId; + } + + public TKTouch populateWithTouch( Touch touch ) + { + position = touch.position; + deltaPosition = touch.deltaPosition; + deltaTime = touch.deltaTime; + tapCount = touch.tapCount; + + if (touch.phase== TouchPhase.Began) + { + startPosition = position; + } + + // canceled and ended are the same to us + if( touch.phase == TouchPhase.Canceled ) + phase = TouchPhase.Ended; + else + phase = touch.phase; + + return this; + } + +#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + public TKTouch populateWithPosition( Vector3 currentPosition, TouchPhase touchPhase ) + { + var currentPosition2d = new Vector2( currentPosition.x, currentPosition.y ); + + // if we have a lastMousePosition use it to get a delta + if( _lastPosition.HasValue ) + deltaPosition = currentPosition2d - _lastPosition.Value; + else + deltaPosition = new Vector2( 0, 0 ); + + switch( touchPhase ) + { + case TouchPhase.Began: + phase = TouchPhase.Began; + + // check for multiple clicks + if( Time.time < _lastClickTime + _multipleClickInterval ) + tapCount++; + else + tapCount = 1; + _lastPosition = currentPosition2d; + startPosition = currentPosition2d; + _lastClickTime = Time.time; + break; + case TouchPhase.Stationary: + case TouchPhase.Moved: + if( deltaPosition.sqrMagnitude == 0 ) + phase = TouchPhase.Stationary; + else + phase = TouchPhase.Moved; + + _lastPosition = currentPosition2d; + break; + case TouchPhase.Ended: + phase = TouchPhase.Ended; + _lastPosition = null; + break; + } + + position = currentPosition2d; + + return this; + } + + + public TKTouch populateFromMouse() + { + // do we have some input to work with? + if( Input.GetMouseButtonUp( 0 ) || Input.GetMouseButton( 0 ) ) + { + var phase = TouchPhase.Moved; + + // guard against down and up being called in the same frame + if( Input.GetMouseButtonDown( 0 ) && Input.GetMouseButtonUp( 0 ) ) + phase = TouchPhase.Canceled; + else if( Input.GetMouseButtonUp( 0 ) ) + phase = TouchPhase.Ended; + else if( Input.GetMouseButtonDown( 0 ) ) + phase = TouchPhase.Began; + + var currentMousePosition = new Vector2( Input.mousePosition.x, Input.mousePosition.y ); + this.populateWithPosition( currentMousePosition, phase ); + } + + return this; + } +#endif + + + public override string ToString() + { + return string.Format( "[TKTouch] fingerId: {0}, phase: {1}, position: {2}", fingerId, phase, position ); + } + +} \ No newline at end of file diff --git a/Assets/TouchKit/TouchKit/Helpers/TKTouch.cs.meta b/Assets/TouchKit/TouchKit/Helpers/TKTouch.cs.meta new file mode 100644 index 00000000..45773b39 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Helpers/TKTouch.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2defb83e5e57b48bfb27864a8ab5e134 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Helpers/TouchKitEditorSupport.cs b/Assets/TouchKit/TouchKit/Helpers/TouchKitEditorSupport.cs new file mode 100644 index 00000000..87a74172 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Helpers/TouchKitEditorSupport.cs @@ -0,0 +1,171 @@ +using UnityEngine; +using System.Collections; + +#if UNITY_EDITOR +/// +/// this only exists in the editor to assist with testing and simulating touches and keeping the main class clean +/// +public partial class TouchKit +{ + private Vector3? _simulatedMultitouchStartPosition; + private Vector3 _simulatedMousePosition; + private bool _hasActiveSimulatedTouch; + private bool _hasActiveSimulatedMultitouch; + private bool _hasUnityRemoteActive; + + + /// + /// returns true if mouse input should be processed as touch input. it will be true when the Unity Remote is not active. + /// + private bool shouldProcessMouseInput() + { + if( !simulateTouches ) + return false; + + // check to see if the Unity Remote is active + if( Input.touchCount > 0 ) + { + Debug.LogWarning( "disabling touch simulation because we detected a Unity Remote connected" ); + simulateTouches = false; + return false; + } + + // if enabled and alt is being held down we are simulating pinching + if( simulateMultitouch && ( _hasActiveSimulatedMultitouch || Input.GetKey( KeyCode.LeftAlt ) || Input.GetKeyUp( KeyCode.LeftAlt ) ) ) + { + if( Input.GetKeyDown( KeyCode.LeftAlt ) ) + { + _simulatedMultitouchStartPosition = Input.mousePosition; + } + else if( Input.GetKey( KeyCode.LeftShift ) ) + { + // calculate the last mouse position from the simulated position and shift the start position acordingly + var lastMousePosition = _simulatedMultitouchStartPosition.Value + ( _simulatedMultitouchStartPosition.Value - _simulatedMousePosition ); + var diff = Input.mousePosition - lastMousePosition; + _simulatedMultitouchStartPosition += diff; + } + + if( Input.GetKey( KeyCode.LeftAlt ) || Input.GetKeyUp( KeyCode.LeftAlt ) ) + { + var diff = new Vector3( Input.mousePosition.x - _simulatedMultitouchStartPosition.Value.x, Input.mousePosition.y - _simulatedMultitouchStartPosition.Value.y ); + _simulatedMousePosition = _simulatedMultitouchStartPosition.Value - diff; + } + + TouchPhase? touchPhase = null; + if( Input.GetKey( KeyCode.LeftAlt ) && Input.GetMouseButton( 0 ) ) + { + // if we haven't started yet, add a touch began, else move + if( !_hasActiveSimulatedMultitouch ) + { + _hasActiveSimulatedMultitouch = true; + touchPhase = TouchPhase.Began; + } + else + { + touchPhase = TouchPhase.Moved; + } + } + + if( ( Input.GetKeyUp( KeyCode.LeftAlt ) || Input.GetMouseButtonUp(0)) && _hasActiveSimulatedMultitouch ) + { + touchPhase = TouchPhase.Ended; + _hasActiveSimulatedMultitouch = false; + } + + + if( touchPhase.HasValue ) + { + // we need to set up a second touch + _liveTouches.Add( _touchCache[1].populateWithPosition( _simulatedMousePosition, touchPhase.Value ) ); + } + + if( Input.GetKeyUp( KeyCode.LeftAlt ) ) + { + _simulatedMultitouchStartPosition = null; + } + } + + _hasActiveSimulatedTouch = Input.GetMouseButton( 0 ); + + return true; + } + + + // this is for debugging only while in the editor + private void OnDrawGizmos() + { + if( _instance == null ) + return; + + if( drawTouches ) + { + // draw a green point for all active touches, including the touches from Unity remote + foreach( TKTouch touch in _touchCache ) + { + if( touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved || touch.phase == TouchPhase.Stationary ) + { + var touchPos = Camera.main.ScreenToWorldPoint( new Vector3( touch.position.x, touch.position.y, Camera.main.farClipPlane ) ); + Gizmos.DrawIcon( touchPos, "greenPoint.png", false ); + } + } + + if( _simulatedMultitouchStartPosition.HasValue && !_hasActiveSimulatedTouch ) + { + var mousePos = Camera.main.ScreenToWorldPoint( new Vector3( Input.mousePosition.x, Input.mousePosition.y, Camera.main.farClipPlane ) ); + Gizmos.DrawIcon( mousePos, "redPoint.png", false ); + + var simulatedPos = Camera.main.ScreenToWorldPoint( new Vector3( _simulatedMousePosition.x, _simulatedMousePosition.y, Camera.main.farClipPlane ) ); + Gizmos.DrawIcon( simulatedPos, "redPoint.png", false ); + } + } + + if( drawDebugBoundaryFrames ) + { + var colors = new Color[] + { + Color.red, + Color.cyan, + Color.red, + Color.magenta, + Color.yellow + }; + int i = 0; + + foreach( var r in _gestureRecognizers ) + { + if( r.boundaryFrame.HasValue ) + { + debugDrawRect( r.boundaryFrame.Value, colors [i] ); + if( ++i >= colors.Length ) + i = 0; + } + } + } + } + + + private void debugDrawRect( TKRect rect, Color color ) + { + var bl = new Vector3( rect.xMin, rect.yMin, 0 ); + var br = new Vector3( rect.xMax, rect.yMin, 0 ); + var tl = new Vector3( rect.xMin, rect.yMax, 0 ); + var tr = new Vector3( rect.xMax, rect.yMax, 0 ); + + bl = Camera.main.ScreenToWorldPoint( new Vector3( bl.x, bl.y, Camera.main.farClipPlane ) ); + br = Camera.main.ScreenToWorldPoint( new Vector3( br.x, br.y, Camera.main.farClipPlane ) ); + tl = Camera.main.ScreenToWorldPoint( new Vector3( tl.x, tl.y, Camera.main.farClipPlane ) ); + tr = Camera.main.ScreenToWorldPoint( new Vector3( tr.x, tr.y, Camera.main.farClipPlane ) ); + + // draw four sides + Debug.DrawLine( bl, br, color ); + Debug.DrawLine( br, tr, color ); + Debug.DrawLine( tr, tl, color ); + Debug.DrawLine( tl, bl, color ); + + // make an "x" at the midpoint + Debug.DrawLine( tl, br, color ); + Debug.DrawLine( bl, tr, color ); + } + +} +#endif \ No newline at end of file diff --git a/Assets/TouchKit/TouchKit/Helpers/TouchKitEditorSupport.cs.meta b/Assets/TouchKit/TouchKit/Helpers/TouchKitEditorSupport.cs.meta new file mode 100644 index 00000000..ef8e46a7 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Helpers/TouchKitEditorSupport.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1f6cfc9c43424c2eaafa3f02ee2fb90 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers.meta b/Assets/TouchKit/TouchKit/Recognizers.meta new file mode 100644 index 00000000..4e1bd950 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: c43f7b533c50c424fbbfc3ea8d40548e +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKAbstractGestureRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKAbstractGestureRecognizer.cs new file mode 100644 index 00000000..d3ff05ba --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKAbstractGestureRecognizer.cs @@ -0,0 +1,288 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + + +public enum TKGestureRecognizerState +{ + Possible, // we havent started yet and we are still listening + Began, // we have started and latched at least one finger + FailedOrEnded, // no go. failed to recognize or we are done recognizing + RecognizedAndStillRecognizing, // this will fire the state changed event and allow a gesture to continue to recognize. useful for continuous gestures + Recognized // successfully recognized and we are not a continuous recognizer +} + + +public abstract class TKAbstractGestureRecognizer : IComparable +{ + public bool enabled = true; + + /// + /// frame that the touch must be within to be recognized. null means full screen. note that Unity's origin is the bottom left + /// + public TKRect? boundaryFrame = null; + + /// + /// zIndex of touch input. 0 by default. if a zIndex of greater than 0 uses a touch in touchesBegan it will not be passed to any other recognizers. + /// useful if you have some full screen recognizers and you want to overlay a button/control + /// + public uint zIndex = 0; + + private TKGestureRecognizerState _state = TKGestureRecognizerState.Possible; + public TKGestureRecognizerState state + { + get { return _state; } + set + { + _state = value; + + if( _state == TKGestureRecognizerState.Recognized || _state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + fireRecognizedEvent(); + + if( _state == TKGestureRecognizerState.Recognized || _state == TKGestureRecognizerState.FailedOrEnded ) + reset(); + } + } + + + /// + /// when true, touchesMoved will be called for ALL touches. By default, only the touches + /// a recognizer is tracking (from touchesBegan) will be sent. + /// + protected bool alwaysSendTouchesMoved = false; + + /// + /// stores all the touches we are currently tracking + /// + protected List _trackingTouches = new List(); + + /// + /// The subset of touches being tracked that is applicable to the current recognizer. This is kept around to avoid allocations at runtime. + /// + private List _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer = new List(); + + /// + /// stores whether we sent any of the phases to the recognizer. This is to avoid sending a phase twice in one frame. + /// + private bool _sentTouchesBegan; + private bool _sentTouchesMoved; + private bool _sentTouchesEnded; + + /// + /// checks to see if the touch is currently being tracked by the recognizer + /// + protected bool isTrackingTouch( TKTouch t ) + { + return _trackingTouches.Contains( t ); + } + + + /// + /// checks to see if any of the touches are currently being tracked by the recognizer + /// + protected bool isTrackingAnyTouch( List touches ) + { + for( int i = 0; i < touches.Count; i++ ) + { + if( _trackingTouches.Contains( touches[i] ) ) + return true; + } + + return false; + } + + + /// + /// populates the _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer with only the touches currently being tracked by the recognizer. + /// returns true if there are any touches being tracked + /// + private bool populateSubsetOfTouchesBeingTracked( List touches ) + { + _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer.Clear(); + + for( int i = 0; i < touches.Count; i++ ) + { + if( alwaysSendTouchesMoved || isTrackingTouch( touches[i] ) ) + _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer.Add( touches[i] ); + } + + return _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer.Count > 0; + } + + + private bool shouldAttemptToRecognize + { + get + { + return ( enabled && state != TKGestureRecognizerState.FailedOrEnded && state != TKGestureRecognizerState.Recognized ); + } + } + + + #region Public API + + internal void recognizeTouches( List touches ) + { + if( !shouldAttemptToRecognize ) + return; + + // reset our state to avoid sending any phase more than once + _sentTouchesBegan = _sentTouchesMoved = _sentTouchesEnded = false; + + // we loop backwards because the Began phase could end up removing a touch + for( var i = touches.Count - 1; i >= 0; i-- ) + { + var touch = touches[i]; + switch( touch.phase ) + { + case TouchPhase.Began: + { + // only send touches began once and ensure that the touch is in the boundaryFrame if applicable + if( !_sentTouchesBegan && isTouchWithinBoundaryFrame( touches[i] ) ) + { + // if touchesBegan returns true and we have a zIndex greater than 0 we remove the touches with a phase of Began + if( touchesBegan( touches ) && zIndex > 0 ) + { + // if we remove more than one touch we have to be careful with our loop and make sure to decrement i appropriately + var removedTouches = 0; + for( var j = touches.Count - 1; j >= 0; j-- ) + { + if( touches[j].phase == TouchPhase.Began ) + { + touches.RemoveAt( j ); + removedTouches++; + } + } + + // if we removed more than 1 touch decrement i for each additional touch removed + if( removedTouches > 0 ) + i -= ( removedTouches - 1 ); + } + _sentTouchesBegan = true; + } + break; + } + case TouchPhase.Moved: + { + // limit touches sent to those that are being tracked + if( !_sentTouchesMoved && populateSubsetOfTouchesBeingTracked( touches ) && _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer.Contains( touch ) ) + { + touchesMoved( _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer ); + _sentTouchesMoved = true; + } + break; + } + case TouchPhase.Ended: + case TouchPhase.Canceled: + { + // limit touches sent to those that are being tracked + if( !_sentTouchesEnded && populateSubsetOfTouchesBeingTracked( touches ) && _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer.Contains( touch ) ) + { + touchesEnded( _subsetOfTouchesBeingTrackedApplicableToCurrentRecognizer ); + _sentTouchesEnded = true; + } + break; + } + } + } + } + + + internal void reset() + { + _state = TKGestureRecognizerState.Possible; + _trackingTouches.Clear(); + } + + + internal bool isTouchWithinBoundaryFrame( TKTouch touch ) + { + return !boundaryFrame.HasValue || boundaryFrame.Value.contains( touch.position ); + } + + + /// + /// returns the location of the touches. If there are multiple touches this will return the centroid of the location. + /// + public Vector2 touchLocation() + { + var x = 0f; + var y = 0f; + var k = 0f; + + for( var i = 0; i < _trackingTouches.Count; i++ ) + { + x += _trackingTouches[i].position.x; + y += _trackingTouches[i].position.y; + k++; + } + + if( k > 0 ) + return new Vector2( x / k, y / k ); + else + return Vector2.zero; + } + + /// + /// returns the start location of the touches. If there are multiple touches this will return the centroid of the location. + /// + public Vector2 startTouchLocation() + { + var x = 0f; + var y = 0f; + var k = 0f; + + for( var i = 0; i < _trackingTouches.Count; i++ ) + { + x += _trackingTouches[i].startPosition.x; + y += _trackingTouches[i].startPosition.y; + k++; + } + + if( k > 0 ) + return new Vector2( x / k, y / k ); + else + return Vector2.zero; + } + + /// + /// return true if a touch was used, false if none were. this is used by any recognizers that should swallow touches if on a higher than 0 zIndex + /// + internal virtual bool touchesBegan( List touches ) + { + return false; + } + + + internal virtual void touchesMoved( List touches ) + {} + + + internal virtual void touchesEnded( List touches ) + {} + + + internal abstract void fireRecognizedEvent(); + + #endregion + + + #region IComparable and ToString implementation + + public int CompareTo( TKAbstractGestureRecognizer other ) + { + return zIndex.CompareTo( other.zIndex ); + } + + + + + public override string ToString() + { + return string.Format( "[{0}] state: {1}, location: {2}, zIndex: {3}", this.GetType(), state, touchLocation(), zIndex ); + } + + #endregion +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKAbstractGestureRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKAbstractGestureRecognizer.cs.meta new file mode 100644 index 00000000..ec5d9960 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKAbstractGestureRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5f52cf2673474a919f25105431aaca6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKAngleSwipeRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKAngleSwipeRecognizer.cs new file mode 100644 index 00000000..4c268776 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKAngleSwipeRecognizer.cs @@ -0,0 +1,174 @@ +using UnityEngine; +using System; +using System.Collections.Generic; + +public class TKAngleSwipeRecognizer : TKAbstractGestureRecognizer +{ + + public event Action gestureRecognizedEvent; + + private struct AngleListener + { + public float Varience; + public Vector2 Direction; + public Action Action; + + public AngleListener (Vector2 direction, float varience, Action action) : this () + { + Varience = varience; + Direction = direction; + Action = action; + } + } + + private List _angleRecognizedEvents = new List (); + + public float timeToSwipe = 0.5f; + + public float swipeVelocity { get; private set; } + + public float swipeAngle { get; private set; } + + public Vector2 swipeVelVector { get; private set; } + + public float minimumDistance = 2f; + + // swipe state info + private Vector2 _startPoint; + private Vector2 _endPoint; + private float _startTime; + + public Vector2 startPoint { + get { return this._startPoint; } + } + + public Vector2 endPoint { + get { return this._endPoint; } + } + + public TKAngleSwipeRecognizer () : this (2f) + { + } + + public TKAngleSwipeRecognizer (float minimumDistanceCm) + { + minimumDistance = minimumDistanceCm; + } + + public void addAngleRecogizedEvents (Action action, Vector2 direction, float angleVarience) + { + _angleRecognizedEvents.Add (new AngleListener (direction, angleVarience, action)); + } + + public void removeAngleRecognizedEvents (Action action) + { + _angleRecognizedEvents.RemoveAll ( + (AngleListener listener) => { + return listener.Action == action; + }); + } + + public void removeAllAngleRecongnizedEvents () + { + _angleRecognizedEvents.Clear (); + } + + public void fireAngleRecognizedEvents () + { + for (int i = 0, length = _angleRecognizedEvents.Count; i < length; i++) + { + var angleEvent = _angleRecognizedEvents [i]; + if (angleEvent.Varience > Vector2.Angle (angleEvent.Direction, swipeVelVector)) + { + angleEvent.Action (this); + } + } + } + + private bool checkForSwipeCompletion (TKTouch touch) + { + // if we have a time stipulation and we exceeded it stop listening for swipes + if (timeToSwipe > 0.0f && (Time.time - _startTime) > timeToSwipe) + { + state = TKGestureRecognizerState.FailedOrEnded; + return false; + } + + // Grab the total distance moved in both directions + var xDeltaAbsCm = Mathf.Abs (_startPoint.x - touch.position.x) / TouchKit.instance.ScreenPixelsPerCm; + var yDeltaAbsCm = Mathf.Abs (_startPoint.y - touch.position.y) / TouchKit.instance.ScreenPixelsPerCm; + + _endPoint = touch.position; + + // Get the velocity + swipeVelocity = Mathf.Sqrt (xDeltaAbsCm * xDeltaAbsCm + yDeltaAbsCm * yDeltaAbsCm); + + // Calculate the movement vector + var displacement = endPoint - startPoint; + // Calculate the angle with respect to the x axis + swipeAngle = Mathf.Rad2Deg * Mathf.Atan2 (displacement.y, displacement.x); + // Get it between 0 to 360 + if (swipeAngle < 0) + { + swipeAngle += 360; + } + + swipeVelVector = _endPoint - _startPoint; + + // If we have enough distance, then return true + if (swipeVelocity > minimumDistance) + { + return true; + } + + return false; + } + + + internal override void fireRecognizedEvent () + { + if (gestureRecognizedEvent != null) + { + gestureRecognizedEvent (this); + } + fireAngleRecognizedEvents (); + } + + + internal override bool touchesBegan (List touches) + { + if (state == TKGestureRecognizerState.Possible) + { + _startPoint = touches [0].position; + _startTime = Time.time; + _trackingTouches.Add (touches [0]); + + state = TKGestureRecognizerState.Began; + } + return false; + } + + + internal override void touchesMoved (List touches) + { + if (state == TKGestureRecognizerState.Began) + { + if (checkForSwipeCompletion (touches [0])) + { + state = TKGestureRecognizerState.Recognized; + } + } + } + + + internal override void touchesEnded (List touches) + { + state = TKGestureRecognizerState.FailedOrEnded; + } + + public override string ToString () + { + return string.Format ("{0}, velocity: {1}, angle: {2}, start point: {3}, end point: {4}", + base.ToString (), swipeVelocity, swipeAngle, startPoint, endPoint); + } +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKAngleSwipeRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKAngleSwipeRecognizer.cs.meta new file mode 100644 index 00000000..3773b20f --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKAngleSwipeRecognizer.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 3c11e6452bbdb4506bba74590e0ea981 +timeCreated: 1461834236 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKAnyTouchRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKAnyTouchRecognizer.cs new file mode 100644 index 00000000..5606ed40 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKAnyTouchRecognizer.cs @@ -0,0 +1,113 @@ +using UnityEngine; +using System; +using System.Collections.Generic; + + +public class TKAnyTouchRecognizer : TKAbstractGestureRecognizer +{ + public event Action onEnteredEvent; + public event Action onExitedEvent; + + + /// + /// the contstructor ensures we have a frame to work with + /// + public TKAnyTouchRecognizer( TKRect frame ) + { + alwaysSendTouchesMoved = true; + boundaryFrame = frame; + } + + + void onTouchEntered() + { + // fire the event if this is the first touch we are tracking + if( _trackingTouches.Count == 1 && onEnteredEvent != null ) + onEnteredEvent( this ); + } + + + void onTouchExited() + { + if( _trackingTouches.Count == 0 && onExitedEvent != null ) + onExitedEvent( this ); + } + + + #region TKAbstractGestureRecognizer + + // we do nothing here. all events will be handled internally + internal override void fireRecognizedEvent() {} + + + internal override bool touchesBegan( List touches ) + { + // grab the first touch that begins on us + if( state == TKGestureRecognizerState.Possible ) + { + for( int i = 0; i < touches.Count; i++ ) + { + // only add touches in the Began phase + if( touches[i].phase == TouchPhase.Began ) + { + _trackingTouches.Add( touches[i] ); + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + onTouchEntered(); + + return true; + } + } + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + for( int i = 0; i < touches.Count; i++ ) + { + // check to see if the touch is in our frame + var isTouchInFrame = isTouchWithinBoundaryFrame( touches[i] ); + + // are we already tracking this touch? + var isTrackingTouch = _trackingTouches.Contains( touches[i] ); + + // if we are tracking the touch and it is in frame we do nothing more + if( isTrackingTouch && isTouchInFrame ) + continue; + + // if we are not tracking the touch and it is in our frame start tracking it + if( !isTrackingTouch && isTouchInFrame ) + { + _trackingTouches.Add( touches[i] ); + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + onTouchEntered(); + } + // if we are tracking the touch and it exited the frame fire the onExitedEvent + else if( isTrackingTouch && !isTouchInFrame ) + { + _trackingTouches.Remove( touches[i] ); + state = TKGestureRecognizerState.FailedOrEnded; + onTouchExited(); + } + } + } + + + internal override void touchesEnded( List touches ) + { + for( int i = 0; i < touches.Count; i++ ) + { + if( touches[i].phase == TouchPhase.Ended && _trackingTouches.Contains( touches[i] ) ) + { + _trackingTouches.Remove( touches[i] ); + state = TKGestureRecognizerState.FailedOrEnded; + onTouchExited(); + } + } + } + + #endregion + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKAnyTouchRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKAnyTouchRecognizer.cs.meta new file mode 100644 index 00000000..5c974a06 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKAnyTouchRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b7aa8925dea2045e3be6e6676b65f7ac +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKButtonRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKButtonRecognizer.cs new file mode 100644 index 00000000..27ea7af8 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKButtonRecognizer.cs @@ -0,0 +1,152 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + + +public class TKButtonRecognizer : TKAbstractGestureRecognizer +{ + public event Action onSelectedEvent; + public event Action onDeselectedEvent; + public event Action onTouchUpInsideEvent; + + private TKRect _defaultFrame; + private TKRect _highlightedFrame; + + + /* State Definitions + * Began: a touch started out on the button but has moved off. We still track it in case it comes back on the button + * RecognizedAndStillRecognizing: a touch is currently down on the button + * Recognized: + */ + + #region Constructors + + /// + /// the constructors ensure we have a frame to work with for button recognizers + /// + public TKButtonRecognizer( TKRect defaultFrame ) : this( defaultFrame, 40f ) + {} + + + public TKButtonRecognizer( TKRect defaultFrame, float highlightedExpansion ) : this( defaultFrame, defaultFrame.copyWithExpansion( highlightedExpansion ) ) + {} + + + public TKButtonRecognizer( TKRect defaultFrame, TKRect highlightedFrame ) + { + _defaultFrame = defaultFrame; + _highlightedFrame = highlightedFrame; + boundaryFrame = _defaultFrame; + } + + #endregion + + + #region Button methods. Subclasses can override these or you can skip subclassing and just listen to the events + + /// + /// called when a touch has began on the button or reentered the frame + /// + protected virtual void onSelected() + { + // while selected, we use a highlighted frame to allow the touch to move a bit and still remain selected + boundaryFrame = _highlightedFrame; + + if( onSelectedEvent != null ) + onSelectedEvent( this ); + } + + + /// + /// called when a touch ends (if the button was already highlighted) or if a tracked touch exits the highlighted frame + /// + protected virtual void onDeselected() + { + if( onDeselectedEvent != null ) + onDeselectedEvent( this ); + } + + + /// + /// called if a tracked touch ends while the button is highlighted + /// + protected virtual void onTouchUpInside() + { + if( onTouchUpInsideEvent != null ) + onTouchUpInsideEvent( this ); + } + + #endregion + + + #region TKAbstractGestureRecognizer + + // we do nothing here. all events will be handled internally + internal override void fireRecognizedEvent() {} + + + internal override bool touchesBegan( List touches ) + { + // grab the first touch that begins on us + if( state == TKGestureRecognizerState.Possible ) + { + for( int i = 0; i < touches.Count; i++ ) + { + // only add touches in the Began phase + if( touches[i].phase == TouchPhase.Began ) + { + _trackingTouches.Add( touches[i] ); + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + onSelected(); + + return true; + } + } + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + for( int i = 0; i < touches.Count; i++ ) + { + if( touches[i].phase == TouchPhase.Stationary ) + { + // check to see if the touch is still in our frame + var isTouchInFrame = isTouchWithinBoundaryFrame( touches[i] ); + + // if we are in the Began phase than we should switch to RecognizedAndStillRecognizing (highlighted) if the touch is in our frame + if( state == TKGestureRecognizerState.Began && isTouchInFrame ) + { + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + onSelected(); + } + else if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing && !isTouchInFrame ) // if the touch exits the frame and we were highlighted deselect now + { + state = TKGestureRecognizerState.FailedOrEnded; + onDeselected(); + } + } + } + } + + + internal override void touchesEnded( List touches ) + { + // if we were previously highlighted (RecognizedAndStillRecognizing) we have an official touch + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + onTouchUpInside(); + + // reset the boundary frame + boundaryFrame = _defaultFrame; + + state = TKGestureRecognizerState.FailedOrEnded; + } + + #endregion + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKButtonRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKButtonRecognizer.cs.meta new file mode 100644 index 00000000..666c2f85 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKButtonRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e4f7acc174154eb899d479350230e1c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKCurveRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKCurveRecognizer.cs new file mode 100644 index 00000000..f8b671e3 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKCurveRecognizer.cs @@ -0,0 +1,155 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + +public class TKCurveRecognizer : TKAbstractGestureRecognizer +{ + public event Action gestureRecognizedEvent; + public event Action gestureCompleteEvent; + + public float reportRotationStep = 20f; //how much rotation (degrees) is needed for the recognized event to fire + public float squareDistance = 10f; //squared distance of touhes being evaluated + public float maxSharpnes = 50f; //maximum angle (degrees) a touch is allowed to change direction of movement + + public int minimumNumberOfTouches = 1; + public int maximumNumberOfTouches = 2; + + //should be read only + public float deltaRotation = 0f; //rotation since last reported + + private Vector2 _previousLocation; + private Vector2 _deltaTranslation;//direction vector from previous to current location (current location being the last location far enough from the previous one) + private Vector2 _previousDeltaTranslation;//last direction + + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + + internal override bool touchesBegan( List touches ) + { + // add new or additional touches to gesture (allows for two or more touches to be added or removed without ending the pan gesture) + if( state == TKGestureRecognizerState.Possible || + ( ( state == TKGestureRecognizerState.Began || state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) && _trackingTouches.Count < maximumNumberOfTouches ) ) + { + for( int i = 0; i < touches.Count; i++ ) + { + // only add touches in the Began phase + if( touches[i].phase == TouchPhase.Began ) + { + _trackingTouches.Add( touches[i] ); + + if( _trackingTouches.Count == maximumNumberOfTouches ) + break; + } + } // end for + + if( _trackingTouches.Count >= minimumNumberOfTouches ) + { + _previousLocation = touchLocation(); + if( state != TKGestureRecognizerState.RecognizedAndStillRecognizing ){ + //initialize values, but stay in Possible state. use Began only when there's enough data + state = TKGestureRecognizerState.Possible; + deltaRotation = 0f; + _deltaTranslation = Vector2.zero; + _previousDeltaTranslation = Vector2.zero; + } + } + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + if( state == TKGestureRecognizerState.Possible ){ + //previous delta translation hasn't been set yet, need another itteration + + Vector2 currentLocation = touchLocation(); + Vector2 delta = currentLocation - _previousLocation; + _deltaTranslation = delta; + _previousLocation = currentLocation; + _previousDeltaTranslation = _deltaTranslation; + + state = TKGestureRecognizerState.Began; //got enough data to begin recognizing in next move + } + else if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing || state == TKGestureRecognizerState.Began ) + { + var currentLocation = touchLocation(); + + var delta = currentLocation - _previousLocation; + if( delta.sqrMagnitude >= 10f ) + { + var a = Vector2.Angle( _previousDeltaTranslation, delta ); + + if( a > maxSharpnes ) + { + Debug.Log( "Curve is to sharp: " + a + " max sharpnes set to:" + maxSharpnes ); + state = TKGestureRecognizerState.FailedOrEnded; //calls reset + } + else + { + _deltaTranslation = delta; + + float crossZ = Vector3.Cross( _previousDeltaTranslation, delta ).z;// / (_previousDeltaTranslation.magnitude * delta.magnitude); + if( crossZ > 0f ) + deltaRotation -= a; + else + deltaRotation += a; + + if( Mathf.Abs ( deltaRotation) >= reportRotationStep ) + { + //if total rotation changed enough: recognize and reset total rotation + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; // fires recognized event + deltaRotation = 0f;//reset total rotation + } + _previousLocation = currentLocation; + _previousDeltaTranslation = _deltaTranslation; + + } + } + + } + } + + + internal override void touchesEnded( List touches ) + { + // remove any completed touches + for( int i = 0; i < touches.Count; i++ ) + { + if( touches[i].phase == TouchPhase.Ended ) + _trackingTouches.Remove( touches[i] ); + } + + // if we still have a touch left continue. no touches means its time to reset + if( _trackingTouches.Count >= minimumNumberOfTouches ) + { + _previousLocation = touchLocation(); + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; //fires recognized event + } + else + { + // if we had previously been recognizing fire our complete event + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + { + if( gestureCompleteEvent != null ) + gestureCompleteEvent( this ); + } + state = TKGestureRecognizerState.FailedOrEnded; //calls reset + } + } + + + public override string ToString() + { + return string.Format( "[{0}] state: {1}, trans: {2}, lastTrans: {3}, totalRot: {4}", this.GetType(), state, _deltaTranslation, _previousDeltaTranslation, deltaRotation ); + } + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKCurveRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKCurveRecognizer.cs.meta new file mode 100644 index 00000000..03560b92 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKCurveRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: daf4d976dc3d0492081da0f1b65c25b2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKLongPressRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKLongPressRecognizer.cs new file mode 100644 index 00000000..b5aab435 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKLongPressRecognizer.cs @@ -0,0 +1,112 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + + +/// +/// detects a long press. The gesture is considered recognized when a touch has been down for minimumPressDuration and if it has moved less than allowableMovement +/// +public class TKLongPressRecognizer : TKAbstractGestureRecognizer +{ + public event Action gestureRecognizedEvent; + public event Action gestureCompleteEvent; // fired when after a successful long press the finger is lifted + + public float minimumPressDuration = 0.5f; + public int requiredTouchesCount = -1; + public float allowableMovementCm = 1f; + + Vector2 _beginLocation; + bool _waiting; + + + + public TKLongPressRecognizer() + {} + + + public TKLongPressRecognizer( float minimumPressDuration, float allowableMovement, int requiredTouchesCount ) + { + this.minimumPressDuration = minimumPressDuration; + this.allowableMovementCm = allowableMovement; + this.requiredTouchesCount = requiredTouchesCount; + } + + + IEnumerator beginGesture() + { + var endTime = Time.time + minimumPressDuration; + + // wait for our time to elapse or to be cancelled + while( _waiting && Time.time < endTime ) + yield return null; + + // if our time elapsed it means we were not cancelled + if( Time.time >= endTime ) + { + if( state == TKGestureRecognizerState.Began ) + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + + _waiting = false; + } + + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + + internal override bool touchesBegan( List touches ) + { + if (!_waiting && state == TKGestureRecognizerState.Possible && (requiredTouchesCount == -1 || touches.Count == requiredTouchesCount)) + { + _beginLocation = touches[0].position; + _waiting = true; + + TouchKit.instance.StartCoroutine( beginGesture() ); + _trackingTouches.Add(touches[0]); + state = TKGestureRecognizerState.Began; + } + else if (requiredTouchesCount != -1) + { + _waiting = false; + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + if( state == TKGestureRecognizerState.Began || state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + { + // did we move too far? + var moveDistance = Vector2.Distance(touches[0].position, _beginLocation) / TouchKit.instance.ScreenPixelsPerCm; + if (moveDistance > allowableMovementCm) + { + // fire the complete event if we had previously recognized a long press + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing && gestureCompleteEvent != null ) + gestureCompleteEvent( this ); + + state = TKGestureRecognizerState.FailedOrEnded; + _waiting = false; + } + } + } + + + internal override void touchesEnded( List touches ) + { + // fire the complete event if we had previously recognized a long press + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing && gestureCompleteEvent != null ) + gestureCompleteEvent( this ); + + state = TKGestureRecognizerState.FailedOrEnded; + _waiting = false; + } + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKLongPressRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKLongPressRecognizer.cs.meta new file mode 100644 index 00000000..60dc035e --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKLongPressRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1116f36a0f51547ab8db2bcc051d3662 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKOneFingerRotationRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKOneFingerRotationRecognizer.cs new file mode 100644 index 00000000..17977b36 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKOneFingerRotationRecognizer.cs @@ -0,0 +1,68 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + + +/// +/// detects a rotation around an object with a single finger. The target objects position must be provided in screen coordinates. +/// +public class TKOneFingerRotationRecognizer : TKRotationRecognizer +{ + public new event Action gestureRecognizedEvent; + public new event Action gestureCompleteEvent; + + /// + /// this should be the center point in screen coordinates of the object that is being rotated + /// + public Vector2 targetPosition; + + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + + internal override bool touchesBegan( List touches ) + { + if( state == TKGestureRecognizerState.Possible ) + { + _trackingTouches.Add( touches[0] ); + + deltaRotation = 0; + _previousRotation = angleBetweenPoints( targetPosition, _trackingTouches[0].position ); + state = TKGestureRecognizerState.Began; + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing || state == TKGestureRecognizerState.Began ) + { + var currentRotation = angleBetweenPoints( targetPosition, _trackingTouches[0].position ); + deltaRotation = Mathf.DeltaAngle( currentRotation, _previousRotation ); + _previousRotation = currentRotation; + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + } + + + internal override void touchesEnded( List touches ) + { + // if we had previously been recognizing fire our complete event + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + { + if( gestureCompleteEvent != null ) + gestureCompleteEvent( this ); + } + + state = TKGestureRecognizerState.FailedOrEnded; + } + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKOneFingerRotationRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKOneFingerRotationRecognizer.cs.meta new file mode 100644 index 00000000..9aeb2d68 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKOneFingerRotationRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2924e17256fe946bcad4a3f8d5a8abcc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKPanRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKPanRecognizer.cs new file mode 100644 index 00000000..f5bdcb15 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKPanRecognizer.cs @@ -0,0 +1,160 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + + +public class TKPanRecognizer : TKAbstractGestureRecognizer +{ + public event Action gestureRecognizedEvent; + public event Action gestureCompleteEvent; + + public Vector2 deltaTranslation; + public float deltaTranslationCm; + public int minimumNumberOfTouches = 1; + public int maximumNumberOfTouches = 2; + + private float totalDeltaMovementInCm = 0f; + private Vector2 _previousLocation; + private float _minDistanceToPanCm; + private Vector2 _startPoint; + private Vector2 _endPoint; + + + public Vector2 startPoint + { + get + { + return this._startPoint; + } + } + + public Vector2 endPoint + { + get + { + return this._endPoint; + } + } + + + public TKPanRecognizer( float minPanDistanceCm = 0.5f ) + { + _minDistanceToPanCm = minPanDistanceCm; + } + + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + + internal override bool touchesBegan( List touches ) + { + // extra touches abort gesture + if( _trackingTouches.Count + touches.Count > maximumNumberOfTouches ) + { + state = TKGestureRecognizerState.FailedOrEnded; + return false; + } + + // add new or additional touches to gesture (allows for two or more touches to be added or removed without ending the pan gesture) + if( state == TKGestureRecognizerState.Possible || ( ( state == TKGestureRecognizerState.Began || state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) && _trackingTouches.Count < maximumNumberOfTouches ) ) + { + for( int i = 0; i < touches.Count; i++ ) + { + // only add touches in the Began phase + if( touches[i].phase == TouchPhase.Began ) + { + _trackingTouches.Add( touches[i] ); + _startPoint = touches[0].position; + + if( _trackingTouches.Count == maximumNumberOfTouches ) + break; + } + } // end for + + if( _trackingTouches.Count >= minimumNumberOfTouches && _trackingTouches.Count <= maximumNumberOfTouches ) + { + _previousLocation = touchLocation(); + if( state != TKGestureRecognizerState.RecognizedAndStillRecognizing ) + { + totalDeltaMovementInCm = 0f; + state = TKGestureRecognizerState.Began; + } + } + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + //do not engage with touch events if the number of touches is outside our desired constraints + if( _trackingTouches.Count >= minimumNumberOfTouches && _trackingTouches.Count <= maximumNumberOfTouches ) + { + var currentLocation = touchLocation(); + deltaTranslation = currentLocation - _previousLocation; + deltaTranslationCm = deltaTranslation.magnitude / TouchKit.instance.ScreenPixelsPerCm; + _previousLocation = currentLocation; + + if( state == TKGestureRecognizerState.Began ) + { + totalDeltaMovementInCm += deltaTranslationCm; + + if( Math.Abs( totalDeltaMovementInCm ) >= _minDistanceToPanCm ) + { + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + } + else + { + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + } + } + + + internal override void touchesEnded( List touches ) + { + _endPoint = touchLocation(); + + // remove any completed touches + for( int i = 0; i < touches.Count; i++ ) + { + if( touches[i].phase == TouchPhase.Ended ) + _trackingTouches.Remove( touches[i] ); + } + + // if we still have a touch left continue. no touches means its time to reset + if( _trackingTouches.Count >= minimumNumberOfTouches ) + { + _previousLocation = touchLocation(); + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + else + { + // if we had previously been recognizing fire our complete event + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + { + if( gestureCompleteEvent != null ) + { + gestureCompleteEvent( this ); + } + } + + state = TKGestureRecognizerState.FailedOrEnded; + } + } + + + public override string ToString() + { + return string.Format( "[{0}] state: {1}, location: {2}, deltaTranslation: {3}", this.GetType(), state, touchLocation(), deltaTranslation ); + } + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKPanRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKPanRecognizer.cs.meta new file mode 100644 index 00000000..5c1b05b9 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKPanRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 675d9465bff894932a61c4ab70006c02 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKPinchRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKPinchRecognizer.cs new file mode 100644 index 00000000..5bbce530 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKPinchRecognizer.cs @@ -0,0 +1,147 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + + +public class TKPinchRecognizer : TKAbstractGestureRecognizer +{ + public event Action gestureRecognizedEvent; + public event Action gestureCompleteEvent; + + /// + /// the minimum amount of distance the two fingers must move apart before the gesture is recognized + /// + public float minimumScaleDistanceToRecognize = 0; + public float deltaScale = 0; + + private float _intialDistance = 0; // represents the distance between two fingers when gesture was first officially recognized + private float _firstDistance = 0; // first ever distance when two fingers hit the screen (not yet recognized) + private float _previousDistance = 0; + + /// + /// calculated, read-only property. Represents the scale accumulated since the gesture was initially recognized + /// + /// The accumulated scale. + public float accumulatedScale + { + get + { + var currentDistance = distanceBetweenTrackedTouches(); + return currentDistance / _intialDistance; + } + } + + + private float distanceBetweenTrackedTouches() + { + // prevent NaN when the distance between the touches is zero -- only happens in editor + var distance = Vector2.Distance( _trackingTouches[0].position, _trackingTouches[1].position ); + return ( Mathf.Max(0.0001f, distance) / TouchKit.instance.ScreenPixelsPerCm ); + } + + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + + internal override bool touchesBegan( List touches ) + { + if( state == TKGestureRecognizerState.Possible ) + { + // we need to have two touches to work with so we dont set state to Begin until then + // latch the touches + for( int i = 0; i < touches.Count; i++ ) + { + // only add touches in the Began phase + if( touches[i].phase == TouchPhase.Began ) + { + _trackingTouches.Add( touches[i] ); + + if( _trackingTouches.Count == 2 ) + break; + } + } // end for + + if( _trackingTouches.Count == 2 ) + { + // gesture cannot be recognized until the two touches exceed the minimum scale threshold + _firstDistance = distanceBetweenTrackedTouches(); + + // if( minimumScaleDistanceToRecognize == 0 ) + // { + // _intialDistance = _firstDistance; + // state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + // } + } + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + // if the two fingers move far apart to exceed the minimum threshold, begin officially recognizing the gesture + if( _trackingTouches.Count == 2 ) + { + if ( state == TKGestureRecognizerState.Possible ) + { + if( Mathf.Abs( distanceBetweenTrackedTouches() - _firstDistance ) >= minimumScaleDistanceToRecognize ) + { + deltaScale = 0; + _intialDistance = distanceBetweenTrackedTouches(); + _previousDistance = _intialDistance; + state = TKGestureRecognizerState.Began; + } + } + else if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing || state == TKGestureRecognizerState.Began ) + { + var currentDistance = distanceBetweenTrackedTouches(); + deltaScale = ( currentDistance - _previousDistance ) / _intialDistance; + _previousDistance = currentDistance; + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + } + } + + + internal override void touchesEnded( List touches ) + { + // remove any completed touches + for( int i = 0; i < touches.Count; i++ ) + { + if( touches[i].phase == TouchPhase.Ended ) + _trackingTouches.Remove( touches[i] ); + } + + // if we had previously been recognizing fire our complete event + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + { + if( gestureCompleteEvent != null ) + gestureCompleteEvent( this ); + } + + // if we still have a touch left continue to wait for another. no touches means its time to reset + if( _trackingTouches.Count == 1 ) + { + state = TKGestureRecognizerState.Possible; + deltaScale = 0; // I don't know why this would be 1 instead of 0 + } + else + { + state = TKGestureRecognizerState.FailedOrEnded; + } + } + + + public override string ToString() + { + return string.Format( "[{0}] state: {1}, deltaScale: {2}", this.GetType(), state, deltaScale ); + } + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKPinchRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKPinchRecognizer.cs.meta new file mode 100644 index 00000000..39cbc57b --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKPinchRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6fbc0b12876354ebb9ebe2a28e3d9709 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKRotationRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKRotationRecognizer.cs new file mode 100644 index 00000000..b1b12354 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKRotationRecognizer.cs @@ -0,0 +1,160 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + + +/// +/// +/// +public class TKRotationRecognizer : TKAbstractGestureRecognizer +{ + public event Action gestureRecognizedEvent; + public event Action gestureCompleteEvent; + + public float deltaRotation = 0; + public float minimumRotationToRecognize = 0; + + protected float _previousRotation = 0; + protected float _firstRotation = 0; // first ever rotation angle when 2 fingers hit the screen + protected float _initialRotation = 0; // rotation angle when gesture is officially recognized + + public float accumulatedRotation + { + get + { + if( _trackingTouches.Count == 2 ) + return Mathf.DeltaAngle( angleBetweenPoints( _trackingTouches[0].position, _trackingTouches[1].position ), _initialRotation ); + return 0; + } + } + + /// + /// this is public due to its usefulness elsewhere. it should probably move to a helper class. + /// + public static float angleBetweenPoints( Vector2 position1, Vector2 position2 ) + { + var fromLine = position2 - position1; + var toLine = new Vector2( 1, 0 ); + + var angle = Vector2.Angle( fromLine, toLine ); + var cross = Vector3.Cross( fromLine, toLine ); + + // did we wrap around? + if( cross.z > 0 ) + angle = 360f - angle; + + return angle; + } + + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + + internal override bool touchesBegan( List touches ) + { + if( state == TKGestureRecognizerState.Possible ) + { + // we need to have two touches to work with so we dont set state to Begin until then + // latch the touches + for( int i = 0; i < touches.Count; i++ ) + { + // only add touches in the Began phase + if( touches[i].phase == TouchPhase.Began ) + { + _trackingTouches.Add( touches[i] ); + + if( _trackingTouches.Count == 2 ) + break; + } + } // end for + + if( _trackingTouches.Count == 2 ) + { + if( minimumRotationToRecognize == 0 ) + { + deltaRotation = 0; + _previousRotation = angleBetweenPoints( _trackingTouches[0].position, _trackingTouches[1].position ); + state = TKGestureRecognizerState.Began; + } + else + { + // gesture cannot be recognized until the the rotation angle exceeds the minimum threshold + _firstRotation = angleBetweenPoints( _trackingTouches[0].position, _trackingTouches[1].position ); + } + } + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + // if the gesture has passed the minimum delta rotation threshold, begin officially recognizing the gesture + if( state == TKGestureRecognizerState.Possible && _trackingTouches.Count == 2 ) + { + var cr = angleBetweenPoints( _trackingTouches[0].position, _trackingTouches[1].position ); + var delta = Mathf.Abs( Mathf.DeltaAngle( cr, _firstRotation ) ); + + if( delta > minimumRotationToRecognize ) + { + _initialRotation = cr; // the starting rotation when the gesture was first recognized + + deltaRotation = 0; + _previousRotation = angleBetweenPoints( _trackingTouches[0].position, _trackingTouches[1].position ); + state = TKGestureRecognizerState.Began; + } + } + + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing || state == TKGestureRecognizerState.Began ) + { + var currentRotation = angleBetweenPoints( _trackingTouches[0].position, _trackingTouches[1].position ); + deltaRotation = Mathf.DeltaAngle( currentRotation, _previousRotation ); + _previousRotation = currentRotation; + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + } + + + internal override void touchesEnded( List touches ) + { + // remove any completed touches + for( int i = 0; i < touches.Count; i++ ) + { + if( touches[i].phase == TouchPhase.Ended ) + _trackingTouches.Remove( touches[i] ); + } + + // if we had previously been recognizing fire our complete event + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + { + if( gestureCompleteEvent != null ) + gestureCompleteEvent( this ); + } + + // if we still have a touch left continue to wait for another. no touches means its time to reset + if( _trackingTouches.Count == 1 ) + { + state = TKGestureRecognizerState.Possible; + deltaRotation = 0; + } + else + { + state = TKGestureRecognizerState.FailedOrEnded; + _initialRotation = 0; + } + } + + + public override string ToString() + { + return string.Format( "[{0}] state: {1}, location: {2}, rotation: {3}", this.GetType(), state, touchLocation(), deltaRotation ); + } + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKRotationRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKRotationRecognizer.cs.meta new file mode 100644 index 00000000..fe0402e4 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKRotationRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c732a760266d044c28bd68c3db8bd88d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKSwipeRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKSwipeRecognizer.cs new file mode 100644 index 00000000..558981d6 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKSwipeRecognizer.cs @@ -0,0 +1,257 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using System.Linq; + + +[System.Flags] +public enum TKSwipeDirection +{ + Left = ( 1 << 0 ), + Right = ( 1 << 1 ), + Up = ( 1 << 2 ), + Down = ( 1 << 3 ), + + UpLeft = ( 1 << 4 ), + DownLeft = ( 1 << 5 ), + UpRight = ( 1 << 6 ), + DownRight = ( 1 << 7 ), + + Horizontal = ( Left | Right ), + Vertical = ( Up | Down ), + Cardinal = ( Horizontal | Vertical ), + + DiagonalUp = ( UpLeft | UpRight ), + DiagonalDown = ( DownLeft | DownRight ), + DiagonalLeft = ( UpLeft | DownLeft ), + DiagonalRight = ( UpRight | DownRight ), + Diagonal = ( DiagonalUp | DiagonalDown ), + + RightSide = ( Right | DiagonalRight ), + LeftSide = ( Left | DiagonalLeft ), + TopSide = ( Up | DiagonalUp ), + BottomSide = ( Down | DiagonalDown ), + + All = ( Horizontal | Vertical | Diagonal ) +} + +public class TKSwipeRecognizer : TKAbstractGestureRecognizer +{ + /// + /// The event that fires when a swipe is recognized. + /// + public event System.Action gestureRecognizedEvent; + + /// + /// The maximum amount of time for the motion to be considered a swipe. + /// Setting to 0f will disable the time restriction completely. + /// + public float timeToSwipe = 0.5f; + + /// + /// The velocity of the swipe, in centimeters based on the screen resolution + /// and pixel density, if available. + /// + public float swipeVelocity { get; private set; } + + /// + /// The direction that the swipe was made in. Possibilities include the four + /// cardinal directions and the four diagonal directions. + /// + public TKSwipeDirection completedSwipeDirection { get; private set; } + + /// + /// The minimum number of simultaneous touches (fingers) on the screen to trigger + /// this swipe recognizer. Default is 1. + /// + public int minimumNumberOfTouches = 1; + + /// + /// The maximum number of simultaneous touches (fingers) on the screen to trigger + /// this swipe recognizer. Default is 2. + /// + public int maximumNumberOfTouches = 2; + + /// + /// If true, will trigger on the frame that the criteria for a swipe are first met. + /// If false, will only trigger on completion of the motion, when the touch is lifted. + /// + public bool triggerWhenCriteriaMet = true; + + + /// + /// The minimum distance in centimeters that the gesture has to make to be considered + /// a proper swipe, based on resolution and pixel density. Default is 2cm. + /// + private float _minimumDistance = 2f; + + /// + /// The maximum distance in centimeters that the gesture has to make to be considered + /// a proper swipe. + /// + private float _maximumDistance = 10f; + + /// + /// The individual points that make up the gesture, recorded every frame from when a + /// finger is first pressed to the screen until it's lifted. Only tracks the first touch + /// on the screen, in the case of multiple touches. + /// + private List _points = new List(); + + /// + /// The time that the gesture started. Is used to determine if the time limit has been + /// passed, and whether to ignore further checks. + /// + private float _startTime; + + + /// + /// The first touch point in the gesture. + /// + public Vector2 startPoint + { + get { return this._points.FirstOrDefault(); } + } + + /// + /// The last touch point in the gesture. + /// + public Vector2 endPoint + { + get { return this._points.LastOrDefault(); } + } + + + public TKSwipeRecognizer() : this( 2f, 10f ) + { } + + public TKSwipeRecognizer( float minimumDistanceCm, float maximumDistanceCm ) + { + this._minimumDistance = minimumDistanceCm; + this._maximumDistance = maximumDistanceCm; + } + + + private bool checkForSwipeCompletion( TKTouch touch ) + { + // if we have a time stipulation and we exceeded it stop listening for swipes, fail + if( timeToSwipe > 0.0f && ( Time.time - this._startTime ) > timeToSwipe ) + return false; + + // if we don't have at least two points to test yet, then fail + if( this._points.Count < 2 ) + return false; + + // the ideal distance in pixels from the start to the finish + float idealDistance = Vector2.Distance( startPoint, endPoint ); + + // the ideal distance in centimeters, based on the screen pixel density + float idealDistanceCM = idealDistance / TouchKit.instance.ScreenPixelsPerCm; + + // if the distance moved in cm was less than the minimum, + if( idealDistanceCM < this._minimumDistance || idealDistanceCM > this._maximumDistance ) + return false; + + // add up distances between all points sampled during the gesture to get the real distance + float realDistance = 0f; + for( int i = 1; i < this._points.Count; i++ ) + realDistance += Vector2.Distance( this._points[i], this._points[i - 1] ); + + // if the real distance is 10% greater than the ideal distance, then fail + // this weeds out really irregular "lines" and curves from being considered swipes + if( realDistance > idealDistance * 1.1f ) + return false; + + // the speed in cm/s of the swipe + swipeVelocity = idealDistanceCM / ( Time.time - this._startTime ); + + // turn the slope of the ideal swipe line into an angle in degrees + Vector2 v2 = ( endPoint - startPoint ).normalized; + float swipeAngle = Mathf.Atan2( v2.y, v2.x ) * Mathf.Rad2Deg; + if( swipeAngle < 0 ) + swipeAngle = 360 + swipeAngle; + swipeAngle = 360 - swipeAngle; + + // depending on the angle of the line, give a logical swipe direction + if( swipeAngle >= 292.5f && swipeAngle <= 337.5f ) + completedSwipeDirection = TKSwipeDirection.UpRight; + else if( swipeAngle >= 247.5f && swipeAngle <= 292.5f ) + completedSwipeDirection = TKSwipeDirection.Up; + else if( swipeAngle >= 202.5f && swipeAngle <= 247.5f ) + completedSwipeDirection = TKSwipeDirection.UpLeft; + else if( swipeAngle >= 157.5f && swipeAngle <= 202.5f ) + completedSwipeDirection = TKSwipeDirection.Left; + else if( swipeAngle >= 112.5f && swipeAngle <= 157.5f ) + completedSwipeDirection = TKSwipeDirection.DownLeft; + else if( swipeAngle >= 67.5f && swipeAngle <= 112.5f ) + completedSwipeDirection = TKSwipeDirection.Down; + else if( swipeAngle >= 22.5f && swipeAngle <= 67.5f ) + completedSwipeDirection = TKSwipeDirection.DownRight; + else // swipeAngle >= 337.5f || swipeAngle <= 22.5f + completedSwipeDirection = TKSwipeDirection.Right; + + return true; + } + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + internal override bool touchesBegan( List touches ) + { + if( state == TKGestureRecognizerState.Possible ) + { + // add any touches on screen + for( int i = 0; i < touches.Count; i++ ) + this._trackingTouches.Add( touches[i] ); + + // if the number of touches is within our constraints, begin tracking + if( this._trackingTouches.Count >= minimumNumberOfTouches && this._trackingTouches.Count <= maximumNumberOfTouches ) + { + // reset everything + this._points.Clear(); + this._points.Add( touches[0].position ); + + this._startTime = Time.time; + state = TKGestureRecognizerState.Began; + } + } + return false; + } + + internal override void touchesMoved( List touches ) + { + // only bother doing anything if we haven't recognized or failed yet + if( state == TKGestureRecognizerState.Began ) + { + this._points.Add( touches[0].position ); + + // if we're triggering when the criteria is met, then check for completion every frame + if( triggerWhenCriteriaMet && checkForSwipeCompletion( touches[0] ) ) + state = TKGestureRecognizerState.Recognized; + } + } + + internal override void touchesEnded( List touches ) + { + // if we haven't recognized or failed yet + if( state == TKGestureRecognizerState.Began ) + { + this._points.Add( touches[0].position ); + + // last frame, one last check- recognized or fail + if( checkForSwipeCompletion( touches[0] ) ) + state = TKGestureRecognizerState.Recognized; + else + state = TKGestureRecognizerState.FailedOrEnded; + } + } + + public override string ToString() + { + return string.Format( "{0}, swipe direction: {1}, swipe velocity: {2}, start point: {3}, end point: {4}", + base.ToString(), completedSwipeDirection, swipeVelocity, startPoint, endPoint ); + } +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKSwipeRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKSwipeRecognizer.cs.meta new file mode 100644 index 00000000..b2a50bdf --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKSwipeRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 05051c1d2a36c43a195c3a390af1b74a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKTapRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKTapRecognizer.cs new file mode 100644 index 00000000..881f6801 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKTapRecognizer.cs @@ -0,0 +1,107 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + +public class TKTapRecognizer : TKAbstractGestureRecognizer +{ + public event Action gestureRecognizedEvent; + + public int numberOfTapsRequired = 1; + public int numberOfTouchesRequired = 1; + + // taps that last longer than this duration will be ignored + float _maxDurationForTapConsideration = 0.5f; + + float _maxDeltaMovementForTapConsideration = 1f; + float _touchBeganTime; + int _preformedTapsCount = 0; + + + public TKTapRecognizer() : this( 0.5f, 1f ) + {} + + + public TKTapRecognizer( float maxDurationForTapConsideration, float maxDeltaMovementForTapConsiderationCm ) + { + _maxDurationForTapConsideration = maxDurationForTapConsideration; + _maxDeltaMovementForTapConsideration = maxDeltaMovementForTapConsiderationCm; + } + + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + + internal override bool touchesBegan( List touches ) + { + if( Time.time > _touchBeganTime + _maxDurationForTapConsideration && _preformedTapsCount != 0 && _preformedTapsCount < numberOfTapsRequired ) + state = TKGestureRecognizerState.FailedOrEnded; + + if( state == TKGestureRecognizerState.Possible ) + { + for( int i = 0; i < touches.Count; i++ ) + { + // only add touches in the Began phase + if( touches[i].phase == TouchPhase.Began ) + { + _trackingTouches.Add( touches[i] ); + + if( _trackingTouches.Count == numberOfTouchesRequired ) + break; + } + } // end for + + if( _trackingTouches.Count == numberOfTouchesRequired ) + { + _touchBeganTime = Time.time; + _preformedTapsCount = 0; + state = TKGestureRecognizerState.Began; + + return true; + } + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + if( state == TKGestureRecognizerState.Began ) + { + // did we move? + for( var i = 0; i < touches.Count; i++ ) + { + if ( + ((Math.Abs(touches[i].position.x - touches[i].startPosition.x) / TouchKit.instance.ScreenPixelsPerCm) > _maxDeltaMovementForTapConsideration) || + ((Math.Abs(touches[i].position.y - touches[i].startPosition.y) / TouchKit.instance.ScreenPixelsPerCm) > _maxDeltaMovementForTapConsideration) + ) + { + state = TKGestureRecognizerState.FailedOrEnded; + break; + } + } + } + } + + + internal override void touchesEnded( List touches ) + { + if( state == TKGestureRecognizerState.Began && ( Time.time <= _touchBeganTime + _maxDurationForTapConsideration ) ) + { + ++_preformedTapsCount; + if( _preformedTapsCount == numberOfTapsRequired ) + state = TKGestureRecognizerState.Recognized; + } + else + { + state = TKGestureRecognizerState.FailedOrEnded; + } + } + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKTapRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKTapRecognizer.cs.meta new file mode 100644 index 00000000..539f8870 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKTapRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6e33f2100ab364510815a15f9fc0503d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKTouchPadRecognizer.cs b/Assets/TouchKit/TouchKit/Recognizers/TKTouchPadRecognizer.cs new file mode 100644 index 00000000..c9a245f4 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKTouchPadRecognizer.cs @@ -0,0 +1,103 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + + + +public class TKTouchPadRecognizer : TKAbstractGestureRecognizer +{ + public event Action gestureRecognizedEvent; + public event Action gestureCompleteEvent; + + public AnimationCurve inputCurve = AnimationCurve.Linear( 0.0f, 0.0f, 1.0f, 1.0f ); + public Vector2 value; + + + /// + /// the constructor ensures we have a frame to work with for this recognizer + /// + public TKTouchPadRecognizer( TKRect frame ) + { + boundaryFrame = frame; + } + + + internal override void fireRecognizedEvent() + { + if( gestureRecognizedEvent != null ) + gestureRecognizedEvent( this ); + } + + + internal override bool touchesBegan( List touches ) + { + if( state == TKGestureRecognizerState.Possible ) + { + for( var i = 0; i < touches.Count; i++ ) + { + // only add touches in the Began phase + if( touches[i].phase == TouchPhase.Began ) + _trackingTouches.Add( touches[i] ); + } + + if( _trackingTouches.Count > 0 ) + { + state = TKGestureRecognizerState.Began; + + // call through to touchesMoved so we set the value and set the state to RecognizedAndStillRecognizing which triggers the recognized event + touchesMoved( touches ); + } + } + + return false; + } + + + internal override void touchesMoved( List touches ) + { + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing || state == TKGestureRecognizerState.Began ) + { + var currentLocation = touchLocation(); + value = currentLocation - boundaryFrame.Value.center; + + // normalize from 0 - 1 and clamp + value.x = Mathf.Clamp( value.x / ( boundaryFrame.Value.width * 0.5f ), -1f, 1f ); + value.y = Mathf.Clamp( value.y / ( boundaryFrame.Value.height * 0.5f ), -1f, 1f ); + + // apply our inputCurve + value.x = inputCurve.Evaluate( Mathf.Abs( value.x ) ) * Mathf.Sign( value.x ); + value.y = inputCurve.Evaluate( Mathf.Abs( value.y ) ) * Mathf.Sign( value.y ); + + state = TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + } + + + internal override void touchesEnded( List touches ) + { + // remove any completed touches + for( var i = 0; i < touches.Count; i++ ) + { + if( touches[i].phase == TouchPhase.Ended ) + _trackingTouches.Remove( touches[i] ); + } + + // if we had previously been recognizing fire our complete event + if( state == TKGestureRecognizerState.RecognizedAndStillRecognizing ) + { + if( gestureCompleteEvent != null ) + gestureCompleteEvent( this ); + } + + value = Vector2.zero; + state = TKGestureRecognizerState.FailedOrEnded; + } + + + public override string ToString() + { + return string.Format( "[{0}] state: {1}, value: {2}", this.GetType(), state, value ); + } + +} diff --git a/Assets/TouchKit/TouchKit/Recognizers/TKTouchPadRecognizer.cs.meta b/Assets/TouchKit/TouchKit/Recognizers/TKTouchPadRecognizer.cs.meta new file mode 100644 index 00000000..e2d00f28 --- /dev/null +++ b/Assets/TouchKit/TouchKit/Recognizers/TKTouchPadRecognizer.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 884f51553239d423d859e6adb04b1fc8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKit/TouchKit.cs b/Assets/TouchKit/TouchKit/TouchKit.cs new file mode 100644 index 00000000..2e035a3a --- /dev/null +++ b/Assets/TouchKit/TouchKit/TouchKit.cs @@ -0,0 +1,308 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + + +public partial class TouchKit : MonoBehaviour +{ + [HideInInspector] + public bool simulateTouches = true; + [HideInInspector] + public bool simulateMultitouch = true; + [HideInInspector] + public bool drawTouches = false; + [HideInInspector] + public bool drawDebugBoundaryFrames = false; + + /// + /// lets TouchKit know if it should scale all rects and distances based on the designTimeResolution + /// + public bool autoScaleRectsAndDistances = true; + + /// + /// if false, TouchKit will not do anything in Update. You will need to call updateTouches yourself. + /// + public bool shouldAutoUpdateTouches = true; + + private Vector2 _designTimeResolution = new Vector2( 320, 180 ); // 16:9 is a decent starting point for aspect ratio + /// + /// all TKRect sizes should be based on this screen size. They will be adjusted at runtime if autoUpdateRects is true + /// + public Vector2 designTimeResolution { + get { + return _designTimeResolution; + } + set { + _designTimeResolution = value; + setupRuntimeScale(); + } + } + public int maxTouchesToProcess = 2; + + /// + /// used at runtime to scale any TKRects as they are made for the current screen size + /// + public Vector2 runtimeScaleModifier { get; private set; } + + /// + /// used at runtime to modify distances + /// + public float runtimeDistanceModifier { get; private set; } + + /// + /// used at runtime to translate a pixel value into Unity units. Just multiply the pixel value by the pixelsToUnityUnitsMultiplier. + /// Note that this will only work for orthographic cameras! + /// + public Vector2 pixelsToUnityUnitsMultiplier { get; private set; } + + + private List _gestureRecognizers = new List( 5 ); + private TKTouch[] _touchCache; + private List _liveTouches = new List( 2 ); + private bool _shouldCheckForLostTouches = false; // used internally to ensure we dont check for lost touches too often + + private const float inchesToCentimeters = 2.54f; + + public float ScreenPixelsPerCm + { + get + { + float fallbackDpi = 72f; + #if UNITY_ANDROID + // Android MDPI setting fallback + // http://developer.android.com/guide/practices/screens_support.html + fallbackDpi = 160f; + #elif (UNITY_WP8 || UNITY_WP8_1 || UNITY_WSA || UNITY_WSA_8_0) + // Windows phone is harder to track down + // http://www.windowscentral.com/higher-resolution-support-windows-phone-7-dpi-262 + fallbackDpi = 92f; + #elif UNITY_IOS + // iPhone 4-6 range + fallbackDpi = 326f; + #endif + + return Screen.dpi == 0f ? fallbackDpi / inchesToCentimeters : Screen.dpi / inchesToCentimeters; + } + } + + private static TouchKit _instance = null; + public static TouchKit instance + { + get + { + if( !_instance ) + { + // check if there is a GO instance already available in the scene graph + _instance = FindObjectOfType( typeof( TouchKit ) ) as TouchKit; + + // nope, create a new one + if( !_instance ) + { + var obj = new GameObject( "TouchKit" ); + _instance = obj.AddComponent(); + DontDestroyOnLoad( obj ); + } + + // prep the scalers. for the distance scaler we just use an average of the width and height scales + var aCamera = Camera.main ?? Camera.allCameras[0]; + if( aCamera.orthographic ) + { + setupPixelsToUnityUnitsMultiplierWithCamera( aCamera ); + } + else + { + _instance.pixelsToUnityUnitsMultiplier = Vector2.one; + } + + _instance.setupRuntimeScale(); + } + + return _instance; + } + } + + protected void setupRuntimeScale() + { + _instance.runtimeScaleModifier = new Vector2( Screen.width / _instance.designTimeResolution.x, Screen.height / _instance.designTimeResolution.y ); + _instance.runtimeDistanceModifier = ( _instance.runtimeScaleModifier.x + _instance.runtimeScaleModifier.y ) / 2f; + + if( !_instance.autoScaleRectsAndDistances ) + { + _instance.runtimeScaleModifier = Vector2.one; + _instance.runtimeDistanceModifier = 1f; + } + } + + /// + /// Unity often misses the Ended phase of touches so this method will look out for that + /// + private void addTouchesUnityForgotToEndToLiveTouchesList() + { + for( int i = 0; i < _touchCache.Length; i++ ) + { + if( _touchCache[i].phase != TouchPhase.Ended ) + { + Debug.LogWarning( "found touch Unity forgot to end with phase: " + _touchCache[i].phase ); + _touchCache[i].phase = TouchPhase.Ended; + _liveTouches.Add( _touchCache[i] ); + } + } + } + + + private void internalUpdateTouches() + { + // the next couple sections are disgustingly, appallingly, horrendously horrible due to all the #ifs but it + // helps when testing in the editor + #if UNITY_EDITOR + // check to see if the Unity Remote is active + if( shouldProcessMouseInput() ) + { + #endif + + #if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + + // we only need to process if we have some interesting input this frame + if( Input.GetMouseButtonUp( 0 ) || Input.GetMouseButton( 0 ) ) + _liveTouches.Add( _touchCache[0].populateFromMouse() ); + + #endif + + #if UNITY_EDITOR + } + #endif + + + // get all touches and examine them. only do our touch processing if we have some touches + if( Input.touchCount > 0 ) + { + _shouldCheckForLostTouches = true; + + var maxTouchIndexToExamine = Mathf.Min( Input.touches.Length, maxTouchesToProcess ); + for( var i = 0; i < maxTouchIndexToExamine; i++ ) + { + var touch = Input.touches[i]; + if( touch.fingerId < maxTouchesToProcess ) + _liveTouches.Add( _touchCache[touch.fingerId].populateWithTouch( touch ) ); + } + } + else + { + // we guard this so that we only check once after all the touches are lifted + if( _shouldCheckForLostTouches ) + { + addTouchesUnityForgotToEndToLiveTouchesList(); + _shouldCheckForLostTouches = false; + } + } + + // pass on the touches to all the recognizers + if( _liveTouches.Count > 0 ) + { + for( var i = 0; i < _gestureRecognizers.Count; i++ ) + _gestureRecognizers[i].recognizeTouches( _liveTouches ); + _liveTouches.Clear(); + } + } + + + #region MonoBehaviour + + private void Awake() + { + // prep our TKTouch cache so we avoid excessive allocations + _touchCache = new TKTouch[maxTouchesToProcess]; + for( int i = 0; i < maxTouchesToProcess; i++ ) + _touchCache[i] = new TKTouch( i ); + } + + + private void Update() + { + if( shouldAutoUpdateTouches ) + internalUpdateTouches(); + } + + + private void OnApplicationQuit() + { + _instance = null; + Destroy( gameObject ); + } + + #endregion + + + #region Public API + + /// + /// TouchKit will attempt to use the first camera to set this up. If that is not the camera you would like used + /// just call this method with your HUD (or standard orthographic) camera. + /// + /// Cam. + public static void setupPixelsToUnityUnitsMultiplierWithCamera( Camera cam ) + { + if( !cam.orthographic ) + { + Debug.LogError( "Attempting to setup unity pixel-to-units modifier with a non-orthographic camera" ); + return; + } + + var screenSizeUnityUnits = new Vector2( cam.aspect * cam.orthographicSize * 2f, cam.orthographicSize * 2f ); + _instance.pixelsToUnityUnitsMultiplier = new Vector2 + ( + screenSizeUnityUnits.x / (float)Screen.width, + screenSizeUnityUnits.y / (float)Screen.height + ); + } + + + public static void updateTouches() + { + if( _instance == null ) + return; + + _instance.internalUpdateTouches(); + } + + + public static void addGestureRecognizer( TKAbstractGestureRecognizer recognizer ) + { + // add, then sort and reverse so the higher zIndex items will be on top + instance._gestureRecognizers.Add( recognizer ); + + if( recognizer.zIndex > 0 ) + { + _instance._gestureRecognizers.Sort(); + _instance._gestureRecognizers.Reverse(); + } + } + + + public static void removeGestureRecognizer( TKAbstractGestureRecognizer recognizer ) + { + if( _instance == null ) + return; + + if( !_instance._gestureRecognizers.Contains( recognizer ) ) + { + Debug.LogError( "Trying to remove gesture recognizer that has not been added: " + recognizer ); + return; + } + + recognizer.reset(); + instance._gestureRecognizers.Remove( recognizer ); + } + + + public static void removeAllGestureRecognizers() + { + if( _instance == null ) + return; + + instance._gestureRecognizers.Clear(); + } + + #endregion + +} diff --git a/Assets/TouchKit/TouchKit/TouchKit.cs.meta b/Assets/TouchKit/TouchKit/TouchKit.cs.meta new file mode 100644 index 00000000..db604fb6 --- /dev/null +++ b/Assets/TouchKit/TouchKit/TouchKit.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e065ffc7dbca743ee9cef1b5106b0d26 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKitDemos.meta b/Assets/TouchKit/TouchKitDemos.meta new file mode 100644 index 00000000..ced5bbe7 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 1e966c05fe45e4ea095c9c431c9fe0c6 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKitDemos/DemoOne.meta b/Assets/TouchKit/TouchKitDemos/DemoOne.meta new file mode 100644 index 00000000..3d36176a --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoOne.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 2bb37a37b01b54cf0824218be7f4b5db +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.cs b/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.cs new file mode 100644 index 00000000..33523113 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.cs @@ -0,0 +1,226 @@ +using UnityEngine; +using System.Collections; + + +public class DemoOne : MonoBehaviour +{ + public Transform cube; + private Vector2 _scrollPosition; // for the scroll view + public AnimationCurve touchPadInputCurve = AnimationCurve.Linear( 0.0f, 0.0f, 1.0f, 1.0f ); + + + void OnGUI() + { + GUI.skin.button.padding = new RectOffset( 10, 10, 20, 20 ); + GUI.skin.button.fixedWidth = 250; + + + GUILayout.BeginArea( new Rect( Screen.width - GUI.skin.button.fixedWidth - 20, 0, GUI.skin.button.fixedWidth + 20, Screen.height ) ); + _scrollPosition = GUILayout.BeginScrollView( _scrollPosition, GUILayout.Width( GUI.skin.button.fixedWidth + 20 ), GUILayout.Height( Screen.height ) ); + + + if( GUILayout.Button( "Add Tap Recognizer" ) ) + { + var recognizer = new TKTapRecognizer(); + + // we can limit recognition to a specific Rect, in this case the bottom-left corner of the screen + recognizer.boundaryFrame = new TKRect( 0, 0, 50f, 50f ); + + // we can also set the number of touches required for the gesture + if( Application.platform == RuntimePlatform.IPhonePlayer ) + recognizer.numberOfTouchesRequired = 2; + + recognizer.gestureRecognizedEvent += ( r ) => + { + Debug.Log( "tap recognizer fired: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add Long Press Recognizer" ) ) + { + var recognizer = new TKLongPressRecognizer(); + recognizer.gestureRecognizedEvent += ( r ) => + { + Debug.Log( "long press recognizer fired: " + r ); + }; + recognizer.gestureCompleteEvent += ( r ) => + { + Debug.Log( "long press recognizer finished: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add Pan Recognizer" ) ) + { + var recognizer = new TKPanRecognizer(); + + // when using in conjunction with a pinch or rotation recognizer setting the min touches to 2 smoothes movement greatly + if( Application.platform == RuntimePlatform.IPhonePlayer ) + recognizer.minimumNumberOfTouches = 2; + + recognizer.gestureRecognizedEvent += ( r ) => + { + Camera.main.transform.position -= new Vector3( recognizer.deltaTranslation.x, recognizer.deltaTranslation.y ) / 100; + Debug.Log( "pan recognizer fired: " + r ); + }; + + // continuous gestures have a complete event so that we know when they are done recognizing + recognizer.gestureCompleteEvent += r => + { + Debug.Log( "pan gesture complete" ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add TouchPad Recognizer" ) ) + { + var recognizer = new TKTouchPadRecognizer( new TKRect( 0f, 50f, 80f, 50f ) ); + recognizer.inputCurve = touchPadInputCurve; + + recognizer.gestureRecognizedEvent += ( r ) => + { + //Camera.main.transform.position -= new Vector3( recognizer.deltaTranslation.x, recognizer.deltaTranslation.y ) / 100; + Debug.Log( "touchpad recognizer fired: " + r ); + }; + + // continuous gestures have a complete event so that we know when they are done recognizing + recognizer.gestureCompleteEvent += r => + { + Debug.Log( "touchpad gesture complete" ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add Horizontal Swipe Recognizer" ) ) + { + var recognizer = new TKSwipeRecognizer(); + recognizer.gestureRecognizedEvent += ( r ) => + { + Debug.Log( "swipe recognizer fired: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + if( GUILayout.Button( "Add Top-Right Swipe Recognizer" ) ) + { + var recognizer = new TKAngleSwipeRecognizer(); + recognizer.addAngleRecogizedEvents ( + (TKAngleSwipeRecognizer r) => { + Debug.Log( "Top-Right angle swipe fired " + r ); + }, new Vector2(1,1), 45); + + recognizer.gestureRecognizedEvent += r => { + // You can also do ordinary event, which fires at any angle + // Debug.Log( "angle swipe recognizer fired: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add Pinch Recognizer" ) ) + { + var recognizer = new TKPinchRecognizer(); + recognizer.gestureRecognizedEvent += ( r ) => + { + cube.transform.localScale += Vector3.one * recognizer.deltaScale; + Debug.Log( "pinch recognizer fired: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add Rotation Recognizer" ) ) + { + var recognizer = new TKRotationRecognizer(); + recognizer.gestureRecognizedEvent += ( r ) => + { + cube.Rotate( Vector3.back, recognizer.deltaRotation ); + Debug.Log( "rotation recognizer fired: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add Button Recognizer" ) ) + { + var recognizer = new TKButtonRecognizer( new TKRect( 5f, 145f, 80f, 30f ), 10f ); + recognizer.zIndex = 1; + recognizer.onSelectedEvent += ( r ) => + { + Debug.Log( "button recognizer selected: " + r ); + }; + recognizer.onDeselectedEvent += ( r ) => + { + Debug.Log( "button recognizer deselected: " + r ); + }; + recognizer.onTouchUpInsideEvent += ( r ) => + { + Debug.Log( "button recognizer touch up inside: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add One Finger Rotation Recognizer" ) ) + { + var recognizer = new TKOneFingerRotationRecognizer(); + recognizer.targetPosition = Camera.main.WorldToScreenPoint( cube.position ); + recognizer.gestureRecognizedEvent += ( r ) => + { + cube.Rotate( Vector3.back, recognizer.deltaRotation ); + Debug.Log( "one finger rotation recognizer fired: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add Any Touch Recognizer" ) ) + { + var recognizer = new TKAnyTouchRecognizer( new TKRect( 10, 10, 80, 50 ) ); + recognizer.zIndex = 1; + recognizer.onEnteredEvent += ( r ) => + { + Debug.Log( "any touch entered: " + r ); + }; + recognizer.onExitedEvent += ( r ) => + { + Debug.Log( "any touch exited: " + r ); + }; + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Add Curve Recognizer" ) ) + { + var recognizer = new TKCurveRecognizer(); + + recognizer.gestureRecognizedEvent += ( r ) => + { + cube.Rotate( Vector3.back, recognizer.deltaRotation ); + Debug.Log( "curve recognizer fired: " + r ); + }; + + recognizer.gestureCompleteEvent += ( r ) => + { + Debug.Log( "curve completed."); + }; + + TouchKit.addGestureRecognizer( recognizer ); + } + + + if( GUILayout.Button( "Remove All Recognizers" ) ) + { + TouchKit.removeAllGestureRecognizers(); + } + + + GUILayout.EndScrollView(); + GUILayout.EndArea(); + } +} diff --git a/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.cs.meta b/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.cs.meta new file mode 100644 index 00000000..da501258 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f2caec28268145de81952dd10b76252 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.unity b/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.unity new file mode 100644 index 00000000..1c13b05e --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.unity @@ -0,0 +1,612 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientEquatorColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientGroundColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &4 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 1 + m_BakeResolution: 50 + m_AtlasSize: 1024 + m_AO: 1 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 0 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 1 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 512 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 0 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 0 +--- !u!196 &5 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666666 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &20608213 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 20608214} + - component: {fileID: 20608215} + - component: {fileID: 20608218} + - component: {fileID: 20608216} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &20608214 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20608213} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!20 &20608215 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20608213} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 0 + orthographic size: 100 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 0 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!81 &20608216 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20608213} + m_Enabled: 1 +--- !u!124 &20608218 +Behaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20608213} + m_Enabled: 1 +--- !u!1 &235682970 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 235682974} + - component: {fileID: 235682973} + - component: {fileID: 235682972} + - component: {fileID: 235682971} + m_Layer: 0 + m_Name: Sphere + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!23 &235682971 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235682970} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10302, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!135 &235682972 +SphereCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235682970} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Radius: 0.5 + m_Center: {x: 0, y: 0, z: 0} +--- !u!33 &235682973 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235682970} + m_Mesh: {fileID: 10207, guid: 0000000000000000e000000000000000, type: 0} +--- !u!4 &235682974 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 235682970} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1.183403, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 1052943443} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &764707309 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 764707311} + - component: {fileID: 764707310} + m_Layer: 0 + m_Name: TouchKit + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &764707310 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 764707309} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e065ffc7dbca743ee9cef1b5106b0d26, type: 3} + m_Name: + m_EditorClassIdentifier: + simulateTouches: 1 + simulateMultitouch: 1 + drawTouches: 1 + drawDebugBoundaryFrames: 1 + autoScaleRectsAndDistances: 1 + shouldAutoUpdateTouches: 1 + maxTouchesToProcess: 2 +--- !u!4 &764707311 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 764707309} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 3 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1052943442 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1052943443} + - component: {fileID: 1052943445} + - component: {fileID: 1052943446} + - component: {fileID: 1052943444} + m_Layer: 0 + m_Name: Cube + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1052943443 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1052943442} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.036293983, y: 1, z: -4.0702114} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 235682974} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!23 &1052943444 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1052943442} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 0 + m_ReflectionProbeUsage: 1 + m_RayTracingMode: 2 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 10302, guid: 0000000000000000f000000000000000, type: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_ReceiveGI: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 1 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!33 &1052943445 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1052943442} + m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} +--- !u!65 &1052943446 +BoxCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1052943442} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + serializedVersion: 2 + m_Size: {x: 1, y: 1, z: 1} + m_Center: {x: 0, y: 0, z: 0} +--- !u!1 &1332715272 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1332715273} + - component: {fileID: 1332715274} + m_Layer: 0 + m_Name: ui + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1332715273 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1332715272} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -354.3353, y: 172.3465, z: 49.999996} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 4 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &1332715274 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1332715272} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 8f2caec28268145de81952dd10b76252, type: 3} + m_Name: + m_EditorClassIdentifier: + cube: {fileID: 1052943443} + touchPadInputCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0.14999999 + value: 0 + inSlope: 0.4453594 + outSlope: 0.4453594 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 1 + inSlope: 2.7624688 + outSlope: 2.7624688 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 +--- !u!1 &1591823659 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1591823660} + - component: {fileID: 1591823661} + m_Layer: 0 + m_Name: Directional light + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &1591823660 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1591823659} + m_LocalRotation: {x: 0.27440774, y: 0.06740036, z: -0.045521457, w: 0.95816773} + m_LocalPosition: {x: 0, y: 9.506577, z: -27.999771} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!108 &1591823661 +Light: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1591823659} + m_Enabled: 1 + serializedVersion: 10 + m_Type: 1 + m_Shape: 0 + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_Intensity: 1 + m_Range: 10 + m_SpotAngle: 30 + m_InnerSpotAngle: 21.80208 + m_CookieSize: 10 + m_Shadows: + m_Type: 0 + m_Resolution: -1 + m_CustomResolution: -1 + m_Strength: 1 + m_Bias: 0.05 + m_NormalBias: 0.4 + m_NearPlane: 0.2 + m_CullingMatrixOverride: + e00: 1 + e01: 0 + e02: 0 + e03: 0 + e10: 0 + e11: 1 + e12: 0 + e13: 0 + e20: 0 + e21: 0 + e22: 1 + e23: 0 + e30: 0 + e31: 0 + e32: 0 + e33: 1 + m_UseCullingMatrixOverride: 0 + m_Cookie: {fileID: 0} + m_DrawHalo: 0 + m_Flare: {fileID: 0} + m_RenderMode: 0 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingLayerMask: 1 + m_Lightmapping: 1 + m_LightShadowCasterMode: 0 + m_AreaSize: {x: 1, y: 1} + m_BounceIntensity: 1 + m_ColorTemperature: 6570 + m_UseColorTemperature: 0 + m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} + m_UseBoundingSphereOverride: 0 + m_ShadowRadius: 0 + m_ShadowAngle: 0 diff --git a/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.unity.meta b/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.unity.meta new file mode 100644 index 00000000..7d338c26 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoOne/DemoOne.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 9f1b907393c7e41448148dc6517f5c3d +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKitDemos/DemoTwo.meta b/Assets/TouchKit/TouchKitDemos/DemoTwo.meta new file mode 100644 index 00000000..80214820 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoTwo.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: bedd8b8197a974a16b124fd890c0e775 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.cs b/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.cs new file mode 100644 index 00000000..ccd3a522 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.cs @@ -0,0 +1,56 @@ +using UnityEngine; +using System.Collections; + + +/// +/// this demo will create a virtual d-pad and two buttons. the virtual d-pad will have a left, right and up button. the up +/// button will overlap the left and right buttons. the reason for this is to show one way to handle 5 directional d-pad +/// (left, up-left, up, up-right, right) letting the player slide their finger around. It alsow demonstrates how the TKAnyTouchRecognizer +/// does not "eat" touches and allows them to bleed down through to recognizers below them. +/// +/// note that we are working with a 16:9 design time resolution since that is the most popular on mobile and a good base. Note also +/// that we have set shouldAutoUpdateTouches to false and we are manually calling updateTouches. This lets us process the touches +/// exactly when we want: right before we use them. +/// +public class DemoTwo : MonoBehaviour +{ + private VirtualControls _controls; + + + void Start() + { + _controls = new VirtualControls(); + _controls.createDebugQuads(); + } + + + void Update() + { + _controls.update(); + } + + + void OnGUI() + { + showLabelAndValue( "Left: ", _controls.leftDown.ToString() ); + showLabelAndValue( "Right: ", _controls.rightDown.ToString() ); + showLabelAndValue( "Up: ", _controls.upDown.ToString() ); + + GUILayout.Space( 4 ); + + showLabelAndValue( "Attack: ", _controls.attackDown.ToString() ); + showLabelAndValue( "Jump: ", _controls.jumpDown.ToString() ); + } + + + void showLabelAndValue( string label, string value ) + { + GUILayout.BeginHorizontal(); + { + GUILayout.Label( label, GUILayout.Width( 50 ) ); + GUILayout.Label( value ); + } + GUILayout.EndHorizontal(); + } + +} diff --git a/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.cs.meta b/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.cs.meta new file mode 100644 index 00000000..4916ff32 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 14e83b1078b824cc5957fa7a77be02d7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.unity b/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.unity new file mode 100644 index 00000000..b7252f51 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.unity @@ -0,0 +1,308 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientEquatorColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientGroundColor: {r: 0.2, g: 0.2, b: 0.2, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &4 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 1 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 1 + m_BakeResolution: 50 + m_AtlasSize: 1024 + m_AO: 1 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 0 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 1 + m_BakeBackend: 0 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 512 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 0 + m_PVRDenoiserTypeDirect: 0 + m_PVRDenoiserTypeIndirect: 0 + m_PVRDenoiserTypeAO: 0 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 0 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 0 +--- !u!196 &5 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666666 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &59454456 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 59454461} + - component: {fileID: 59454460} + - component: {fileID: 59454458} + - component: {fileID: 59454457} + m_Layer: 0 + m_Name: Main Camera + m_TagString: MainCamera + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!81 &59454457 +AudioListener: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 59454456} + m_Enabled: 1 +--- !u!124 &59454458 +Behaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 59454456} + m_Enabled: 1 +--- !u!20 &59454460 +Camera: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 59454456} + m_Enabled: 1 + serializedVersion: 2 + m_ClearFlags: 1 + m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0.019607844} + m_projectionMatrixMode: 1 + m_GateFitMode: 2 + m_FOVAxisMode: 0 + m_SensorSize: {x: 36, y: 24} + m_LensShift: {x: 0, y: 0} + m_FocalLength: 50 + m_NormalizedViewPortRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 + near clip plane: 0.3 + far clip plane: 1000 + field of view: 60 + orthographic: 1 + orthographic size: 5 + m_Depth: -1 + m_CullingMask: + serializedVersion: 2 + m_Bits: 4294967295 + m_RenderingPath: -1 + m_TargetTexture: {fileID: 0} + m_TargetDisplay: 0 + m_TargetEye: 3 + m_HDR: 0 + m_AllowMSAA: 1 + m_AllowDynamicResolution: 0 + m_ForceIntoRT: 0 + m_OcclusionCulling: 1 + m_StereoConvergence: 10 + m_StereoSeparation: 0.022 +--- !u!4 &59454461 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 59454456} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 1, z: -10} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 1 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &494578000 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 494578002} + - component: {fileID: 494578001} + m_Layer: 0 + m_Name: DemoTwo + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &494578001 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 494578000} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 14e83b1078b824cc5957fa7a77be02d7, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!4 &494578002 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 494578000} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!1 &1995668659 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1995668661} + - component: {fileID: 1995668660} + m_Layer: 0 + m_Name: TouchKit + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &1995668660 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1995668659} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e065ffc7dbca743ee9cef1b5106b0d26, type: 3} + m_Name: + m_EditorClassIdentifier: + simulateTouches: 1 + simulateMultitouch: 1 + drawTouches: 1 + drawDebugBoundaryFrames: 1 + autoScaleRectsAndDistances: 1 + shouldAutoUpdateTouches: 0 + maxTouchesToProcess: 5 +--- !u!4 &1995668661 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1995668659} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 2 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.unity.meta b/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.unity.meta new file mode 100644 index 00000000..3cf93555 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoTwo/DemoTwo.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 62c8bf4ea5f784fed9707bbb086970ae +DefaultImporter: + userData: diff --git a/Assets/TouchKit/TouchKitDemos/DemoTwo/VirtualControls.cs b/Assets/TouchKit/TouchKitDemos/DemoTwo/VirtualControls.cs new file mode 100644 index 00000000..54649294 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoTwo/VirtualControls.cs @@ -0,0 +1,126 @@ +using UnityEngine; +using System.Collections; + + +/// +/// this class shows one way to setup a virtual control setup (d-pad and two buttons). It illustrates a bunch of concepts +/// including recognizer layering (overlapping "up" button to get diagonals) and also how to detect only in this frame +/// if a button is down (attack button). +/// +public class VirtualControls +{ + public bool leftDown, upDown, rightDown, attackDown, jumpDown; + + private float buttonWidth = 24f; + private float buttonHeight = 30f; + + + private TKAnyTouchRecognizer _leftRecognizer; + private TKAnyTouchRecognizer _rightRecognizer; + private TKAnyTouchRecognizer _upRecognizer; + + private TKButtonRecognizer _attackRecognizer; + private TKButtonRecognizer _jumpRecognizer; + + public TKRect leftRect { get { return _leftRecognizer.boundaryFrame.Value; } } + public TKRect rightRect { get { return _rightRecognizer.boundaryFrame.Value; } } + public TKRect upRect { get { return _upRecognizer.boundaryFrame.Value; } } + + public TKRect attackRect { get { return _attackRecognizer.boundaryFrame.Value; } } + public TKRect jumpRect { get { return _jumpRecognizer.boundaryFrame.Value; } } + + + public VirtualControls() + { + // if we have something like the iPad with a squarish aspect ratio adjust the button height to be a bit smaller + if( Camera.main.aspect < 1.7f ) + { + buttonHeight *= Camera.main.aspect / 1.7f; + buttonWidth *= Camera.main.aspect / 1.7f; + } + setupRecognizers(); + } + + + public void update() + { + // reset our state + leftDown = upDown = rightDown = attackDown = jumpDown = false; + + // first update our touches then use our recognizers to set our state + TouchKit.updateTouches(); + + leftDown = _leftRecognizer.state == TKGestureRecognizerState.RecognizedAndStillRecognizing; + rightDown = _rightRecognizer.state == TKGestureRecognizerState.RecognizedAndStillRecognizing; + upDown = _upRecognizer.state == TKGestureRecognizerState.RecognizedAndStillRecognizing; + + jumpDown = _jumpRecognizer.state == TKGestureRecognizerState.RecognizedAndStillRecognizing; + } + + + public void createDebugQuads() + { + createQuadButton( leftRect, Color.green ); + createQuadButton( rightRect, Color.green ); + createQuadButton( upRect, Color.white ); + + createQuadButton( attackRect, Color.cyan ); + createQuadButton( jumpRect, Color.magenta ); + } + + + void createQuadButton( TKRect rect, Color color ) + { + color.a = 0.2f; + + // find the center point in Unity units + var center = Camera.main.ScreenToWorldPoint( rect.center ); + center.z = 0; + + // create the quad button + var button = GameObject.CreatePrimitive( PrimitiveType.Quad ); + button.transform.position = center; + button.GetComponent().material.shader = Shader.Find( "Sprites/Default" ); + button.GetComponent().material.color = color; + + // scale the quad button accordingly + button.transform.localScale = new Vector3 + ( + TouchKit.instance.pixelsToUnityUnitsMultiplier.x * rect.width, + TouchKit.instance.pixelsToUnityUnitsMultiplier.y * rect.height + ); + } + + + void setupRecognizers() + { + // left button + _leftRecognizer = new TKAnyTouchRecognizer( new TKRect( 0f, 0f, buttonWidth, buttonHeight ) ); + TouchKit.addGestureRecognizer( _leftRecognizer ); + + + // right button + _rightRecognizer = new TKAnyTouchRecognizer( new TKRect( buttonWidth + 1f, 0f, buttonWidth, buttonHeight ) ); + TouchKit.addGestureRecognizer( _rightRecognizer ); + + + // up button. we place it 70% of the way up the other two buttons allowing some overlap + _upRecognizer = new TKAnyTouchRecognizer( new TKRect( 0f, buttonHeight * 0.7f, buttonWidth * 2f + 1f, 20f ) ); + TouchKit.addGestureRecognizer( _upRecognizer ); + + + // attack button. we use the onSelectedEvent here because we only want to know the exact frame it was pressed + _attackRecognizer = new TKButtonRecognizer( new TKRect( TouchKit.instance.designTimeResolution.x - buttonWidth * 2f, 0, buttonWidth, buttonHeight ), 0f ); + _attackRecognizer.onSelectedEvent += ( r ) => + { + attackDown = true; + }; + TouchKit.addGestureRecognizer( _attackRecognizer ); + + + // jump button + _jumpRecognizer = new TKButtonRecognizer( new TKRect( TouchKit.instance.designTimeResolution.x - buttonWidth, 0, buttonWidth, buttonHeight ), 0f ); + TouchKit.addGestureRecognizer( _jumpRecognizer ); + } + +} diff --git a/Assets/TouchKit/TouchKitDemos/DemoTwo/VirtualControls.cs.meta b/Assets/TouchKit/TouchKitDemos/DemoTwo/VirtualControls.cs.meta new file mode 100644 index 00000000..0a64bb86 --- /dev/null +++ b/Assets/TouchKit/TouchKitDemos/DemoTwo/VirtualControls.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9dbccd6fa8ec6447aaa2b359982e10a0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/TouchKit/TouchKitLite.meta b/Assets/TouchKit/TouchKitLite.meta new file mode 100644 index 00000000..4eeea507 --- /dev/null +++ b/Assets/TouchKit/TouchKitLite.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 37184f9b6bcba44e4a734f97b8c92dda +folderAsset: yes +timeCreated: 1434758149 +licenseType: Pro +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TouchKit/TouchKitLite/TKLSwipeDetector.cs b/Assets/TouchKit/TouchKitLite/TKLSwipeDetector.cs new file mode 100644 index 00000000..7f126402 --- /dev/null +++ b/Assets/TouchKit/TouchKitLite/TKLSwipeDetector.cs @@ -0,0 +1,178 @@ +using UnityEngine; +using System.Collections.Generic; +using System; + + +namespace Prime31 +{ + +public enum SwipeDirection +{ + Left = ( 1 << 0 ), + Right = ( 1 << 1 ), + Up = ( 1 << 2 ), + Down = ( 1 << 4 ), + Horizontal = ( Left | Right ), + Vertical = ( Up | Down ), + All = ( Horizontal | Vertical ) +} + + +public class TKLSwipeDetector : MonoBehaviour +{ + public event Action onSwipeDeteced; + + + public float timeToSwipe = 0.5f; + public float swipeVelocity; + SwipeDirection completedSwipeDirection; + + public float _minimumDistance = 2f; + public float _allowedVariance = 1.5f; + public SwipeDirection _swipesToDetect = SwipeDirection.All; + + // swipe state info + private Vector2 _startPoint; + private float _startTime; + private SwipeDirection _swipeDetectionState; + // the current swipes that are still possibly valid + bool _didCompleteDetection = true; + + + void Update() + { + // dont process drags if we have no input + if( TouchKitLite.instance.liveTouches.Count == 0 ) + return; + + var touch = TouchKitLite.instance.liveTouches[0]; + + // touch down, possible chance for a swipe + if( touch.phase == TouchPhase.Began ) + { + _swipeDetectionState = _swipesToDetect; + _startPoint = touch.position; + _startTime = Time.time; + _didCompleteDetection = false; + } + else if( touch.phase == TouchPhase.Moved ) + { + if( !_didCompleteDetection && checkForSwipeCompletion( touch ) ) + { + _didCompleteDetection = true; + if( onSwipeDeteced != null ) + onSwipeDeteced( completedSwipeDirection ); + } + } + } + + + private bool checkForSwipeCompletion( TKLTouch touch ) + { + // if we have a time stipulation and we exceeded it stop listening for swipes + if( timeToSwipe > 0.0f && ( Time.time - _startTime ) > timeToSwipe ) + { + return false; + } + + + // when dealing with standalones (non touch-based devices) we need to be careful what we examaine + // we filter out all touches (mouse movements really) that didnt move + #if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + if( touch.deltaPosition.x != 0.0f || touch.deltaPosition.y != 0.0f ) + { + #endif + // check the delta move positions. We can rule out at least 2 directions + if( touch.deltaPosition.x > 0.0f ) + _swipeDetectionState &= ~SwipeDirection.Left; + if( touch.deltaPosition.x < 0.0f ) + _swipeDetectionState &= ~SwipeDirection.Right; + + if( touch.deltaPosition.y < 0.0f ) + _swipeDetectionState &= ~SwipeDirection.Up; + if( touch.deltaPosition.y > 0.0f ) + _swipeDetectionState &= ~SwipeDirection.Down; + + #if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + } + #endif + + //Debug.Log( string.Format( "swipeStatus: {0}", swipeDetectionState ) ); + + // Grab the total distance moved in both directions + var xDeltaAbsCm = Mathf.Abs( _startPoint.x - touch.position.x ) / TouchKitLite.instance.screenPixelsPerCm; + var yDeltaAbsCm = Mathf.Abs( _startPoint.y - touch.position.y ) / TouchKitLite.instance.screenPixelsPerCm; + + // only check for swipes in directions that havent been ruled out yet + // left check + if( ( _swipeDetectionState & SwipeDirection.Left ) != 0 ) + { + if( xDeltaAbsCm > _minimumDistance ) + { + if( yDeltaAbsCm < _allowedVariance ) + { + completedSwipeDirection = SwipeDirection.Left; + swipeVelocity = xDeltaAbsCm / ( Time.time - _startTime ); + return true; + } + + // We exceeded our variance so this swipe is no longer allowed + _swipeDetectionState &= ~SwipeDirection.Left; + } + } + + // right check + if( ( _swipeDetectionState & SwipeDirection.Right ) != 0 ) + { + if( xDeltaAbsCm > _minimumDistance ) + { + if( yDeltaAbsCm < _allowedVariance ) + { + completedSwipeDirection = SwipeDirection.Right; + swipeVelocity = xDeltaAbsCm / ( Time.time - _startTime ); + return true; + } + + // We exceeded our variance so this swipe is no longer allowed + _swipeDetectionState &= ~SwipeDirection.Right; + } + } + + // up check + if( ( _swipeDetectionState & SwipeDirection.Up ) != 0 ) + { + if( yDeltaAbsCm > _minimumDistance ) + { + if( xDeltaAbsCm < _allowedVariance ) + { + completedSwipeDirection = SwipeDirection.Up; + swipeVelocity = yDeltaAbsCm / ( Time.time - _startTime ); + return true; + } + + // We exceeded our variance so this swipe is no longer allowed + _swipeDetectionState &= ~SwipeDirection.Up; + } + } + + // down check + if( ( _swipeDetectionState & SwipeDirection.Down ) != 0 ) + { + if( yDeltaAbsCm > _minimumDistance ) + { + if( xDeltaAbsCm < _allowedVariance ) + { + completedSwipeDirection = SwipeDirection.Down; + swipeVelocity = yDeltaAbsCm / ( Time.time - _startTime ); + return true; + } + + // We exceeded our variance so this swipe is no longer allowed + _swipeDetectionState &= ~SwipeDirection.Down; + } + } + + return false; + } +} +} diff --git a/Assets/TouchKit/TouchKitLite/TKLSwipeDetector.cs.meta b/Assets/TouchKit/TouchKitLite/TKLSwipeDetector.cs.meta new file mode 100644 index 00000000..4f05208b --- /dev/null +++ b/Assets/TouchKit/TouchKitLite/TKLSwipeDetector.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 11d446fb7bf8547c2b2ea2bc44c731dc +timeCreated: 1434758615 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TouchKit/TouchKitLite/TKLTouch.cs b/Assets/TouchKit/TouchKitLite/TKLTouch.cs new file mode 100644 index 00000000..cdc4c753 --- /dev/null +++ b/Assets/TouchKit/TouchKitLite/TKLTouch.cs @@ -0,0 +1,143 @@ +using UnityEngine; +using System.Collections; + + +namespace Prime31 { + +public class TKLTouch +{ + public readonly int fingerId; + public Vector2 position; + public Vector2 deltaPosition; + public float deltaTime; + public int tapCount; + public TouchPhase phase = TouchPhase.Ended; + + public Vector2 previousPosition + { + get { return position - deltaPosition; } + } + +#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + // used to track mouse movement and fake touches + private Vector2? _lastPosition; + private double _lastClickTime; + private double _multipleClickInterval = 0.2; +#endif + + + public TKLTouch( int fingerId ) + { + // lock this TKLTouch to the fingerId + this.fingerId = fingerId; + } + + + public TKLTouch populateWithTouch( Touch touch ) + { + position = touch.position; + deltaPosition = touch.deltaPosition; + deltaTime = touch.deltaTime; + tapCount = touch.tapCount; + + // canceled and ended are the same to us + if( touch.phase == TouchPhase.Canceled ) + phase = TouchPhase.Ended; + else + phase = touch.phase; + + return this; + } + + + /// + /// populates the TKLTouch with either mouse or touch input + /// + public void populate() + { +#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + if (!UnityEditor.EditorApplication.isRemoteConnected) + populateFromMouse(); +#else + populateWithTouch( Input.touches[0] ); +#endif + } + + + public bool hasMouseInput() + { + return Input.GetMouseButtonUp( 0 ) || Input.GetMouseButton( 0 ); + } + + +#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + public TKLTouch populateWithPosition( Vector3 currentPosition, TouchPhase touchPhase ) + { + var currentPosition2d = new Vector2( currentPosition.x, currentPosition.y ); + + // if we have a lastMousePosition use it to get a delta + if( _lastPosition.HasValue ) + deltaPosition = currentPosition2d - _lastPosition.Value; + else + deltaPosition = new Vector2( 0, 0 ); + + switch( touchPhase ) + { + case TouchPhase.Began: + phase = TouchPhase.Began; + + // check for multiple clicks + if( Time.time < _lastClickTime + _multipleClickInterval ) + tapCount++; + else + tapCount = 1; + _lastPosition = currentPosition2d; + _lastClickTime = Time.time; + break; + case TouchPhase.Stationary: + case TouchPhase.Moved: + if( deltaPosition.sqrMagnitude == 0 ) + phase = TouchPhase.Stationary; + else + phase = TouchPhase.Moved; + + _lastPosition = currentPosition2d; + break; + case TouchPhase.Ended: + phase = TouchPhase.Ended; + _lastPosition = null; + break; + } + + position = currentPosition2d; + + return this; + } + + + public TKLTouch populateFromMouse() + { + // do we have some input to work with? + if( hasMouseInput() ) + { + TouchPhase phase = TouchPhase.Moved; + if( Input.GetMouseButtonUp( 0 ) ) + phase = TouchPhase.Ended; + if( Input.GetMouseButtonDown( 0 ) ) + phase = TouchPhase.Began; + + var currentMousePosition = new Vector2( Input.mousePosition.x, Input.mousePosition.y ); + this.populateWithPosition( currentMousePosition, phase ); + } + + return this; + } +#endif + + + public override string ToString() + { + return string.Format( "[TKLTouch] fingerId: {0}, phase: {1}, position: {2}", fingerId, phase, position ); + } + +}} \ No newline at end of file diff --git a/Assets/TouchKit/TouchKitLite/TKLTouch.cs.meta b/Assets/TouchKit/TouchKitLite/TKLTouch.cs.meta new file mode 100644 index 00000000..656beb0f --- /dev/null +++ b/Assets/TouchKit/TouchKitLite/TKLTouch.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: dd67e044dba9145e4b372b0efe14cb35 +timeCreated: 1434758248 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/TouchKit/TouchKitLite/TouchKitLite.cs b/Assets/TouchKit/TouchKitLite/TouchKitLite.cs new file mode 100644 index 00000000..db35e0eb --- /dev/null +++ b/Assets/TouchKit/TouchKitLite/TouchKitLite.cs @@ -0,0 +1,119 @@ +using UnityEngine; +using System.Collections.Generic; + + +namespace Prime31 { + +public class TouchKitLite : MonoBehaviour +{ + public bool shouldProcessTouches = true; + const int kTotalTouchesToProcess = 2; + + + public List liveTouches = new List( 2 ); + TKLTouch[] _touchCache; + const float inchesToCentimeters = 2.54f; + + public float screenPixelsPerCm + { + get + { + var fallbackDpi = 72f; + + #if UNITY_ANDROID + // Android MDPI setting fallback + // http://developer.android.com/guide/practices/screens_support.html + fallbackDpi = 160f; + #elif UNITY_WP8 || UNITY_WP8_1 || UNITY_WSA || UNITY_WSA_8_0 + // Windows phone is harder to track down + // http://www.windowscentral.com/higher-resolution-support-windows-phone-7-dpi-262 + fallbackDpi = 92f; + #elif UNITY_IOS + // iPhone 4-6 range + fallbackDpi = 326f; + #endif + + return Screen.dpi == 0f ? fallbackDpi / inchesToCentimeters : Screen.dpi / inchesToCentimeters; + } + } + + + private static TouchKitLite _instance = null; + public static TouchKitLite instance + { + get + { + if( System.Object.Equals( _instance, null ) ) + _instance = FindObjectOfType( typeof( TouchKitLite ) ) as TouchKitLite; + + return _instance; + } + } + + + #region MonoBehaviour + + void Awake() + { + // prep our TKLTouch cache so we avoid excessive allocations + _touchCache = new TKLTouch[kTotalTouchesToProcess]; + for( int i = 0; i < kTotalTouchesToProcess; i++ ) + _touchCache[i] = new TKLTouch( i ); + } + + + void Update() + { + liveTouches.Clear(); + + if( !shouldProcessTouches ) + return; + +#if UNITY_EDITOR || UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_WEBPLAYER || UNITY_WEBGL + + // we only need to process if we have some interesting input this frame + if( Input.GetMouseButtonUp( 0 ) || Input.GetMouseButton( 0 ) ) + { +#if UNITY_EDITOR + // in the editor if the remote is not connected we use the mouse to simulate touch + if( !UnityEditor.EditorApplication.isRemoteConnected ) +#endif + liveTouches.Add( _touchCache[0].populateFromMouse() ); + } + +#endif + + + if( Input.touchCount > 0 ) + { + var maxTouchIndexToExamine = Mathf.Min( Input.touches.Length, kTotalTouchesToProcess ); + for( var i = 0; i < maxTouchIndexToExamine; i++ ) + { + var touch = Input.touches[i]; + if( touch.fingerId < kTotalTouchesToProcess ) + liveTouches.Add( _touchCache[touch.fingerId].populateWithTouch( touch ) ); + } + } + } + + + void OnApplicationQuit() + { + _instance = null; + } + + #endregion + + + public bool hasTouchBeganInRect( Rect rect ) + { + for( var i = 0; i < liveTouches.Count; i++ ) + { + var touch = liveTouches[i]; + if( touch.phase == TouchPhase.Began && rect.Contains( touch.position ) ) + return true; + } + + return false; + } +}} diff --git a/Assets/TouchKit/TouchKitLite/TouchKitLite.cs.meta b/Assets/TouchKit/TouchKitLite/TouchKitLite.cs.meta new file mode 100644 index 00000000..f48a9ecb --- /dev/null +++ b/Assets/TouchKit/TouchKitLite/TouchKitLite.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: c9b42263bedf3484b87e7191b7a5501b +timeCreated: 1434758154 +licenseType: Pro +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: