オブジェクトが動いている速度を知りたい場合はどうすればいいの?
移動量とデルタタイムから計算したり、Rigidbody.velocityプロパティにアクセスすれば良いわ。
動くゲームオブジェクトの速度を取得したい場合、主に次の2通りの方法で実現できます。
- 前フレームからの移動量とデルタタイムから計算する
- Rigidbody.velocityプロパティから取得する
前者は、前フレームから現在フレームにかけて移動した量をデルタタイム(Time.deltaTime)で割って速度を求める方法です。スクリプトの実装が必要ですが、どの場面でも汎用的に扱える方法です。
後者は、物理演算されているオブジェクト限定になりますが、速度計算の実装をせずともプロパティから簡単に取得できます。
本記事では、上記2通りの方法でゲームオブジェクトの現在速度を取得する方法を解説していきます。
この作品はユニティちゃんライセンス条項の元に提供されています
- Unity 2021.1.23f1
目次 非表示
移動量とデルタタイムから計算する
1つ目の方法はあらゆる環境でも普遍的に使える方法です。速度計算の原理を解説してからサンプルスクリプトを示す流れで解説します。
速度の求め方
速度とは、単位時間当たりにどの向きにどれくらい移動するかを表す物理量です。したがって、速度はベクトルとして得られます。
ある時間\Delta tで位置が\vec{\Delta P}だけ変化した場合、時間\Delta tにおける平均速度\vec{v}は次式で表されます。
\vec{v} = \frac{\vec{\Delta P}}{\Delta t}
厳密な速度ではなく、あくまで平均速度を求めるという点に留意する必要があります。
移動量\vec{\Delta P}は、移動後の位置P^{\prime}から移動前の位置Pを引いた結果となります。
\vec{\Delta P} = P^{\prime} - P
平均速度を求める際、移動前と移動後の位置を求める時間\Delta tを短くすると、現在速度により近い値が得られます。
この\Delta tを限りなく0に近づけたものが現在速度ですが、Unityには計測できる時間間隔に限度が存在します。
この最小限度の時間間隔はTime.deltaTimeプロパティから得られます。これは、UpdateやFixedUpdateイベントの前フレームからの経過時間(秒)を表します。
したがって、プログラム中では前述の式のパラメータを次の通り対応させれば良いことになります。
- P : 1フレーム前のtransform.position
- P^{\prime} : 現在フレームのtransform.position
- \Delta t : Time.deltaTime
実際の処理は次のようになるでしょう。
3次元における速度(velocity)はVector3型です。
一般に、velocity.magnitudeのような大きさだけ持つ物理量は「速さ」と言い、向きを持った「速度」とは区別されます。
サンプルスクリプト
以下、3次元のフレーム毎の平均速度を計算する例です。計算された速度(ベクトル)を毎フレームログ出力します。
上記スクリプトをCalcVelocityExample.csとしてUnityプロジェクトに保存し、速度を計算したいゲームオブジェクトにアタッチすると機能します。
実行結果
対象オブジェクトの速度がログ出力されることが確認できました。
オブジェクトを動かすと(0, 0, 0)以外の結果が出力されます。
スクリプトの説明
速度計算に使用する1フレーム前の位置は、別の変数に保持しておく必要があります。これは、以下フィールドに格納しています。
そして、速度の計算をUpdateイベント内で行いますが、Time.deltaTimeが0になった場合にゼロ除算エラーになるため、最初にチェックします。
参考:Mathf-Approximately – Unity スクリプトリファレンス
チェックが済んだら、以下処理で速度を計算します。
最後に、Updateイベントの最後で前フレーム位置を更新して完了です。
Rigidbodyの移動速度を取得する
Rigidbodyにより物理演算されているオブジェクトの場合、Rigidbody.velocityプロパティから現在速度を取得できます。
参考:Rigidbody-velocity – Unity スクリプトリファレンス
注意点としては、物理演算されているオブジェクトの速度を取得できるものであり、transform.positionプロパティ等で直接位置を書き換えた場合は正しく速度を取得できません。
サンプルスクリプト
実行結果
物理演算でオブジェクトが動くと0以外の速度が得られるようになりました。
特定方向の速度を取得する
ここまで解説した方法は、ワールド空間における速度ベクトルを取得する方法でした。
例えばオブジェクトの前後方向など、特定方向の成分の速度を抽出したい場合を考えます。
これは、前述の速度ベクトルと向きベクトルの内積から求められます。
v = \vec{v} \cdot \vec{d}
ただし、
\vec{v} : ワールド空間の速度
\vec{d} : 向きベクトル
|\vec{d}| = 1
向きベクトルを長さを1に正規化してから内積を取らないと正しい結果が得られない点にご注意ください。
得られる結果は、速度ベクトルを向きベクトルに投影した位置です。
向きベクトルに対して速度ベクトルが同じ向きの場合、内積の結果は正となります。逆向きの場合は負となります。
サンプルスクリプト
以下、指定された向きベクトルの成分の速度を抽出してログ出力する例です。
上記をDirectionalVelocityExample.csという名前でUnityプロジェクトに保存し、速度を計測したゲームオブジェクトにアタッチしてください。
実行結果
以下は向きベクトルを(0, 0, 1)とした場合です。
z軸成分の速度のみ計測できていることが確認できました。
スクリプトの説明
一つ目の例と異なる部分は以下です。
元の速度velocityと抽出したい速度成分の向きベクトル_directionとの内積から結果を求めています。
Rigidbody.velocityに対しても同様に内積を取ることで計算できます。
さいごに
現在速度は、前フレームからの経過時間(Time.deltaTime)と変位(transform.positionの変化量)から計算できます。
Rigidbodyで物理演算されているオブジェクトの場合、Rigidbody.velocityから簡単に知ることができます。
オブジェクトの移動速度が分かれば、移動方向にキャラクターを回転させたり、弾を打つなど動作が可能になります。