概要
本記事では、UnityでMathf.Clamp()を用いて、特定の角度でオブジェクトを傾ける実装を解説します。
目的
本来Unityでは、オブジェクトの角度をTransformのRotationで管理することが一般的ですが、それでは値を比較することによる範囲制御ができません。
例えば、以下のような実装を想像してください。
if (transform.eulerAngle <= 30)
{
//処理の内容を記述
}
上記の実装では、30度以下という条件を用いています。しかし、50度という角度は、-310度とも表すことができるので、30度以下のような条件を満たすと捉えることができるのです。
以上のように、角度制御の実装を行うためには、Rotation以外を用いた実装が必要です。本記事では、Mathf.Clamp()を用いて、この問題を解決します。
Mathf.Clamp()とは?
Mathf.Clamp()とは、主に値の範囲を制御するための関数です。ここでは、範囲を制御するという説明に留めますが、より細かい説明を参照したい方は、公式のリファレンス等も参考にしてみてください。
さて、続いては引数として用いる値について、紹介していきます。Mathf.Clamp()を記述する際には、以下のように引数を用います。
Mathf.Clamp(float value, float max, float min)
基本的に、この関数が出力する値はvalueの値そのものです。ただし、minからmaxの範囲内に収まっているかを判断し、範囲外の場合には最寄りの値に変化させます。
使用例
最後に、以下のような実装の場合どのようになるか考えましょう。
using UnityEngine;
public class ClampSide : MonoBehaviour
{
// 最小値
public float min = -1;
// 最大値
public float max = 1;
// 判定する値
private float _value = 3;
private void Start()
{
// x軸方向の移動範囲制限
_value = Mathf.Clamp(_value, min, max);
Debug.Log(_value);
}
}
初め、 変数_valueの数値は3で定義されています。Clamp()関数の引数に注目すると、最小値は変数minで-1、最大値は変数maxで1と指定されています。この時、変数_valueの値は指定した範囲を超えるので、関数の出力としては1が出力されることとなります。
したがって、コンソールビューには1が表示されることとなります。
実装の概要
ここからは、実装について順を追ってみていきましょう。実装の手順は、主に以下の3点
- 現在の角度を取得する変数を用意
- 変数をClamp関数で制御しながら更新
- Transformへ変数を適用
順を追って説明していきますね
現在の角度を取得する変数_currentAngleを用意
以下のように、角度を数値として保存するための変数を用意。中途半端な角度に備え、floatで宣言。
private float _currentAngle;
_currantAngleをClamp()関数で制御しながら更新
Update()関数内で、フレームごとに_currentAngleの値を更新。ここでは、フレームごとにrotateSpeed * Time.deltaTime増えるように実装。
制限をするために、maxAngleを設定。これによって、_currentAngleはmaxAngle以上にも-maxAngle以下にもならない。
_currentAngle = Mathf.Clamp(_currentAngle + rotateSpeed * Time.deltaTime, -maxAngle, maxAngle);
Transformへ_currentAngleの値を適用
最後に、更新した_currentAngleをTransformに適用すれば処理は完了。
transform.rotation = Quaternion.Euler(0, 0, _currentAngle);
実際の実装
挙動
スクリプト
Playerに対してスクリプトを作成し、以下のようなコードで実装した。
using UnityEngine;
public class player : MonoBehaviour
{
public float moveSpeed = 2.0f;
public float rotateSpeed = 200.0f; // 回転スピード
public float maxAngle = 20.0f; // 最大傾き角度
private float _currentAngle = 0.0f; //現在の角度を取得する変数
// Update is called once per frame
void Update()
{
// 左キー(A)を押している間
if (Input.GetKey(KeyCode.A))
{
// 左に移動
transform.position += new Vector3(-moveSpeed, 0, 0);
// 傾きを計算して制限
_currentAngle = Mathf.Clamp(_currentAngle + rotateSpeed * Time.deltaTime, -maxAngle, maxAngle);
//実際に傾きを適用
transform.rotation = Quaternion.Euler(0, 0, _currentAngle);
}else
{
// 傾きを緩やかに元に戻す
_currentAngle = Mathf.Lerp(_currentAngle, 0, Time.deltaTime * 5);
//実際に傾きを適用
transform.rotation = Quaternion.Euler(0, 0, _currentAngle);
}
// 右キー(D)を押している間
if (Input.GetKey(KeyCode.D))
{
// 右に移動
transform.position += new Vector3(moveSpeed, 0, 0);
// 傾きを計算して制限
_currentAngle = Mathf.Clamp(_currentAngle - rotateSpeed * Time.deltaTime, -maxAngle, maxAngle);
//実際に傾きを適用
transform.rotation = Quaternion.Euler(0, 0, _currentAngle);
}
else
{
// 傾きを緩やかに元に戻す
_currentAngle = Mathf.Lerp(_currentAngle, 0, Time.deltaTime * 5);
//実際に傾きを適用
transform.rotation = Quaternion.Euler(0, 0, _currentAngle);
}
}
}

