3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-06-22

Slerpの回転終了を検知したい!

Unityで滑らかな回転を実現してくれるQuaternion.Slerpを使う機会があったのですが
その回転終了を検知するのに手間取ったお話です
回転している間は入力を受け付けたくない時などに使えると思います

Sleap0.gif

いろいろ試してみた

ド直球にやってみる


if (transform.eulerAngles == rotAngle)
{
    Debug.Log("回転終了");
}

transform.eulerAngles : Vecotr3(オイラー角)で角度を取得
rotAngle : Vector3型の変数名、回転後の角度

これで取れると思ったのですが
Sleap4.gif

なぜか反応なし…
そこで回転している軸の成分(Z軸ならtransform.eulerAngles.z)だけ見てみると…
Sleap1.gif
※90°まで回そうとした際の値です
あと少しのところで止まっていることが判明、道理でできないわけだ……

少し変えてみる


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 : 最も近い整数を偶数丸めで返す、四捨五入に近いやつ

実行してみると
Sleap2.gif

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

結局

以下のようにしました


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 : 与えられた角度の差を求める
分かりにくいですが0°と360°なら0が返り、0°と390°なら30が返ってきます

サンプルコード

改造等ご自由にどうぞ

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;
        }
    }
}

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


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

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?