- Home /
Cylinder touch rotation
I'm trying to rotate a cylinder with touch. The behavior that I want is that if I touch the cylinder in point A and drag my finger straight to the left, Cylinder will rotate on Y Axis so that point A is always under my finger. I've tried this code but the cylinder kinda "slips" under the fingers.
using UnityEngine;
using System.Collections;
public class CR_Rotate : MonoBehaviour {
[SerializeField]
float _speed = 1f;
bool _canRotate = false;
Transform _cachedTransform;
public bool CanRotate
{
get { return _canRotate; }
private set { _canRotate = value; }
}
void Start () {
//Make reference to transform
_cachedTransform = transform;
}
// Update is called once per frame
void Update () {
if(Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
//Switch through touch events
switch(Input.GetTouch(0).phase)
{
case TouchPhase.Began:
if(VerifyTouch(touch))
CanRotate = true;
break;
case TouchPhase.Moved:
if(CanRotate)
RotateObject(touch);
break;
case TouchPhase.Ended:
CanRotate = false;
break;
}
}
}
///
/// Verifies the touch.
///
///
/// The touch.
///
///
/// If set to true touch.
///
bool VerifyTouch(Touch touch)
{
Ray ray = Camera.main.ScreenPointToRay(touch.position);
RaycastHit hit ;
//Check if there is a collider attached already, otherwise add one on the fly
if(collider == null)
gameObject.AddComponent(typeof(BoxCollider));
if (Physics.Raycast (ray, out hit))
{
if(hit.collider.gameObject == this.gameObject)
return true;
}
return false;
}
///
/// Rotates the object.
///
///
/// Touch.
///
void RotateObject(Touch touch)
{
_cachedTransform.Rotate(new Vector3(touch.deltaPosition.y, -touch.deltaPosition.x,0)*_speed, Space.World);
}
}
Answer by robertbu · Oct 04, 2013 at 04:11 PM
Imagine a clear upright cylinder with a dot on the font face rotating at a fixed rate. As the cylinder begins to rotate, almost all the motion is horizontal (X), but as it rotates more the motion is evermore 'Z' motion until the dot wraps to the backside. If just watch the dot as the cylinder rotates, the dot's motion is sinusoidal, not linear. So you cannot map your linear finger movement to a fixed rotation as you are doing with your code above and have the finger track the cylinder.
An alternate approach is to Raycast() against the cylinder and use the angle of the hit position to inform the rotation. Here is an example script:
using UnityEngine;
using System.Collections;
public class CylRot : MonoBehaviour {
private Quaternion qStart;
private Vector3 v3Start;
void OnMouseDown () {
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
Physics.Raycast (ray, out hit); // Shouldn't fail
v3Start = hit.point;
v3Start.y = transform.position.y;
qStart = transform.rotation;
v3Start = v3Start - transform.position;
}
void OnMouseDrag () {
RaycastHit hit;
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
if (Physics.Raycast (ray, out hit) && hit.transform == transform) {
Vector3 v3 = hit.point;
v3.y = transform.position.y;
v3 = v3 - transform.position;
transform.rotation = Quaternion.FromToRotation (v3Start, v3) * qStart;
}
}
}
I found it touchy at the left and right edge of the cylinder. You may want to add just a bit of smoothing, though that would also cause a bit more lag in the rotation.
P.S. I just remembered that cylinders use capsule colliders. You may want to replace the default collider with a mesh collider. You will have problems at the top and bottom otherwise.