Posted at

Unityで回転したかったお話

More than 3 years have passed since last update.

Unityでオブジェクトを指定した角度分回転したかっただけ…なのだけど結構時間をかけてしまったので残しておく…。

結果的には回転させる方法よりも角度を比較する方法が大事だったってお話。


ただ回転させたいだけならRotate


Transform.Rotate

transform.Rotate(new Vector3(0f,90f,0f)); // y軸を軸として90°回転



  • この方法だと一瞬でその方向に回転する。

  • なめらかな回転がしたかったので他の方法を考えることに。


オブジェクトの角度情報を持つメンバ


  • transform.rotation だと Quaternion 型で得られる。

  • transform.eulerAngles だと Vector3 型で得られる。


試行錯誤


eulerAnglesに直接加算する

if (Mathf.Abs (leftRotation - 90f) > 0.1f) {

leftRotation += 5f;
transform.eulerAngles += new Vector3 (0f, -5f, 0f);
}


  • eulerAngleで取ってきたオブジェクトに直接値を足して行く方法。

  • ちゃんと滑らかに動く。

  • でも今どこまで変化したか覚える変数がなんかダメな感じしたので消したくて却下。


    • 後になって考えたら条件を直せば消せた。




Quaternion.Slerpを使う

transform.rotation = Quaternion.Slerp(transform.rotation,newRotation,Time.deltaTime);


  • unity 回転 滑らか で検索するとコレを使う方法が多く引っかかった。

  • 向きは同じでも newRotation と transform.rotation の値に違いが出ることがあり、回転終了の検出が難しく断念


LeapAngleを使う

if (Mathf.Abs((transform.eulerAngles.y - fixAngleY(newAngle).y)) > 0.1f){

transform.eulerAngles = new Vector3(0f,Mathf.LerpAngle(transform.eulerAngles.y,newAngle.y,Time.deltaTime),0f);
}


  • LerpAngleはLeapの角度に対応したバージョンみたいなもの。これだと0と270を与えた時に0から270ではなく、0から-90(近い方に回転するように値が変化する)ようになる。

  • 動作的にはコレでもいけたけれど回転終了に向かうに連れて回転速度が落ちるのが気に入らなかったので却下。



  • DeltaAngleは与えた二つの角度の差を-180°〜180°の範囲内で返してくれる。


    • 例えば100と360を与えたら-100が返る。




結局以下のようにした

if (Mathf.DeltaAngle(transform.eulerAngles.y,newAngle.y) < -0.1f){

transform.Rotate (new Vector3 (0f, -5f, 0f));
}


  • 角度の比較が正しく行えるようになったので指定した角度に辿り着くまでちょっとずつRotate()

  • 直接加算する方法と結局は同じ…だと思う。

  • 比較部分について


    • DeltaAngleは与えた二つの角度の差を-180°〜180°の範囲内で返してくれる。


      • 例えば100と360を与えたら-100が返る。



    • 今回の場合、右回転の必要があれば正、左回転の必要があれば負、回転する必要がなければ0が帰ってくるのでそれでどう回転するかを判断する。


      • 実際には小数の演算誤差があるので0.1の猶予を与えている。






最初に言ったように回転させる方法よりも回転終了の検知を行うための向きの比較に手こずっていた感じでした。はじめから回転方法じゃなくて向きの比較方法に注目していれば時間はかからなかったかもしれません…。

本当はこう書くのが良いという意見があれば教えていただければ幸いです。