Unityで地面の上のキューブを転がす方法【Rotate Around編】

先日開催されていたunity1week(テーマ:転がる)でキューブを回転させているゲームが多くありました。
↓ こういうのとか↓ こういうの良い感じ #unity1week pic.twitter.com/Mmr41ASvr3
— !args(のたぐす) (@notargs) 2017年5月25日
サイコロリ -Saikorori | ゲーム投稿サイト unityroom #unity1week https://t.co/ymZgndisZF 最初ルールわからなかったけど、わかったらメッチャ面白いな。サイコロの目だけ転がるのか。サイコロの下にある数値分進むのかと勘違いしてた pic.twitter.com/dVgbB2t4j8
— 椿 (@tsubaki_t1) 2017年6月3日
一見、簡単そうに思えたのですが、よくよく考えるとどうやって回転させているのか分からなかったので試してみました。
ひとまず思い通りに回転させることはできたので、記事にして残しておきます。

環境
- Unity 5.6.0f3
使用した関数
今回、回転にはtransform.RotateAroundを使いました。「回転の中心」「回転軸」「回転角度」を与えてあげると移動しながら回転してくれます。便利。
- transform.RotateAround
- public void RotateAround(Vector3 point, Vector3 axis, float angle);
- pointを中心に、axisで指定した回転軸に沿って、angle度回転してくれる
一方向だけ動かす
とりあえず一方向だけ回転させることを考えます。
必要な情報は「回転の中心」「回転軸」「回転角度」ですが、以下の図のような感じでうまくいきそうな気がします。

上の図に従って、右に転がす場合の「回転の中心」「回転軸」「回転角度」を設定してみます。
回転の中心を取得する
回転の中心は「回転したい方向の下辺の中心」です。
transform.positionでcubeの中心位置がわかるので、x軸方向にcubeのサイズの半分を足し、y軸方向にcubeのサイズの半分を引けば「回転したい方向の下辺の中心」になりそうです。
オブジェクトの大きさはtransform.localScaleで取得できるので、これを使ってオブジェクトの大きさの半分を求め、適当な変数に入れておきます。
1 2 |
cubeSizeHalf = transform.localScale.x / 2f; rotatePoint = transform.position + new Vector3(cubeSizeHalf, -cubeSizeHalf, 0f); |
回転軸を取得する
右回転する時の回転軸は要はz軸と同一ですが、ベクトルの向きには注意が必要です。
unityで回転させる時、プラスの値を与えると回転の向きは向かって左回転(反時計回り)になります。
なので右回転させたい場合、回転軸の向きを手前側に向けるか、マイナス方向に回転させる必要があります。
どちらの方法でもいいのですが、ここでは回転軸の向きを手前側に向け、角度を常に正の値で与えることにします。

1 |
rotateAxis = new Vector3 (0, 0, -1); |
回転角度
最終的に90度回転してほしいので、ここでは単純に90度を与えます。
1 |
cubeAngle = 90f; |
回転させてみる
ここまでの内容をまとめて、右矢印が押されたら右側に回転させるスクリプトを動かしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
Vector3 rotatePoint = Vector3.zero; //回転の中心 Vector3 rotateAxis = Vector3.zero; //回転軸 float cubeAngle = 0f; //回転角度 float cubeSizeHalf; //キューブの大きさの半分 void Start(){ cubeSizeHalf = transform.localScale.x / 2f; } void Update(){ if (Input.GetKeyDown (KeyCode.RightArrow)) { rotatePoint = transform.position + new Vector3(cubeSizeHalf, -cubeSizeHalf, 0f); rotateAxis = new Vector3 (0, 0, -1); cubeAngle = 90f; transform.RotateAround (rotatePoint, rotateAxis, cubeAngle); } } |

