DOTweenでカーブさせる


DOTween便利

 1週間ほど前にDOTween使い始めました。便利ですねこれ。
 ただ、ちょっと探した感じ、オブジェクトを円周上でカーブさせる方法が見つかりませんでした。パスをうまいことやるとそれっぽいことができるようですが、勉強がてら拡張メソッドを書いてみました。

できたやつ

DOCurveAroundAndRotateの実行の様子。Cylinderを中心にCubeが回転している。

public static class DoTweenExt
{
    //centerを中心、axisを軸として、degree(度)回転する
    public static TweenerCore<float, float, FloatOptions> DOCurveAround(this Transform transform, Vector3 axis, Vector3 center, float degree, float duration)
    {
        var from = Vector3.negativeInfinity;
        return DOTween.To(() => 0, (x) =>
            {
                if (float.IsNegativeInfinity(from.x)) from = transform.position;
                transform.position = Quaternion.AngleAxis(x, axis) * (from - center) + center;
            },
            degree,
            duration
        );
    }

    //オブジェクトそのものも回転させる
    public static TweenerCore<float, float, FloatOptions> DOCurveAroundAndRotate(this Transform transform, Vector3 axis, Vector3 center, float degree, float duration)
    {
        var from  = Vector3.negativeInfinity;
        var fromRot = Vector3.zero;
        return DOTween.To(() => 0, (x) =>
            {
                if (float.IsNegativeInfinity(from.x))
                {
                    from = transform.position;
                    fromRot = transform.localEulerAngles;
                }
                var q = Quaternion.AngleAxis(x, axis);
                transform.position = q * (from - center) + center;
                transform.localEulerAngles = fromRot + q.eulerAngles;
            },
            degree,
            duration
        );
    }

    //使い方
    //(x,y,z)=(2,0,0)を中心に3秒かけて90度回転させる。
    //transform.DOCurveAround(Vector3.up, new Vector3(2, 0, 0), 90, 3);
}

解説

 みんな大好き、Toメソッドを使います。Toの使い方ですが、

DOTween.To(() => Vector3.zero, (x) => transform.position = x, new Vector3(3, 0, 0), 1);

 (0,0,0)から(3,0,0)に1秒かけて移動します。

DOTween.To(() => 0, (x) => transform.position = new Vector3(x,0,0), 3, 1);

 上と意味は同じですが、変化する値があくまでもプリミティブなfloatになってます。このfloatを角度にして、角度からposition、localEulerAnglesを割り出します。

 それがCurveAroundAndRotateの

var q = Quaternion.AngleAxis(x, axis);
transform.position = q * (from - center) + center;
transform.localEulerAngles = fromRot + q.eulerAngles;

 この部分です。まずはQuaternionを出します。そのQuaternionと回転させたいVector3を掛ければ、(0,0,0)を中心に回転します。fromは開始位置ですが、あくまでもこの関数が走り始める時点での位置です。変数初期化時にtransform.positionを入れてしまうと、Sequenceで動かすときにおかしくなってしまいます。
 角度も同様で、関数が走り出す時点でのeulerAnglesをfromRotにとっておきます。で、fromRotとさっきのQuaternionのeulerAnglesとを足したものを放り込みます。

所感

 Quaternionってすげー

 ※ CurveAroundAndRotateでオブジェクトの向きがうまく変わらないバグがありましたので、修正しました。(2020/6/5)