Spinning an object using touch input

Hey guys and gals,

I have literally been pulling my hair out for a few days over this. I have done countless test builds to my iPad to try to fix the issue all to no avail. I feel that I can’t move on until I solve this problem.

I am simply trying to spin an object smoothly based on user touches and swipes. The code (below) which I have cobbled together from various sources (based on mouse input) is largely working as expected. It is currently configured to spin an object using one finger. However it seems that if the user spins the object leaving the first finger on the screen and places another finger down. On the release of the second finger (with the first one still touching) the object jumps to an unexpected angle! I have a feeling this should be a fairly simple fix and that I am doing something rather silly. Any input would be seriously appreciated.

Here is my current code (just attached to any object, currently using a simple cube). There is some ugly stuff here (like using onMouseDown) this is mainly so that I can test the script to some extent without having to build it each time. The unity remote is practically useless when testing touches… so damn laggy and unresponsive.

//Start code

var rotationSpeed = 2.0;
var lerpSpeed = 1.0;

private var speed = new Vector3();
private var avgSpeed = new Vector3();
private var dragging = false;
private var targetSpeedX = new Vector3();

function OnMouseDown() 
{
    dragging = true;
}

function Update() {

if (Input.touchCount == 1)
{
    var theTouch : Touch = Input.GetTouch(0);

    if (theTouch.phase == TouchPhase.Moved)
    {
    	OnMouseDown();
    }

    if ((theTouch.phase == TouchPhase.Ended) || (theTouch.phase == TouchPhase.Canceled))
    {
		dragging = false;
    }
 }

 if (Input.touchCount > 1)
{
    dragging = false;
}

    //Debug.Log ("Speed = " + speed);
    //Debug.Log ("Dragging = " + dragging);

    if ((theTouch.phase == TouchPhase.Moved) && dragging)
    	{
        speed = new Vector3(theTouch.position.x, theTouch.position.y, 0);
        avgSpeed = Vector3.Lerp(avgSpeed,speed,Time.deltaTime * 5);
    	}


    if (Input.GetMouseButton(0) && dragging) 
    	{
        speed = new Vector3(-Input.GetAxis ("Mouse X"), Input.GetAxis("Mouse Y"), 0);
        avgSpeed = Vector3.Lerp(avgSpeed,speed,Time.deltaTime * 5);
    	}

     else 
        {
        if (dragging) {
            speed = avgSpeed;
            dragging = false;
        }
        var i = Time.deltaTime * lerpSpeed;
        speed = Vector3.Lerp( speed, Vector3.zero, i);   
    }

    transform.Rotate( Camera.main.transform.up * speed.x * rotationSpeed, Space.World );
    transform.Rotate( Camera.main.transform.right * speed.y * rotationSpeed, Space.World );

}

//End code snippet

Hello!

I made this C# script. I think this is the easiest way to spin an object. Simply attach it to your object and it will spin while drag, and when you release the spin will slow down.

using UnityEngine;
using System.Collections;

public class SpinLogic : MonoBehaviour {

	float f_lastX = 0.0f;
	float f_difX = 0.5f;
	float f_steps = 0.0f;
	int i_direction = 1;

	// Use this for initialization
	void Start () 
	{
		
	}
	
	// Update is called once per frame
	void Update () 
	{
		if (Input.GetMouseButtonDown(0))
		{
			f_difX = 0.0f;
		}
		else if (Input.GetMouseButton(0))
		{
			f_difX = Mathf.Abs(f_lastX - Input.GetAxis ("Mouse X"));

			if (f_lastX < Input.GetAxis ("Mouse X"))
			{
				i_direction = -1;
				transform.Rotate(Vector3.up, -f_difX);
			}

			if (f_lastX > Input.GetAxis ("Mouse X"))
			{
				i_direction = 1;
				transform.Rotate(Vector3.up, f_difX);
			}

			f_lastX = -Input.GetAxis ("Mouse X");
		}
		else 
		{
			if (f_difX > 0.5f) f_difX -= 0.05f;
			if (f_difX < 0.5f) f_difX += 0.05f;

			transform.Rotate(Vector3.up, f_difX * i_direction);
		}
	}
}

I hope it helps!

Happy Coding!

Ok I found the original clean and beautiful code (from user duck) that I brutally butchered with the finesse of a drunk rhino above. Thinking about it i really wish i posted this in response to the thread i found ducks example in:

I’m basically trying to make this work as well as it does with a mouse but with fingers on a touchscreen with no unexpected issues with potentially multiple fingers touching and releasing in the heat of action. Should be a simple conversion job, but for me it is turning into a real nightmare. I feel so stupid right now. Please don’t think I’m some script kiddie that wants something for free without working for it. I literally can’t get my head around what may be wrong and have spent 2 full days on this tweaking/rebuilding/failing/starting over/coming back/swearing etc. This motion working properly and reliably is the only thing holding me back and it is the main action for my game so it needs to be as efficient as possible. Thanks so much for any help, suggestions or if you must negative comments :wink:

var rotationSpeed = 10.0;
var lerpSpeed = 1.0;

private var speed = new Vector3();
private var avgSpeed = new Vector3();
private var dragging = false;
private var targetSpeedX = new Vector3();

function OnMouseDown() 
{
    dragging = true;
}