なめらかに回転させる
いちおう動くには動きましたが、まったく回転している感じがしないので修正していきます。
一気に回転してしまっているのはangleにいきなり90度を与えてしまっているからなので、徐々に回転させて最終的に90度回転するように変更します。
Update内で徐々に回転させる処理をするとややこしいので、可変であるangle周りの処理をコルーチンにして処理を外に出します。
また、回転中に入力を受け付けないようにisRotateフラグを用意して入力受付を制限します。
角度の与え方はいろいろあると思いますが、ここでは単純に値を加算していって、合計が90度に達したら回転を止めることにします。
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 40 41 42 43 44 45 46 47 48 |
Vector3 rotatePoint = Vector3.zero; //回転の中心 Vector3 rotateAxis = Vector3.zero; //回転軸 float cubeAngle = 0f; //回転角度 float cubeSizeHalf; //キューブの大きさの半分 bool isRotate = false; //回転中に立つフラグ。回転中は入力を受け付けない void Start(){ cubeSizeHalf = transform.localScale.x / 2f; } void Update(){ //回転中は入力を受け付けない if (isRotate) return; if (Input.GetKeyDown (KeyCode.RightArrow)) { rotatePoint = transform.position + new Vector3(cubeSizeHalf, -cubeSizeHalf, 0f); rotateAxis = new Vector3 (0, 0, -1); StartCoroutine (MoveCube()); } } IEnumerator MoveCube(){ //回転中のフラグを立てる isRotate = true; //回転処理 float sumAngle = 0f; //angleの合計を保存 while (sumAngle < 90f) { cubeAngle = 15f; //ここを変えると回転速度が変わる sumAngle += cubeAngle; // 90度以上回転しないように値を制限 if (sumAngle > 90f) { cubeAngle -= sumAngle - 90f; } transform.RotateAround (rotatePoint, rotateAxis, cubeAngle); yield return null; } //回転中のフラグを倒す isRotate = false; yield break; } |

全ての方向に動かす
1方向できているので、あとは同じように他の方向も動かせるようにします。
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 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
Vector3 rotatePoint = Vector3.zero; //回転の中心 Vector3 rotateAxis = Vector3.zero; //回転軸 float cubeAngle = 0f; //回転角度 float cubeSizeHalf; //キューブの大きさの半分 bool isRotate = false; //回転中に立つフラグ。回転中は入力を受け付けない void Start(){ cubeSizeHalf = transform.localScale.x / 2f; } void Update(){ //回転中は入力を受け付けない if (isRotate) return; if (Input.GetKeyDown (KeyCode.RightArrow)) { rotatePoint = transform.position + new Vector3(cubeSizeHalf, -cubeSizeHalf, 0f); rotateAxis = new Vector3 (0, 0, -1); } if (Input.GetKeyDown (KeyCode.LeftArrow)) { rotatePoint = transform.position + new Vector3(-cubeSizeHalf, -cubeSizeHalf, 0f); rotateAxis = new Vector3 (0, 0, 1); } if (Input.GetKeyDown (KeyCode.UpArrow)) { rotatePoint = transform.position + new Vector3(0f, -cubeSizeHalf, cubeSizeHalf); rotateAxis = new Vector3 (1, 0, 0); } if (Input.GetKeyDown (KeyCode.DownArrow)) { rotatePoint = transform.position + new Vector3(0f, -cubeSizeHalf, -cubeSizeHalf); rotateAxis = new Vector3 (-1, 0, 0); } // 入力がない時はコルーチンを呼び出さないようにする if (rotatePoint == Vector3.zero) return; StartCoroutine (MoveCube()); } IEnumerator MoveCube(){ //回転中のフラグを立てる isRotate = true; //回転処理 float sumAngle = 0f; //angleの合計を保存 while (sumAngle < 90f) { cubeAngle = 15f; //ここを変えると回転速度が変わる sumAngle += cubeAngle; // 90度以上回転しないように値を制限 if (sumAngle > 90f) { cubeAngle -= sumAngle - 90f; } transform.RotateAround (rotatePoint, rotateAxis, cubeAngle); yield return null; } //回転中のフラグを倒す isRotate = false; rotatePoint = Vector3.zero; rotateAxis = Vector3.zero; yield break; } |
完成!

1 thought on “Unityで地面の上のキューブを転がす方法【Rotate Around編】”