yotiky Tech Blog

とあるエンジニアの備忘録

Unity - マウスドラッグでオブジェクトを回転させる

対象のオブジェクトをドラッグで回転させるサンプルスクリプト

f:id:yotiky:20200805015106g:plain

public class ObjectRotator : MonoBehaviour
{
    public GameObject targetObject;
    public Vector2 rotationSpeed = new Vector2(0.1f, 0.2f);
    public bool reverse;
    public float zoomSpeed = 1;

    private Camera mainCamera;
    private Vector2 lastMousePosition;

    void Start()
    {
        mainCamera = Camera.main;
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            lastMousePosition = Input.mousePosition;
        }
        else if (Input.GetMouseButton(0))
        {
            if (!reverse)
            {
                var x = (Input.mousePosition.y - lastMousePosition.y);
                var y = (lastMousePosition.x - Input.mousePosition.x);

                var newAngle = Vector3.zero;
                newAngle.x = x * rotationSpeed.x;
                newAngle.y = y * rotationSpeed.y;

                targetObject.transform.Rotate(newAngle);
                lastMousePosition = Input.mousePosition;
            }
            else
            {
                var x = (lastMousePosition.y - Input.mousePosition.y);
                var y = (Input.mousePosition.x - lastMousePosition.x);

                var newAngle = Vector3.zero;
                newAngle.x = x * rotationSpeed.x;
                newAngle.y = y * rotationSpeed.y;

                targetObject.transform.Rotate(newAngle);
                lastMousePosition = Input.mousePosition;
            }
        }
    }
}

回転方向を制限したり、マウスの移動量で縦か横どちらかだけを有効にする場合。

適当なenumを定義して、

public enum RotatableAxis
{
    None,
    X,
    Y,
    XY,
}

rotationSpeed をかける前あたりで、無効な回転軸の値を0にしてしまう。RotatableAxis.XY だった場合は、Mathf.Abs で絶対値を取得できるので、左右または上下どちらに動かした場合でも移動量が大きい方が有効値となる。

    if (rotatableAxis == RotatableAxis.None)
        x = y = 0;
    else if (rotatableAxis == RotatableAxis.X)
        y = 0;
    else if (rotatableAxis == RotatableAxis.Y)
        x = 0;
    else if (Mathf.Abs(x) < Mathf.Abs(y))
        x = 0;
    else
        y = 0;
    
    var newAngle = Vector3.zero;
    newAngle.x = x * rotationSpeed.x;
    newAngle.y = y * rotationSpeed.y;

回転角度に上限を設ける場合。

    [Range(0, 360)]
    public float RotationAngleX;
    [Range(0, 360)]
    public float RotationAngleY;
            // 回転方向を一方に絞る
            if (rotatableAxis == RotatableAxis.Y || Mathf.Abs(x) < Mathf.Abs(y))
                x = 0;
            else
                y = 0;

            // X軸
            var localAngle = targetObject.transform.localEulerAngles;
            localAngle.x += x * rotationSpeed.x;

            // 回転制限
            var halfAngleX = RotationAngleX / 2;
            if (halfAngleX < localAngle.x && localAngle.x < 180)
                localAngle.x = halfAngleX;
            if (180 < localAngle.x && localAngle.x < 360 - halfAngleX)
                localAngle.x = 360 - halfAngleX;
            
            targetObject.transform.localEulerAngles = localAngle;

            // Y軸
            var angle = targetObject.transform.eulerAngles;
            angle.y += y * rotationSpeed.y;

            // 回転制限
            var halfAngleY = RotationAngleY / 2;
            if (halfAngleY < angle.y && angle.y < 180)
                angle.y = halfAngleY;
            if (180 < angle.y && angle.y < 360 - halfAngleY)
                angle.y = 360 - halfAngleY;

            targetObject.transform.eulerAngles = angle;