【Unity】ゲームオブジェクトの移動・回転・拡大縮小のきほん

今回はTransformを使ってキャラクターを動かす方法を教えるね!
スクリプトを書くことになるからしっかりとついてきて!

はい!早速レクチャーお願いしますっ♪

Transformとは

ゲームオブジェクトの移動・回転・拡大縮小を行うためのものです。Transformはコンポーネントの一種で、ゲームオブジェクトに必ず1つ存在します。 [1]

Unityエディタのゲームオブジェクトを選択すると、インスペクタの一番上に以下のように表示されます。

Transformには、位置(Position)・回転(Rotation)・スケール(Scale)の情報が格納されており、自由に設定できるようになっています。
ここで注意すべきは、これらがローカル座標になっている点です。

ローカル座標とワールド座標

Transformに格納されている位置・回転・スケールは、ローカル座標です。
ローカル座標とは、親の中心位置を原点とした座標のことです。回転やスケールも親基準となります。

これに対し、シーンの原点を基準とした座標ワールド座標と言います。

ローカル座標系は原点が動く可能性がありますが、ワールド座標は原点が常に固定です。 [2]

いま自分が扱っている座標はローカル座標・ワールド座標のどちらなのかを常に意識することがとても重要だわ!

次は、スクリプトから移動・回転・拡大縮小する方法について解説します。
スクリプトでは、ローカル座標とワールド座標の両方を扱うことが可能なため、両者混同しないように注意しましょう。

スクリプトからゲームオブジェクトを動かす

いよいよスクリプトを作成していきます。
スクリプトを動かす準備をしましょう。

前準備

適当なシーンに適当なゲームオブジェクトを作成します。
そして、適当なスクリプト(ObjectMover.cs)を作成し、ゲームオブジェクトにアタッチします。

これで準備完了です。

Transformへのアクセス方法

Transformは、スクリプトからはtransformプロパティとしてアクセスできます。
ゲームオブジェクトの位置を取得したり、動かしたりする操作は、すべてtransformプロパティに対して行います。

具体例を見ていきましょう。

移動

移動は、Transformの位置(Position)を指定することにより行います。

位置の指定

// ローカル座標の位置を(1, 2, 3)に設定
transform.localPosition = new Vector3(1, 2, 3);

// ワールド座標の位置を(1, 2, 3)に設定
transform.position = new Vector3(1, 2, 3);

ローカル座標指定の場合はtransform.localPosition、ワールド座標の場合はtransform.positionに値を設定します。

この例だと、オブジェクトが(1, 2, 3)の位置に瞬間移動して止まっちゃうね。

そう、位置を初期化するのには使えるけど、キャラクターに動きをつけるには位置を毎フレーム少しずつずらす必要があるの。

次に、指定速度でオブジェクトを移動する方法について見ていきましょう。

等速で移動する

Updateメソッドで位置を積算するとオブジェクトを見かけ上動かすことができます。ただし、即値をそのまま加算する方法はフレームレートによって移動速度が変わってしまうため控えるべきです!

1フレームにかかった時間Time.deltaTimeを用いて積算する必要があります。

以下、指定速度で等速移動させるスクリプトの例です。

ObjectMover.cs
using UnityEngine;

public class ObjectMover : MonoBehaviour
{
    // 移動速度
    [SerializeField] private Vector3 _velocity;

    private void Update()
    {
        // 速度_velocityで移動する(ローカル座標)
        transform.localPosition += _velocity * Time.deltaTime;
    }
}

これをObjectMover.csにコピー&ペーストして、Velocityの値を適当に設定してみてください。

実行すると、オブジェクトが移動していることが分かります。

スクリプト上の_velocityはxyz方向の移動速度で、1秒間にどれくらい移動するかを表した物理量です。

前回のUpdateメソッド呼び出しから、現在のUpdateメソッド呼び出しにかかった時間がTime.deltaTime秒なので、Time.deltaTimeを掛けています。

