【第21回】ボールを打ち出す強さを決めるためのメーターを作るUnityチュートリアル

【第21回】ボールを打ち出す強さを決めるためのメーターを作るUnityチュートリアル

前回のチュートリアルでは、ボールの斜方投射を行う際、予想経路を画面に表示する方法をお送りしました。

計4回にわたるがっつりとした山場でしたね。

今回も若干重めかもしれませんが、UIのスライダーをカスタマイズして、ボール発射の強さを決めるメーターを作ります。

この時、メーターはゲームっぽく上下するようにしてみましょ。

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

 

今回の目的

ボールを打ち出す強さを決めるメーターをUIのSliderで実装します

メーターは自動で上下するようにして、ゲームのプレイヤーが目押しで強さを決められるようにします。

プロジェクトの準備

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

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

UIスライダーの作成

まずは今回使うスライダーを作成してみましょ。『Hierarchy』ウィンドウで『Canvas』オブジェクトを選択し、右クリックまたは二本指タップでコンテキストメニューを開きます。メニューから[Create Empty]を選択します。

メーターの親オブジェクト
親オブジェクトを作るのだポッター

 

名前は[PowerMeterParent]にします。このオブジェクトの子オブジェクトとして、スライダーを追加します。

名前を設定
PowerMeterParentにリネーム

 

今度は『PowerMeterParent』オブジェクトを選択してからコンテキストメニューを開き、[UI] -> [Slider]を選択します。

Sliderの作成
Sliderの作成

 

出来上がったスライダーは[PowerMeter]にリネームします。

名前はPowerMeter
名前はPowerMeter

 

 

ここでSliderコンポーネントの設定をいくつかしておきます。

Interactableの設定は[false]に。これはゲームのプレイヤーが画面から値を変えられるかどうかの設定で、今回はメーターを自動で動かすためチェックを外します。

次に、Handle Rectの設定を[None]にします。これは例のごとく右の丸ボタンから選択できます。ゲームのプレイヤーが値を変えないので、ハンドルも必要ありません。

Directionは[Bottom To Top]に変更します。縦に動くメーターにしたいので向きを変えます。

Min Valueには[3]、Max Valueには[15]を入力します。前回のチュートリアルでガイドを表示してみたところ、力の大きさが10とか20くらいだったらちょうど良さそうだったので、間をとって15にしました。メーターの最大値で止めればガイド通りに飛ぶイメージです。

最小値は0にするとあまりに飛ばなすぎるため、多少動きが出るように3としています。

Sliderコンポーネントの設定
Sliderコンポーネントの設定(大盛り)

 

Sliderの向きを変えたので、Transformも変えておきましょ。Widthを[30]に、ScaleをX, Y, Zそれぞれ[3]にします。オブジェクトの名前は[PowerMeter]にしました。

Transformの設定
Transformの設定

 

続いて、『PowerMeter』オブジェクトの子オブジェクトである『Handle Slide Area』を削除します。今回はSliderコンポーネントでHandleを外しているので、オブジェクト自体も削除してしまいます。

Handleの削除
Handleの削除

 

『Fill Area』オブジェクトでは、Topを[5]、Bottomも[5]にします。スライダーのハンドルが無くなった分、位置を修正しておきます。

Fill Areaの設定
Fill Areaの設定

 

『Fill』オブジェクトでは、Topを[-5]、Bottomも[-5]にします。この値は『PowerMeter』オブジェクトのSliderコンポーネントで、Valueを最大値(ここでは15)にしておくと調整しやすいです。Fillエリアがどこまで伸びているか分かりやすいですからね。

Fillの設定
Fillの設定

 

『Fill』オブジェクトではImageコンポーネントで色も変えましょ。Colorを[FFA840FF](オレンジ)にしておきます。

Fillの色
Fillの色

 

設定の仕上げに、『PowerMeterParent』オブジェクトの位置を動かします。アンカーを[alt(option)]キーと[shift]キーを押しながら[middle – right]に設定した後、Pos Xを[-25]に設定。

アンカーの設定
[alt(option)]キーと[shift]キーを押しながら
PowerMeterParentの位置を修正
PowerMeterParentの位置を修正

 

スライダーを配置した後のイメージはこんな感じ。画面右のオレンジのメーターが今回作ったもの。

スライダー配置後
スライダー配置後のイメージ

 

実は右下のボタン、太字にしちゃいました。ずっと気になってたんですよね、ここだけNormalだったのが。『Button』オブジェクトの子オブジェクトである『Text』オブジェクトのTextコンポーネントで、Font Styleを[Bold]に変更しました。

ついでに[Add Component] -> [UI] -> [Effects] -> [Outline]からOutlineコンポーネントも追加。Effect DistanceのXを[2]、Yを[-2]に設定します。

Textコンポーネント
実はTextコンポーネントを修正

 

配置が終わったので、今度はスクリプトを編集して動きを作っていきます。

 

スクリプトの編集方針

今回の編集方針は以下の通りです。

  • 上下するメーターに応じてボールに加わる力を変える
  • メーターを上下させる
  • 最大値、最小値の時は少し止めたい

メーターの上下はUpdate()を使って毎フレーム値を変えていけば良さそうです。上下だと、上がる時と下がる時で動きを切り替える必要がありますね。

