【Unity基礎】velocityを使用してオブジェクトを動かす方法

Unityでオブジェクトを動かす方法はたくさんありますが、Rigidbodyの速度を直接変更できる「Velocity」についてスクリプト例を交えて説明したいと思います。

Rigidbody.velocityとは

Rigidbody.velocityとは、「Rigidbody の速度ベクトル」です。
・・・と言われてもなんのことかよく分からないですね。

簡単に言うと、velocityはRigidbodyに含まれるVector3型の変数です。
Rigidbodyコンポーネントをアタッチしたオブジェクトを、velocityの値を書き換えることで動かすことが出来ます。
Transform.Translateのように移動する距離を指定したりするのではなく、オブジェクトが移動する速度を指定することになります。

公式リファレンスではvelocityの使用は非推奨

公式リファレンスのRigidbody.velocityのページによると、直接velocityを変更するのは推奨されていません。

その理由は、挙動がリアルじゃないから、とのこと。
確かに、上のGIF画像のように唐突に方向転換していて、非現実的な動きです。
物理演算的により現実により近い動きをさせたい場合はAddForceを使ったほうがいいでしょう。

でも、ゲームなんだから全てリアルに表現する必要はありません。
あえて非現実的な動きをさせたい時なんかにはvelocityをどんどん使ってもOKです。
公式リファレンスには、FPSでのジャンプなんかに使うと良いよって書かれてます。

velocityでオブジェクトを動かすときの書式

例えばこんな感じでスクリプトに書きます。

rb.velocity = new Vector3(0, 1.0f, 0);

rbにはあらかじめRigidbodyコンポーネントを「GetComponent」で取得して入れておきます。
そして、velocityに速度を指定したVector3を代入してあげると、オブジェクトが動きます。
Vector3の座標はワールド座標なので、上の例ではy軸方向、つまり上に昇っていきます。

velocityでオブジェクトを動かすときのスクリプト例

シーンにキューブなどを作成して、Rigidbodyコンポーネントとスクリプトをアタッチ。
スクリプトのclass内に下記コードをコピペすると、カーソルキーの操作で動かせるようになります。

// Rigidbodyコンポーネントを入れる変数"rb"を宣言する。 
public Rigidbody rb; 
void Start() { 
    // Rigidbodyコンポーネントを取得する 
    rb = GetComponent<Rigidbody>(); 
}
void FixedUpdate() { 
    //  Upキーで上昇 
    if (Input.GetKey("up")) { 
        rb.velocity = new Vector3(0, 10.0f, 0); 
    } 
    // Downキーで下降 
    if (Input.GetKey("down")) { 
        rb.velocity = new Vector3(0, -10.0f, 0); 
    } 
    // right キーで右に進む 
    if (Input.GetKey("right")) { 
        rb.velocity = new Vector3(10.0f, 0, 0); 
    } 
    //left キーで左に進む 
    if (Input.GetKey("left")) { 
        rb.velocity = new Vector3(-10.0f, 0, 0); 
    } 
} 

ローカル座標で動かすスクリプト例

velocityにVector3で値を入れると、ワールド座標に従って動きます。
つまり、オブジェクトがどちらを向いていても関係ありません。

オブジェクトの向いている方向に進ませたい場合は、次の書き方をすればローカル座標で動かせます。

 // Rigidbodyコンポーネントを入れる変数"rb"を宣言する。 
 public Rigidbody rb; 
 void Start() { 
     // Rigidbodyコンポーネントを取得する 
     rb = GetComponent<Rigidbody>(); 
} 
 void FixedUpdate() { 
     // Upキーで前に進む 
     if (Input.GetKey("up")) { 
     rb.velocity = transform.forward * 10.0f; 
     } 
     // Downキーで後ろに進む 
     if (Input.GetKey("down")) { 
     rb.velocity = transform.forward * -10.0f; 
     } 
     // Rightキーで右回転 
     if (Input.GetKey("right")) { 
         //rb.MovePosition(transform.position - transform.up * 1.0f * Time.deltaTime); 
         transform.Rotate(new Vector3(0, 2.0f, 0)); 
     } 
     // Leftキーで左回転 
     if (Input.GetKey("left")) { 
         transform.Rotate(new Vector3(0, -2.0f, 0)); 
     } 
 } 

「 transform.forward」はオブジェクトのローカル座標のZ方向を取得できるので、velocityに代入してやると、オブジェクトの前方向へ進ませることが出来ます。

velocityが1の場合、1秒間に1unitの速さ

velocityで表される速度が1の場合、1秒間に1unitの速さであることを表しています。
デフォルトのキューブは1辺が1unitなので、velocityが1の場合、1秒でキューブ1個分進むということ。
1unit = 1mとすると、ゆっくり歩くくらいのスピードですね。

ちなみにUnityの物理演算は1unit = 1mの計算で動いているそうです。
時速60kmで動かしたい場合は、
60,000(m) / 3600(秒) = 16.67
ということで、velocityに16.67を入れるといいことになります。

positionによる移動と違って、velocityではすり抜けない

何が起こっているかよく分からないかもしれませんが、ピンクのキューブが右に向かって超高速で移動し、白いキューブにぶつかって止まっています。

rb.velocity = new Vector3(100000.0f, 0, 0);

Transform.positionや、Transform.Translateを使った移動では超高速での移動時に、間のオブジェクトをすり抜けて通過することがあります。
positionやTranslateの移動は、瞬間移動を繰り返しているようなものなので、1回の移動量が大きいと間の物体に接触せずに向こう側に移動してしまいます。

このことから、velocityによる移動はきちんと連続的に移動していると考えてよさそうです。

Velocityの移動以外の利用方法

velocityはRigidbodyのオブジェクトを動かすためだけに存在するわけではありません。
ここまではvelocityに値を代入してオブジェクトを動かしていましたが、逆に動いているオブジェクトのvelocityを取得することで、オブジェクトの移動速度を知ることが出来ます。

// Rigidbodyコンポーネントを入れる変数"rb"を宣言する。 
public Rigidbody rb;
void Start() {
    // Rigidbodyコンポーネントを取得する 
    rb = GetComponent<Rigidbody>();
}

void Update() {
    Debug.Log(rb.velocity);
}

と、Debug.Logでvelocityを表示すると、Consoleにx, y, zそれぞれの速度を表示できます。
velocityはVector3型の変数なので、ベクトルの長さを取得できるmagnitudeを利用すると、x, y, zに分解された速度じゃなく、オブジェクトの本当の速度を得ることもできます。

Debug.Log(rb.velocity.magnitude);

コメント