So I have this simple script that allows me to rotate a Cannon vertically or horizontally using the Input.Touch system. Code (CSharp): using UnityEngine; public class Swiper : MonoBehaviour { private Touch initTouch = new Touch(); private float rotX = 0f; private float rotY = 0f; private Vector3 origRot; public float rotSpeed = 0.2f; private float MinRotationY = -90f; private float MaxRotationY = 90f; private float MinRotationX = -55f; private float MaxRotationX = 0f; void Start() { origRot = transform.eulerAngles; rotX = origRot.x; rotY = origRot.y; } private void FixedUpdate() { foreach (Touch touch in Input.touches) { if (touch.phase == TouchPhase.Began) { initTouch = touch; } else if (touch.phase == TouchPhase.Moved) { float deltaX = touch.position.x - initTouch.position.x; float deltaY = touch.position.y - initTouch.position.y; rotX += deltaX * Time.deltaTime * rotSpeed; rotX = Mathf.Clamp(rotX, MinRotationY, MaxRotationY); // horizontal rotation of the cannon is around the Y axis. rotY += deltaY * Time.deltaTime * rotSpeed * -1f; rotY = Mathf.Clamp(rotY, MinRotationX, MaxRotationX); // vertical rotation of the cannon is around the X axis. transform.eulerAngles = new Vector3(rotY, rotX, 0f); // In portrait mode, swiping vertically = horizontal swipe in landscape mode. So rotY = x and rotX = y; } else if (touch.phase == TouchPhase.Ended) { initTouch = new Touch(); } } } } The problem is that, if you start swiping with one finger, and then start swiping with another finger (2 touches) the cannon has a very weird snappy behaviour. The desired behaviour is for the cannon to simply rotate normally. This fast 2 finger swipes may occur because it is a way for the player to swipe faster (alternating between 2 thumbs for example, but of course the "alternating" swipe will tend to overlap with each other, for example: thumb 1:S----------E~~~~~~~~S-----------E thumb 2:~~~~~~S------------E S = Start of swipe E = End of swipe As you can see, the first swipe of the thumb 2, overlaps with the first of the thumb 1. How can I then improve this script? Thanks in advance.
The problem is you are not tracking the fingerId of the first finger, so the second one comes in, which might end up in slot zero, and you track that. There's no guarantee of order of that list of touches, but the fingerId is consistent from finger to finger over the life of the swipe. https://docs.unity3d.com/ScriptReference/Touch-fingerId.html Broadly you need to "grab" a particular fingerId and ONLY pay attention that one until it is released. If you want to see my general-purpose "virtual analog button" example, check out the VAButton class (supported by the MicroTouch class) in my proximity_buttons project. proximity_buttons is presently hosted at these locations: https://bitbucket.org/kurtdekker/proximity_buttons https://github.com/kurtdekker/proximity_buttons https://gitlab.com/kurtdekker/proximity_buttons https://sourceforge.net/projects/proximity-buttons/ EDIT: you also MUST process input like this in Update(), not FixedUpdate()!!! If you do it in FixedUpdate() you will miss touch events.
Thank you, I made this small change to my script and is working nicely. I'll leave it here for anyone who needs it. Basically I added a Dictionary where the Key is the fingerID and the Value is the Initial touch. Adding a new Key-Value pair everytime the touch is in Began phase. Then i'm fetching that initial touch on the Moved phase. Finally I remove it from the Dictionary on the Ended phase. Code (CSharp): using System.Collections.Generic; using UnityEngine; public class Swiper : MonoBehaviour { private float RotX = 0f; private float RotY = 0f; private Vector3 OrigRot; public float RotSpeed = 0.2f; private float MinRotationY = -90f; private float MaxRotationY = 90f; private float MinRotationX = -55f; private float MaxRotationX = 0f; Dictionary<int, Touch> touches = new Dictionary<int, Touch>(); // the touch fingerID (key) and the initial touch value. void Start() { OrigRot = transform.eulerAngles; RotX = OrigRot.x; RotY = OrigRot.y; } private void Update() { foreach (Touch touch in Input.touches) { if (touch.phase == TouchPhase.Began) { if(!touches.ContainsKey(touch.fingerId)) touches.Add(touch.fingerId, touch); } else if (touch.phase == TouchPhase.Moved) { Touch initialTouch = touches[touch.fingerId]; float deltaX = touch.position.x - initialTouch.position.x; float deltaY = touch.position.y - initialTouch.position.y; RotX += deltaX * Time.deltaTime * RotSpeed; RotX = Mathf.Clamp(RotX, MinRotationY, MaxRotationY); // horizontal rotation of the cannon is around the Y axis. RotY += deltaY * Time.deltaTime * RotSpeed * -1f; RotY = Mathf.Clamp(RotY, MinRotationX, MaxRotationX); // vertical rotation of the cannon is around the X axis. transform.eulerAngles = new Vector3(RotY, RotX, 0f); // In portrait mode, swiping vertically = horizontal swipe in landscape mode. So rotY = x and rotX = y; } else if (touch.phase == TouchPhase.Ended) { touches.Remove(touch.fingerId); } } } }