また、最大値、最小値になった時はメーターがちょっとだけ止まるようにします。最大値を選択できるのが1フレーム(60FPSで0.016秒)だけとか、TASさんじゃないとムリ。

編集したものがこちら

上記方針で編集したスクリプトについて、更新点を中心に解説していきます。全文を確認したい場合は『GitHub Gist』をみてね。

 

まずはメンバ変数の追加と更新から。

先に既存部分の更新点ですが、forceMagnitudeの[SerializeField]を外しました。今回メーターでボールに加わる力の強さが変わるようにしたので、Inspectorから値を変えてもすぐにメーターの値が格納されることに。余計な設定を残しておくのは混乱の元なので、Inspectorから変えられないようにしました。

今回新規で追加したのは、『PowerMeter』オブジェクトへの参照、Sliderコンポーネントへの参照、メーターの上下するスピード、ディレイとウェイト、メーター増加中フラグです。

参照はいつものアレですが、meterSpeedはメーターが上下するスピードで、Inspectorから調整できるようにしています。毎フレームこのスピードの分だけメーターが変動します。

delayTimeは最大値または最小値で止まる時間で単位は秒。0.08秒だと、60FPSの場合だいたい5フレームから6フレームくらいの入力猶予があります。あまり止めすぎてもゲームとして面白くないし、かといって短くしすぎてもシビアすぎるしで調整が難しいところ。

waitTimeは最大値または最小値でどれだけ待ったかを表しています。この時間がdelayTimeを超えたらメーターが動き出すようにします。

メーターの上下を表現したいので、そのフラグも用意。

 

Start()の中ではpowerMeterSliderへの参照をセットしています。Sliderコンポーネントは特にアクセスする回数が多いので、GetComponentで参照をキャッシュしておかないと泣く羽目になります。

 

Update()では、MovePowerMeter()を呼ぶ処理を追加しました。この処理の中身は後述しますが、Update()が呼ばれるためにスライダーの値を変えていきます。時間変化で量が変わる処理はUpdate()を使うことが多いです。

 

GetBoostForce()は力の大きさと方向をかけてVector3を返すメソッドですが、外部からガイドを表示するために呼ばれています。ガイドは最大値を基準に表示したいので、スライダーの最大値と、角度によって計算される力の方向をかけて値を返すようにします。

この時、外部のスクリプト(GuideManager)にあるStart()の方が早く処理されることがあり、SphereBoosterのStart()より早いと参照がセットされてなくて「NullReferenceException」のエラーが出ます。なので、nullチェックして参照がなかったらここで参照をセットするようにしています。

 

 

今回のメインであるMovePowerMeter()です。メーターを上下させるのは飛行中フラグがfalseの時にします。なのでtrueだったらreturnしてメーターを動かさないようにしています。

境界値は、メーターを止める時の値、つまり最大値か最小値を格納するために用意しています。分岐後の処理を共通化したかったので、ローカル変数boundaryValueを作っています。

メーターが増加中にはスライダーの値を増やし、減少中にはスライダーの値を減らしています。スライダーの値を直接変えているのは、最大値や最小値になったらその値でストップしてくれるためです。

分岐の後は、境界値に達したかどうかを確認しています。float型の変数の場合、等価演算子(==)を使った比較は非推奨なので、MathfのApproximately(ほぼ同じ)を使って比較しています。floatには誤差があるため、ぴったり一致しないんですよねぇ。

境界値に達していたら、そこで少し待つ処理を入れています。

最後に、forceMagnitudeにスライダーの値を入れて、力の計算ができるようにしています。

 

WaitAtBoundaryValue()は境界値で待つ処理です。Time.deltaTimeで前フレームの処理にかかった時間を取得して、フレーム間の処理時間をwaitTimeに足しています。

delayTimeを超えたら、増加フラグを反転させてメーターの動きを逆にします。

 

今回実装したスクリプトの全文は『GitHub Gist』にあります。

オブジェクトの参照をセット

スクリプトを更新したらオブジェクトをセットします。

今回新しく追加されたのは『PowerMeterObject』の項目です。『Hierarchy』ウィンドウから『PowerMeter』オブジェクトをドラッグ&ドロップするか、右の丸ボタンから選択しましょう。

オブジェクト参照のセットを忘れずに(自戒)
オブジェクト参照のセットを忘れずに(自戒)

 

動作確認

んじゃ確認しましょ。(GIFは2倍速)

メーターが上下する
メーターが上下するようになった

 

メーターが上下して、その値に対応してボールが飛んでいます。力に関してはこれでいいでしょう。GIFが2倍速なのでメーターの動きがめっちゃ早いですが、実際にはこの半分だから目押しも大丈夫そう。

次は角度を変えられるようにしましょうか。角度は0度から90度の範囲でゲームのプレイヤーが任意の値を選択できるようにしましょ。

角度と力をゲーム内で操作して、ゴールを目指す感じのゲームにできそう。うん、カービィボウルっぽい。

まとめ

今回はメーターを自動で上下させて、ボタンを押した時の値を読み取ってボールの強さとする処理を実装しました。

ボールの飛ばし方を決めるのは力の大きさと方向なので、力の大きさの方を実装することができました。ということは次回は、力の方向ですね。

角度についてはプレイヤーが任意の値を選べるようにして、それにしたがってガイドも動かすようにします。

     

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

CTA-IMAGE

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


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


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