function Update () 
{

    if (Input.GetMouseButton(0) && dragging) {
        speed = new Vector3(-Input.GetAxis ("Mouse X"), Input.GetAxis("Mouse Y"), 0);
        avgSpeed = Vector3.Lerp(avgSpeed,speed,Time.deltaTime * 5);
    } else {
        if (dragging) {
            speed = avgSpeed;
            dragging = false;
        }
        var i = Time.deltaTime * lerpSpeed;
        speed = Vector3.Lerp( speed, Vector3.zero, i);   
    }

    transform.Rotate( Camera.main.transform.up * speed.x * rotationSpeed, Space.World );
    transform.Rotate( Camera.main.transform.right * speed.y * rotationSpeed, Space.World );

}

Here’s my version that uses physics and touch input from a mobile device if it can help anyone

using UnityEngine;
using System.Collections;

public class SpinWithTouch : MonoBehaviour
{
    public Rigidbody rb;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
    }

    void Update()
    {
        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
        {
            // Get movement of the finger since last frame
            Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;

            rb.AddTorque(Camera.main.transform.up * -touchDeltaPosition.x);
            rb.AddTorque(Camera.main.transform.right * touchDeltaPosition.y);
        }
    }
}

Following @stek very simple and very helpful example. I took his code and modified it so it can spin on both sides while accepting touch controls so it can work on mobile devices. Simply, attach the script to the spinning object. Bare with me, i am a beginner. The script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpinWheelScript : MonoBehaviour {

float pointerY;
float f_lastX = 0.0f;
float f_difX = 0.5f;
float f_steps = 0.0f;
int i_direction = 1;

void Start()
{
    pointerY = Input.GetAxis("Mouse Y");
}

void Update()
{

    if (Input.GetMouseButtonDown(0))
    {
        f_difX = 0.0f;
    }

    else if (Input.touchCount > 0)
    {
        pointerY = Input.touches[0].deltaPosition.y;
        f_difX = Mathf.Abs(f_lastX - pointerY);
        var touch = Input.GetTouch(0);

        if (touch.position.x > Screen.width / 2)
        {
            // Right
            if (f_lastX < Input.GetAxis("Mouse Y"))
            {
                i_direction = 1;
                transform.Rotate(Vector3.forward, f_difX * Time.deltaTime);
            }

            if (f_lastX > Input.GetAxis("Mouse Y"))
            {
                i_direction = -1;
                transform.Rotate(Vector3.forward, -f_difX * Time.deltaTime);
            }
        }
        else if (touch.position.x < Screen.width / 2)
        {
            // Left
            if (f_lastX < Input.GetAxis("Mouse Y"))
            {
                i_direction = -1;
                transform.Rotate(Vector3.forward, -f_difX * Time.deltaTime);
            }

            if (f_lastX > Input.GetAxis("Mouse Y"))
            {
                i_direction = 1;
                transform.Rotate(Vector3.forward, f_difX * Time.deltaTime);
            }
        }

        f_lastX = -pointerY;
        f_difX = 500f;
    Debug.Log(f_difX);
    }
    else
    {
        if (f_difX > 0.5f) f_difX -= 1f;
        if (f_difX < 0.5f) f_difX += 1f;

        transform.Rotate(Vector3.forward, f_difX * i_direction * Time.smoothDeltaTime);
    }
}
}

Currently, the object will spin based on a swipe along the Y axis, you can simple change it by replacing the Y’s with X’s. Also, i’ve modified the speeds to fit my liking. Hope this helps.

Cheers!

I don’t know if anyone else needs this. But in my case I didn’t want the object to rotate, but rather rotate the camera around it, so this is the script I made (for mobile), in case anyone else wants something similar. (The swiper object is an empty gameobject which is the parent of the camera. I didn’t include code to change the swiper transform to match the object since I only use one object, but that should be easy to add if you need to rotate many different things). cheers :slight_smile:

using UnityEngine;
using UnityEngine.EventSystems;

public class Rotator : MonoBehaviour, IDragHandler
{
    public Transform world;
    public GameObject swiper;
    public float zoomSpeed;
    float direction;

    public void OnDrag(PointerEventData eventData)
    {
        if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Moved)
        {

            // Get movement of the finger since last frame
            Vector2 touchDeltaPosition = Input.GetTouch(0).deltaPosition;

            //actual touch
            Touch touchZero = Input.GetTouch(0);
            //current touch x position
            float touchZeroCurrPos = touchZero.position.x;
            //previous touch x position
            float touchZeroPrevPos = touchZero.position.x - touchDeltaPosition.x;
            //difference between previous and current finger position
            float Diff = touchZeroPrevPos - touchZeroCurrPos;

           
            if (touchZeroCurrPos < touchZeroPrevPos )
            {
                Debug.Log("right");
                direction = -1;
                swiper.transform.Rotate(Vector3.up, -Diff * Time.deltaTime * zoomSpeed);
            }
            if (touchZeroCurrPos > touchZeroPrevPos)
            {
                Debug.Log("left");
                direction = 1;
                swiper.transform.Rotate(Vector3.down, Diff * Time.deltaTime * zoomSpeed);
            }

        }
    }
}

Hi Unity Forum.
I’m using @stek rotate script above, which works really well but when I attach the script to a second object, both objects rotate together.
How would I make 2 objects rotate independently of each-other?

Is this possible?

Thank you

Charles

Hello, I followed the script of XX, to perform the touch on the object to open a url. Works fine on the computer, but when I install on android and click nothing happens.
Can anyone help? I had never worked with unity and vuforia, I am a curious beginner.

using UnityEngine;
using System.Collections;

public class SpinLogic : MonoBehaviour
{

    float f_lastX = 0.0f;
    float f_difX = 0.5f;
    float f_steps = 0.0f;
    int i_direction = 1;

    // Use this for initialization
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Application.OpenURL("www.google.com");
        }
       
    }
}