概要
本記事では、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);
}
}
}