現在グレンジでUnityを用いたゲーム開発を行っているみくりやと申します。
グレンジ Advent Calendar 2018 3日目の記事になります。
去年も3日目だったな(ZenjectでDIの真理を悟る)
QuaternionはUnityを使う人なら一度は通る道だと思います。Quaternionについての記事はたくさんありますが、今回はもうちょっと噛み砕いてゲームなどに応用しやすい初歩的な回転サンプルを作ってみたいと思います。
#Quaternionって?
細けぇことは一旦どうでもいいんだ、こいつは回転させてくれる
#注視する回転
指定オブジェクトを注視する回転です。
using UnityEngine;
public class QuaternionTest : MonoBehaviour {
[SerializeField]
private Transform _target;
[SerializeField]
private Transform _player;
void Update () {
LookTarget();
}
private void LookTarget() {
_player.rotation = Quaternion.LookRotation(_target.position - _player.position);
}
}
_player
(Unityちゃん)が_target
(とうふ)を見つめています。
transform.LookAt
を使っているパターンもよく見かけますが、
#指定方向に回転
指定キーが押されている間、指定方向に回転する処理です。
public class QuaternionTest : MonoBehaviour {
[SerializeField]
private Transform _player;
void Update () {
if (Input.GetKey(KeyCode.LeftArrow)) {
OnKeyPressRotate(1);
} else if (Input.GetKey(KeyCode.RightArrow)) {
OnKeyPressRotate(-1);
}
}
private void OnKeyPressRotate(int direction) {
_player.rotation *= Quaternion.AngleAxis(1f * direction, _player.up);
}
}
Quaternion.AngleAxis
は 指定軸に対する単位回転 を表すので、_player
の現在の回転にかけることで角度が加算されてくるくると回っていきます。
コードの例だとプレイヤーのy軸に対して1度回転します。
今度は指定キーを押したときに一定角度回転する動きを作ってみます。
public class QuaternionTest : MonoBehaviour {
[SerializeField]
private Transform _player;
private Quaternion _startRotation;
private Quaternion _endRotation;
private float _countTime;
private bool _startRotate;
void Update () {
if (Input.GetKeyDown(KeyCode.LeftArrow)) {
OnKeyDownRotate(1);
} else if (Input.GetKeyDown(KeyCode.RightArrow)) {
OnKeyDownRotate(-1);
}
UpdateKeyDownRotate();
}
private void OnKeyDownRotate(int direction) {
_countTime = 0f;
_startRotation = _player.rotation;
_endRotation = _player.rotation * Quaternion.AngleAxis(45f * direction, _player.up);
_startRotate = true;
}
private void UpdateKeyDownRotate() {
if (_startRotate == false) {
return;
}
_countTime = Mathf.Clamp(_countTime + Time.deltaTime, 0f, 0.5f);
float rate = _countTime / 0.5f;
_player.rotation = Quaternion.Lerp(_startRotation, _endRotation, rate);
if (rate >= 1f) {
_startRotate = false;
}
}
}
指定キーを押したときに0.5秒かけて45度回転させています。
Quaternion.Lerp
を用いて、_startRotation
から_endRotation
まで回転させていきます。
_endRotation
の値は最初の例と同じ方法で指定しています。Quaternion自体は値なので動いているように見せるには今回のような方法が必要です。
rateの値を調節するとイージングをかけたりできますね。
#指定オブジェクト周りの回転
指定したオブジェクトの周りを回転させます
public class QuaternionTest : MonoBehaviour {
[SerializeField]
private Transform _target;
[SerializeField]
private Transform _player;
void Update () {
RotateArownd();
LookTarget();
}
private void LookTarget() {
_player.rotation = Quaternion.LookRotation(_target.position - _player.position);
}
private void RotateArownd() {
_player.position = Quaternion.AngleAxis(1f, _target.up) * _player.position;
}
}
プレイヤーの座標に回転をかけることでいい感じにオブジェクトの周りを回転してくれます。
しかし、このままだと_target
を動かしたときにおかしなことになります。
Quaternionは 原点を中心とした回転 を表すのでその点を考慮しなければなりません。(今回は_target
が原点にいたのでいい感じに見えてしまっていました)
RotateArownd()
を以下のように改修します。
private void RotateArownd() {
_player.position = _target.position + Quaternion.AngleAxis(1f, _target.up) * (_player.position - _target.position).normalized * 2f;
}
_target
から_player
に向いたベクトルをQuaternion.AngleAxis
で回転させ_target
の座標に加算することで位置を算出します。こうすることで_target
起点の回転を作ることができました。今回は半径2の位置に移動するようにnormalizedしたものに2をかけています。
「指定キーを押したときに一定角度回転する動き」で作ったものを応用することで「指定キーを押したときに指定オブジェクト周りを一定角度回転する」ということもできるでしょう。
#まとめ
今回作成したサンプルでは水平方向にしか回転させていませんが、Quaternionに指定する軸を変えることで回転方向を楽に変えることができるというのも便利なところです。
本記事であげた例以外にもQuaternionの使い方は様々あるので自身のプロジェクトにあった使い方を是非探してみてください。とっかかりに役立てれば幸いです。良きQuaternionライフを!