UnityのSlerpで回転終了を検知する

# Slerpの回転終了を検知したい！
Unityで滑らかな回転を実現してくれる[Quaternion.Slerp](https://docs.unity3d.com/ja/current/ScriptReference/Quaternion.Slerp.html)を使う機会があったのですが
その回転終了を検知するのに手間取ったお話です
回転している間は入力を受け付けたくない時などに使えると思います


![Sleap0.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369539/102f4246-f54c-40b3-2f09-5a6ef7aed223.gif)
## いろいろ試してみた
### ド直球にやってみる
```c#

if (transform.eulerAngles == rotAngle)
{
    Debug.Log("回転終了");
}
```
[transform.eulerAngles](https://docs.unity3d.com/ja/2017.4/ScriptReference/Transform-eulerAngles.html) : Vecotr3(オイラー角)で角度を取得
rotAngle : Vector3型の変数名、回転後の角度

これで取れると思ったのですが
![Sleap4.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369539/ed79e4e5-f756-b68b-e638-83c35801c244.gif)

なぜか反応なし…
そこで回転している軸の成分(Z軸ならtransform.eulerAngles.z)だけ見てみると…
![Sleap1.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369539/196c5f3b-75c1-13f3-2fee-d199dcbe470c.gif)
※90°まで回そうとした際の値です
あと少しのところで止まっていることが判明、道理でできないわけだ……

### 少し変えてみる
```c#

if (Mathf.Round(transform.eulerAngles.x) == rotAngle.x &&
    Mathf.Round(transform.eulerAngles.y) == rotAngle.y &&
    Mathf.Round(transform.eulerAngles.z) == rotAngle.z)
{
    Debug.Log("回転終了");
}
```
[Mathf.Round](https://docs.unity3d.com/ja/current/ScriptReference/Mathf.Round.html) : 最も近い整数を偶数丸めで返す、四捨五入に近いやつ

実行してみると
![Sleap2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/369539/8e2bdb8c-2e76-4f8b-cf7e-efa53fcdcca6.gif)

一応できましたが0°に戻るときだけ検知が遅くなっているのが気になりますね…

### 結局
以下のようにしました

```c#

if (Mathf.DeltaAngle(Mathf.Round(transform.eulerAngles.x), rotAngle.x) == 0 &&
    Mathf.DeltaAngle(Mathf.Round(transform.eulerAngles.y), rotAngle.y) == 0 &&
    Mathf.DeltaAngle(Mathf.Round(transform.eulerAngles.z), rotAngle.z) == 0)
{
    Debug.Log("回転終了");
}
```
[Mathf.DeltaAngle](https://docs.unity3d.com/ja/2018.2/ScriptReference/Mathf.DeltaAngle.html) : 与えられた角度の差を求める
分かりにくいですが0°と360°なら0が返り、0°と390°なら30が返ってきます

## サンプルコード
改造等ご自由にどうぞ

```c#:Rotation.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// アタッチされたオブジェクトを回転させるスクリプト
/// </summary>
public class Rotation : MonoBehaviour
{
    private float rotSpeed;             //回転の速度
    private Vector3 rotAngle;           //回転後の角度
    private bool isRotation;            //回転中かどうか
    private const int ROT_MAX = 360;    //最大回転角

    private void Start()
    {
        //回転速度を設定
        rotSpeed = 5.0f;
    }
    private void Update()
    {
        if (isRotation == true)
        {
            //Slerpで回転
            transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.Euler(rotAngle), rotSpeed * Time.deltaTime);

            //終了検知
            if (Mathf.DeltaAngle(Mathf.Round(transform.eulerAngles.x), rotAngle.x) == 0 &&
                Mathf.DeltaAngle(Mathf.Round(transform.eulerAngles.y), rotAngle.y) == 0 &&
                Mathf.DeltaAngle(Mathf.Round(transform.eulerAngles.z), rotAngle.z) == 0)
            {
                transform.rotation = Quaternion.Euler(rotAngle);
                isRotation = false;
            }

        }
    }
    /// <summary>
    /// 回転を開始するメソッド
    /// </summary>
    public void StartSlerpRotate(Vector3 newAngle)
    {
        //回転中は入力を受け付けない
        if (isRotation == false)
        {
            //回転角度を0°～360°間でループさせる
            rotAngle = new Vector3(
            Mathf.Repeat(rotAngle.x + newAngle.x, ROT_MAX),
            Mathf.Repeat(rotAngle.y + newAngle.y, ROT_MAX),
            Mathf.Repeat(rotAngle.z + newAngle.z, ROT_MAX));
            //回転開始
            isRotation = true;
        }
    }
}

```
<p>
あとはStartSlerpRotateメソッドを呼んで回したい分の角度(Vector3型)を渡せばOKです
ちなみにですが渡ってきた値が360°を超えないように[Mathf.Repeat](https://docs.unity3d.com/ja/2017.4/ScriptReference/Mathf.Repeat.html)でループさせています

---
今回初めての投稿だったのですがいかがだったでしょうか。
わかりやすく出来ているといいのですが…
少しでもお役に立っていただければ幸いです