物理に詳しい人なら、速度の時間積分をやっていると説明すれば分かりやすいかと思います。 [3]

回転

回転は、Transformの回転(Rotation)を指定することにより行います。

回転の指定

// ローカル座標の回転を(30°, 60°, 90°)に設定
transform.localRotation = new Quaternion.Euler(30, 60, 90);

// ワールド座標の回転を(30°, 60°, 90°)に設定
transform.rotation = new Quaternion.Euler(30, 60, 90);

Transformの回転はクォータニオンで表現されています。
クォータニオンとは4つの要素x, y, z, wからなる四元数ですが、これらをそのまま指定するのは直観的ではありません。ヘルパーメソッドを使うのが一般的です。

上記の例では、直観的に分かりやすいオイラー角 [4] で角度指定しています。角度は度数法で指定します。

オイラー角指定での回転は、以下のように書くこともできます。

// ローカル座標の回転を(30°, 60°, 90°)に設定
transform.localEulerAngles = new Vector3(30, 60, 90);

// ワールド座標の回転を(30°, 60°, 90°)に設定
transform.eulerAngles = new Vector3(30, 60, 90);

こちらの方がより簡潔に書けるのでおススメです。

等速で回転する

等速で回転させたい場合も、等速で移動させる考え方を適用できます。
UpdateメソッドでTime.deltaTime秒間に回転する角度をオイラー角に可算すれば良いです。

ObjectRotator.cs
using UnityEngine;

public class ObjectRotator : MonoBehaviour
{
    // 回転角速度
    [SerializeField] private Vector3 _angleVelocity;

    private void Update()
    {
        // _angleVelocityでオイラー角を動かす
        transform.localEulerAngles += _angleVelocity * Time.deltaTime;
    }
}

上記スクリプトをObjectRotator.csとして作成し、ゲームオブジェクトにアタッチしてAngle Velocityの値を弄ってみてください。

実行すると、オブジェクトがその場で回転し続けます。

_angleVelocity一秒間に変化するオイラー角の量(角速度)としました。
したがって、1フレーム間に回転する角度は_angleVelocity * Time.deltaTimeとなります。

拡大縮小

拡大は、Transformのスケール(Scale)を指定することにより行います。

スケールの指定

スケールは位置や回転とは事情が異なり、ワールド座標でのスケール指定はできません。

// ローカル座標のスケールを(1, 2, 3)に設定
transform.localScale = new Vector3(1, 2, 3);

ただし、ワールド座標のスケールの近似値ならtransform.lossyScaleで取得できます。

// ワールド座標のスケール近似値を取得
var lossyScale = transform.lossyScale;

拡大縮小アニメーション

1秒周期で拡大縮小するスクリプトの例です。

ObjectScaler.cs
using UnityEngine;

public class ObjectScaler : MonoBehaviour
{
    // 拡大時のスケール
    [SerializeField] private Vector3 _maxScale;

    private void Update()
    {
        // _frequencyの周波数で拡大縮小を繰り返す
        transform.localScale = (Mathf.Sin(2 * Mathf.PI * Time.time) + 1) * 0.5f * _maxScale;
    }
}

上記をObjectScaler.csとして保存して、_maxScaleに拡大時のスケールを適当に設定してください。
スクリプトの詳細はいったん目を瞑ってください…

実行すると、以下のようなアニメーションになります。

Mathf.Sin()は三角関数のsinの値を返すメソッドです。
Mathf.PIは円周率を返す定数です。
Time.timeはゲーム開始からの経過時間[秒]を返すプロパティです。

これらは今すぐ覚えなくても、使うときに調べるスタンスで問題ありません。

まとめ

Unityにおけるゲームオブジェクトの移動・回転・拡大縮小の方法について解説しました。

キャラクターを動かすにあたって、Unityで扱う座標系についての理解も必要ですが、今回は動かすところまでが目標だったため、割愛いたしました。座標系については、また別記事で解説できればと思います。

参考サイト