どうも、久しぶりの更新になってしまいました。
今日は備忘録を兼ねたUnityの使い方です。
Unityを使ってゲーム作りをしていると、回転が難しいという話があると思います。
実際、スクリプトでの回転操作はなかなか難しいですし、感覚がうまくつかめないところがあると思います。
特に、角度に制限を付けて回転をさせるのはネットでもなかなか見つからず、実装に苦戦している方も少なくないのではないでしょうか。
そこで、当方の実装方法を(備忘録を兼ねて)公開しようと思います。
あまり良い方法ではないかもしれませんが、もし参考になれば幸いです。
【方法とプログラム】
では、さっそくソースからどうぞ。
なお、ここでは前提として上下左右(XとY軸)の方向のみの回転
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
; title="ClampRotation.cs"] //現在の角度 Vector2 rotateAngle; //制限する角度量 Vector2 rotateLimit; void Update() { //対応するキー(デフォルトではa,s,w,dキー)を押すと、このスクリプトを付けた自身が回転 rotateProcess(new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical")), 10f); //2番目の引数は、好きな値で } void rotateProcess(Vector2 delta, float speed) { //回転する方向と速度を決定 Vector2 rotVector = delta.normalized * speed * Time.deltaTime; float rotH = getRotateAngle(rotVector.x, ref rotateAngle.x, rotateLimit.x / 2); float rotV = getRotateAngle(-rotVector.y, ref rotateAngle.y, rotateLimit.y / 2); //砲塔を回転 transform.rotation = Quaternion.AngleAxis(rotateAngle.x, transform.up) * Quaternion.AngleAxis(rotateAngle.y, transform.right); //transform.Rotate(rotV, rotH, 0); //こちらは失敗 } float getRotateAngle(float rotDelta, ref float angle, float rotMax = 90) { float result = rotDelta; //予定の回転角度 float nextRot = angle + rotDelta; //回転できる最大角度を超えたら if (nextRot > rotMax) { result = rotMax - angle; } //回転できる最低角度を超えたら else if (nextRot < -rotMax) { result = -rotMax - angle; } //回転後の角度も渡しておく angle += result; return result; } |
主な手順は以下の二つです。
1. 今の回転角度を求める
2. 1. で求めた角度をもとに、Quaternion.AngleAxitメソッドで回転させる
まず、1. は自作メソッドのgetRotateAngleから求めています。
引数は、左から (回転させたい角度量)、(回転前の角度)、(最大/最小角の絶対値) となっています。
ここでは、2番目の回転前の角度に、1番目の角度量を足して回転後の角度を求め、それが角度の制限値を超えていたら制限に収まるように回転量を調整しています。
戻り値は回転の角度量ですが、2番目の引数が参照(ref)となっているため、回転後の角度値も同時に求められます(実は、こちらの回転後の角度値を2.で使います)。
続いて2.の処理(自作のrotateProcessメソッド)ですが、回転量をQuaternionでもとめて、transform.rotationに入れています。
Quaternionは苦手な方もいらっしゃるかもしれませんが、Unity(に限らないかもしれませんが)で少し複雑な回転処理をさせようとすると必要になってきます。
とはいえ、今回使うのはQuaternion.AngleAxisメソッドのみです。
このメソッドは、引数に (回転させたい角度値)、(回転軸) を指定します。回転軸はVector3で指定するので、軸の伸びている方向と考えるとわかりやすいかもしれません。
オブジェクトに突き刺す軸を決めて、その軸を基に何度回転させるかといったイメージです。
今回のスクリプトは、上下と左右それぞれの回転をQuaternion.AngleAxisで求め、それをオブジェクトのrotationに代入して回転させます。AngleAxisメソッドで求められる回転は、上下、あるいは左右のみのものですが、実はQuaternion同士を掛け合わせると、二つの回転を反映した回転(Quaternion)が求められます。
そのため、以下の式で回転を求められるのです。
(オブジェクトのrotation) = (上下方向のQuaternion) * (左右方向のQuaternion)
なので、計算した角度とAngleAxisで求めたQuaternion同士を掛け合わせると角度制限を設けた回転が求められます。
今回は0°を中心に左右対称で角度の制限値を与えていますが、getRotateAngleの処理を少し変えれば非対称に角度の制限を設けることも可能です。
実は、今の処理に行き着く前にtransformクラスのRotateメソッドで回転を求めようとしました。
ですが、マウスなどでぐりぐり回転させると、なぜかZ軸方向の回転もしてしまい思ったようにオブジェクトが回転してくれませんでしたorz
もしかするとRotateメソッドはマイナスの値を受け付けなかったりするのでしょうか?
処理の方法が気になるのですが、Unityの個人版だと基幹クラスの内部は見られないので、真相は当方にはわかりません。
(あるいはドキュメントとかに載っていたらすいません…)
コメント