【第6回】ボタンの動作・処理を実装するUnityチュートリアル
- 2018.04.11
- Unityチュートリアル
- Unity, チュートリアル
前回のUnityチュートリアルでは、画面に表示するUIパーツとしてボタンを配置する方法をお送りしました。
特にモバイル向けのゲームだと、3Dのオブジェクトを用意するよりUIでイラストを表示することが多いような気がします。モバイルの性能も上がって来ているので、だんだんと3Dのゲームも増えている印象ではありますが、場面に合わせて両方使えるようになっておくと超お役立ちです。
さて今回は、配置したボタンを押した時の処理を実装するチュートリアルです。このチュートリアルでは、スペースキーを押してボールを斜方投射する機能を実装したので、今度はゲーム画面のUIから同じようにボールを飛ばせるようにします。
前回のチュートリアルはこちら。
今回の目的
ゲーム画面に配置されたボタンを押した時に、ボールが斜方投射されるようにします。
といってもスペースキーを押した時の処理をボタンから呼び出せるようにする方法で実装するので、実装コストは少なめ。
楽してズルして結果を残す方針でいきましょ。
プロジェクトの準備
前回のチュートリアルで作成したプロジェクトをそのまま使います。
このページに先にたどり着いた方は、チュートリアルの初回から追っていただけるといいかもしれません。
ボタンから呼び出すメソッドを準備
前回はUnityの画面上での操作でしたが、今回はスクリプトがメイン。
まずは、第4回で作ったスクリプトの内容を整理しましょ。
変更したのは以下の点。
- Rigidbodyコンポーネントへの参照をキャッシュ
- 力の大きさ、向きをメンバ変数に
- ボールを飛ばす処理、ボールを停止させて初期位置に戻す処理をそれぞれメソッドに
- FixedUpdate()にアーリーリターンを追加
この中で特に注目してほしいところは1番目。
GetComponentをキャッシュする
前回までのスクリプトだと、FixedUpdate()の中でGetComponent<Rigidbody>()を呼んでいました。
これはAddForce()を使いたいがためでしたが、ここではゲーム実行中にコンポーネントの付け替えをしていないので、Rigidbodyへの参照は毎回取得する必要がありません。
最初に参照を取得しちゃえばそれを使えるので、rbをメンバ変数にしてStart()でGetComponent<Rigidbody>()を呼ぶようにしています。
そして一番大きな理由は、「GetComponentの処理は重い!」ということ。
GetComponentが呼ばれると、アタッチされたコンポーネントを上から順番に調べていって、該当するコンポーネントが見つかったらその参照を返すみたい。
ということは、今回使っているRigidbodyは『Sphere』オブジェクトの5番目にいるから、FixedUpdate()が呼ばれるたびに5回分のチェックが行われていることに。無駄無駄ァ!!
アーリーリターンの補足
この後のチュートリアルでもアーリーリターンを使うので念のため補足。
FixedUpdate()の中で、ボタンが押されてなかったらreturnにしているけれど、voidだから何も返さずFixedUpdate()を抜けています。仕事残ってないなら無駄に残業しないで早く帰りなさい、的な。
元々はif文がネストになっていましたが、ネストが深くなるとかなり読みづらいんですよねぇ。ネストが深くなりそうな場合には、今後こうした書き方をしていきます。
ネストの深さは闇の深さなんて名言もありますし、闇深ネストの生まれない平和な世界を目指します。
ボタン用メソッドを追加
このスクリプトに、ボタンを押した時に呼び出されるメソッドを追加します。
このメソッドの仕事は至極単純で、呼び出されたらボタン押下フラグをTrueにするだけ。やっていることは、スペースキーが押された時と同じです。ね? 簡単でしょう?
以下のメソッドをBoostSphere()の下に書き加えます。
ポイントは、外部から呼び出されるメソッドなので、publicにすること。その他のメソッドにはアクセス修飾子が付いていませんが、省略した場合はprivateになるので安心です。
ボタンからの呼び出し
メソッドが準備できたら、Unityの画面に戻って呼び出し準備を行います。『Button』オブジェクトを選択し、ButtonコンポーネントからOnClick()の[+]ボタンをクリック。
新たに枠が表示されるので、まずはスクリプトがアタッチされているゲームオブジェクトをアタッチします。
『Button』オブジェクトを選択している状態で、『Hierarchy』ウィンドウにある『Sphere』オブジェクトをドラッグします。
これでメソッドを選べるようになりました。[No Function]になっているドロップダウンリストをクリックし、[SphereBooster] -> [OnPressedBoostButton()]を選択します。
このままゲームを実行してみましょう。
……ボタンを押してボールが飛ぶようになりました!
ボタンへのフォーカス
上の状態で完成としたいところですが、実は、ボタンをクリックした後にスペースキーを押すと変な動きをします。初期位置に戻った瞬間飛び出したり(実際にやってみよう)。
これはUnityの仕様によるもので、最初にボタンをクリックしたことで、そのボタンにフォーカスが当たるのです。ボタンにフォーカスが当たっていると、[Enter]キーまたは[Space]キーを押した時に、ボタンをクリックしたと見なされます。
どうやらボタンにフォーカスしている時は、GetKeyDownのタイミングでボタンクリック扱いになる見たい。その後私たちの設定したGetKeyUpを検知すると飛行中フラグを速攻で切り替えるようです。
ちなみに、ゲーム画面のボタン以外の部分をクリックするとフォーカスを外せます。
……結果として何が問題だったかというと、スペースキーを発射ボタンに割り当てたのが問題でした。同じキーで2種類の入力がされるとか、いかんでしょ。設計者を呼べぃ!!
……。
ええ、私です。
実は初心者の頃にこの罠にハマって悩んでいたので、ここで紹介しておきたかったのでした。決して忘れていた訳ではないんです本当です信じてください!
キー入力の修正
問題があると分かったら、サクッと修正しちゃいましょう。恥ずかしい過去にサヨナラバイバイ。
修正ポイントはもうお気付きかと思いますが、Update()内、Inputで検知する対象のキーを変更します。ボタンのラベルが”Boost!”なので[B]キーにしておきましょ。
合わせて今回のスクリプト全体を記載します。
これでスペースキー重複問題が解決しました。[B]キーでボールを飛ばし、UIのボタンでもボールを飛ばせます。
ボタンにフォーカスがある場合は[Enter]キーと[Space]キーでもボタンを押したのと同じ効果があります。ここは仕様なのでOK。
キーボードからの操作、画面上のボタンでの操作ができるようになり、ちょっとずつゲームの輪郭がぼやっとほんのりうっすらと見えてきました。
次は、ハードコーディングされている力の大きさをInspectorウィンドウで変えられるようにしましょ。デバッグでいちいちコードを書き換えたくないですもんね。
まとめ
画面に配置したボタンを押すと、ボールが飛ぶようになりました。
ポイントは、ボタンから呼び出すメソッドをpublicにしておく辺りでしょうか。これを忘れるとButtonコンポーネントのOnClick()から見えないので焦る羽目になります。
次回はハードコーディングされているメンバ変数をInspectorウィンドウから変更できるようにするチュートリアルです。
ゲーム開発の攻略チャートを作りました!
-
前の記事
【第5回】画面にボタンを配置するUnityチュートリアル 2018.04.10
-
次の記事
【第7回】ハードコードにさよならバイバイ! Inspectorから値を変更する 2018.04.11
コメントを書く