【第10回】斜方投射でボールの飛距離を計算するチュートリアル

【第10回】斜方投射でボールの飛距離を計算するチュートリアル

前回のチュートリアルでは、Inspectorウィンドウで値を入力する際の範囲設定と、球が転がる時際の回転の抵抗力を設定しました。

球が地面の上で止まるようになったので、今回は飛距離を計算して、コンソールに表示してみましょうか。

前回のチュートリアルはこちらから。

 

今回の目的

ボールが飛んだ後、地面を転がって止まった位置までの距離を測定します。

また、その距離をコンソールに出力します。

プロジェクトの準備

前回のチュートリアルで作成したプロジェクトをそのまま使います。

このページに先にたどり着いた方は、チュートリアルの初回から追っていただけるといいかもしれません。

止まったことを検出

これまでのところで、ボールを飛ばした後、地面に着地して停止するまでを作ることが出来ました。

さて、今回は距離を測定したいのですが、まずはボールが止まったことをシステム的に検知しないといけません。

テストプレイしている私たちは『Sphere』オブジェクトのTransformを見て、数字が変わらなくなったら「止まった!」と分かりますが、これをUnityはどうやって検知するの……?

と、こんな時は公式のリファレンス。

Rigidbody概要』を見ると、スリープモードなるものがあるらしい。Rigidbodyのアタッチされたオブジェクトが、決められたスピードより遅くなると、休止状態とみなされるそうな。

さらにスクリプティングガイドを見ると、『Rigidbody』のpublicメソッドにIsSleeping()というスリープモードかどうかを返すものがありました。これを使えそう。

試しに、『Sphere』オブジェクトにアタッチされているSphereBoosterをエディタで開き、FixedUpdate()の一番最初に以下のデバッグ文を仕込みます。

『Sphere』オブジェクトのX軸上の位置と、スリープモードかどうかのbool値を出力しています。この状態でゲームを実行し、ボールが止まる時のコンソール出力を確認します。

コンソール出力
IsSleepingがTrueになることを確認

 

前のフレームと比較して、TransformのXに変化がなくなったタイミング、つまり止まったタイミングで、IsSleeping()の結果がTrueになっています。

ちょっとマニアックな話をすれば、Unityプロジェクトの設定でスリープモードに入る閾値が決められているんです。この閾値は運動エネルギーを見ているようなのですが、内部でどうやって運動エネルギーを計算しているかわからないので割愛。

今回の目的は、ボールが止まったことをスクリプトから検知することですし、闇の深そうな話題には目を瞑りましょ。

このIsSleeping()を使って、ボールが止まったことを判定します。

 

距離の測定

続いて距離の測定です。

今の所、X-Y平面での運動を考えているので、開始位置と停止位置、それぞれについてTransformのXを取得して差分を取れば良さそうです。

んー、でも今後3Dで運動させた時のことを考えると、X-Z平面上での距離を見た方がいいかな。幸い、2つのVector3から距離を出してくれるVector3.Distanceという便利メソッドがあるのでこれを使います。

なお、X-Z平面上の距離を出すので、計算前にY軸の値を0に補正して、距離に反映しないようにする必要があります。高低差が影響するのもなんだか複雑になりそうですもんね。

まずはDebug.Log()を使ってコンソールに距離を出すことから始めましょ。

スクリプトSphereBooster.csの変更点は以下の通り。

  1. 距離測定中フラグの追加
  2. 停止位置の格納用ベクトルの追加
  3. ボタンが押された時の距離測定中フラグセット
  4. 距離測定用メソッドの追加

それぞれ解説を行います。スクリプトがだんだん長くなってきたので、全文はこちらからご覧ください。

今回使いたいメンバ変数を追加します。1の距離測定中フラグと、2の停止位置を格納するベクトルです。

測定中フラグを作ったのは、Rigidbody.IsSleeping()の判定をFixedUpdate()から呼んでいるため。IsSleeping()の結果がTrueの時、なんてやってしまうと、止めどなくデバッグ文が出てしまうので、切り替わった瞬間を検知して、その1回の処理に留める目的があります。

 

FixedUpdate()を変更します。冒頭のデバッグ文を消して、距離の測定を行うCheckDistance()を呼び出します。Boost! ボタンが押されない時はreturnで抜けるようにしているので、それより前に入れないとボタンを押した時にしかチェックしないさぼりメソッドになります(1敗)

 

続いて、3に関してボールの停止用メソッドと射出用メソッドにフラグの操作を追加します。特にStopFlying()の中でフラグを折らないと、ボタンを押して初期位置へ -> 初期位置で停止するのでスリープモードに -> 「飛距離は0メートルです」の暗黒コンボを食らうので注意(1敗)

 

スクリプトの最後尾に2つメソッドを追加しました。CheckDistance()は、FixedUpdate()から呼ばれる距離測定用のメソッドです。

フラグが立ってなければ何もせず抜け、フラグが立っていればスリープモードの判定を行います。

『Sphere』オブジェクトがスリープモードの場合、その位置を停止位置格納用ベクトルにセットします。

コンソール出力ではToString(“F2”)を使って書式を指定し、小数点以下2桁まで表示するようにしました。書式についてはMicrosoftの固定小数点 (“F”) 書式指定子をご参照ください。書式指定は便利。

その下のGetDistanceInXZ()は開始位置、停止位置それぞれのベクトルからY軸成分を除き、距離を算出しています。

 

さてさて、スクリプトが書けたら保存して、Unityに戻りましょ。

ゲームを実行してみると、以下のように停止した時点でデバッグ文が出力されているのが分かります。(GIFは2倍速)

デバッグ文の出力
2倍速でお送りするのだポッター

 

コンソールには、飛距離が指定したフォーマットで出力されます。オブジェクトがいつ停止したかを検知することができたので、次はいよいよゲーム画面に表示してみましょ。ボタンの時に出てきたUIのテキストを使います。

コンソール
コンソールに飛距離が表示される

 

まとめ

初期位置と停止位置のベクトルから、距離を計算してコンソール出力するチュートリアルでした。

ボールの停止はRigidbodyのスリープモードを使うことで検知できます。

次回はUIのテキストを使って、プレイヤーも飛距離が分かるようにしましょ。

     

ゲーム開発の攻略チャートを作りました!

CTA-IMAGE

「ゲームを作ってみたいけど、何から手を付けていいか分からない!」


そんなお悩みをお持ちの方向けに、todoがアプリをリリースした経験を中心に、ゲーム作りの手順や考慮すべき点をまとめたe-bookを作成しました。ゲーム作りはそれ自体がゲームのように楽しいプロセスなので、「攻略チャート」と名付けています。


ゲームを作り始めた時にぶつかる壁である「何をしたら良いのか分からない」という悩みを吹き飛ばしましょう!