【第23回】斜方投射の角度を画面から操作するUnityチュートリアル

【第23回】斜方投射の角度を画面から操作するUnityチュートリアル

前回のチュートリアルでは、画像ファイルのインポートを行い、画面にインポートした画像を表示させました。また、角度を操作するためのUIも作成してあとはスクリプト作るところまで! となっています。

今回はお待ちかねのスクリプト作成。個人的にはスクリプト組んでる時間がめちゃくちゃ好きなので、是非あなたともその楽しみを共有したいところ。

ん? スクリプト書くのは苦手だって?

最悪コピペして動きを見てみるのもあり。最初にサンプルコードをそのまま動かしてみるのもコーディングには大切だと思ってます。

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

 

今回の目的

ボールを打ち出す角度をゲーム画面から操作して決められるようにします。

これができると、角度、パワーをプレイヤーが決められるのでゲームっぽくなってきます。

プロジェクトの準備

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

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

前回の状態

前回のチュートリアルでは、こんな感じの画面になるよう、角度変更ボタンを作成しました。今何度なのかを表す矢印も表示されています。矢印はスクリプトから向きや位置を決める予定なので、宙ぶらりんなう。

UI配置済みの画面
こんな画面を作ったのだポッター

 

イメージとしては、矢印はボールの位置に来て、画面左側にあるボタンを操作すると矢印の向きが上下する感じ。

0度から90度の範囲で動くようにしましょ。もともと『Inspector』ウィンドウから設定していた数値もその範囲でしたからね。

ちょっと準備

スクリプトの編集に入る前に、矢印の画像をボールの位置に合わせておきましょうか。宙ぶらりんだと見栄えがちょっとね。『AngleGuide』オブジェクトを選択し、TransformコンポーネントのPos Xを[50]、Pos Yを[-148]あたりに設定します。

矢印のTransform
矢印を動かすのだポッター

 

これでちょうどボールの位置あたりに表示されるはず。

矢印がボールの位置に
矢印がボールの位置に

 

EventTriggerの導入

今回、角度の変更にはボタンを使いますが、Unityのボタンはデフォルトだと「1回押されたら1回イベント実行」となっています。

勘のいいあなたはお気付きかもしれませんが、これだと角度を変えるたびにボタンを連打しないといけないんですよね。マウスでずっとカチカチカチカチやってるのはプレイヤーにとって負担になります。

そこで今回新たに導入したいのがEventTrigger。これは、「このオブジェクトの上でマウスがクリックされた」といったイベントを拾ってくれるコンポーネントです。マウスに限らず、スマホでのタップも拾ってくれます。

「マウスが離された」というイベントまで拾ってくれるので、ボタンを押した時にフラグをtrueにして、ボタンが離された時にフラグをfalseにする、なんてことも可能に。フラグがtrueの時にUpdate()で処理を呼べば、ボタンを押している間に処理を行うことができます。

ボタンのオブジェクトにEventTriggerコンポーネントをアタッチすることで、画面上の動きや見た目、色はボタンのままにして、実際の動作はEventTriggerで定義する、なんて美味しいこと取りができます。

実際にアタッチしてみる

『AngleUpButton』オブジェクトを選択し、[Add Component] -> [Event] -> [Event Trigger]を選んでEventTriggerコンポーネントをアタッチします。

EventTriggerのアタッチ
EventTriggerのアタッチ

 

アタッチすると、以下のようなコンポーネントが表示されます。最初は何のイベントも登録されていないので、イベント追加用のボタンが表示されているだけですね。

EventTriggerコンポーネント
EventTriggerコンポーネント

 

登録したいのは、このボタンが押された時と、ボタンが離された時のイベント。スマホで画面をタップした時も同じくイベントを拾ってくれます。

まずは[Add New Event Type] -> [PointerDown]を選択。

PointerDownの登録
PointerDownの登録

 

Pointer Downの設定項目が表示されました。ボタンで呼び出すメソッドを登録したのと同じように、ここでもメソッドを登録できます。続いて[Add New Event Type] -> [PointerUp]を選択します。

PointerUpの登録
PointerUpの登録

 

これでボタンが押された時、離された時に呼び出すメソッドを登録できるようになりました。登録作業はスクリプトの編集後に行います。スクリプトを触った後ってすぐテストしたくて、よく忘れるんですよね(1敗)

あ、『AngleDownButton』オブジェクトでも同様に設定項目を追加します。

メソッドの登録が可能に
メソッドの登録が可能に

 

スクリプトの編集

さぁお待ちかねのスクリプト編集のお時間です。今回の方針は以下の通り。

  • 矢印の画像をボールの位置に表示する
  • forceAngleの値に合わせて矢印の画像を回転させる
  • 角度変更ボタンが押された時の動きを追加
  • ついでにキーボードの上キー下キーでもボタンと同じ処理にしたい
  • ガイドも角度に合わせたいよね
  • ボールの飛行中は角度を変えられないようにしたい
  • 後矢印も表示しないようにしたい
  • 同じく飛行中にガイドを表示しないようにしたい

……といったように盛りだくさんです。今回はSphereBoosterとGuideManagerをいじりました。変更した部分も多いので、解説特盛で。

なお、今回のスクリプトの全文は『GitHub Gist』にあります。SphereBoosterGuideManagerの2つをコピペすればすぐ動きを確認できます。

 

まずはGuideManagerから。

SphereBoosterからSetGuidePositions()を呼びたいので、アクセス修飾子をpublicにしました。

また、ガイドの表示/非表示をセットするメソッドSetGuidesState()を追加しました。こちらもpublicにしています。

foreachを使って、ガイドのリスト内に存在する各ガイドオブジェクトを非表示の状態にしています。オブジェクトはSetActive()メソッドで表示/非表示を設定可能です。

 

続いてSphereBooster。

今回はメンバ変数の追加が大量です。私は『Inspector』ウィンドウで参照をセットする系の変数を上にまとめたいので、ちょっと分散して追加をしています。

参照をセットしたいのは、矢印のオブジェクト、角度変更ボタン(上)、角度変更ボタン(下)、『GuideParent』オブジェクトです。

forceAngleについては、ボタンから角度を変えられるようにするため、[SerializeField]を外しました。

角度の増減量についてはconstをつけて固定値にしています。ボタンが押された時にこの値をangleDeltaに格納し、その値の分だけ増加または減少させます。

値を見ているので、フラグは用意しなくても済みそうです。

角度の上限、下限も固定値で定義。

あとはいつものように参照のキャッシュを行うための変数を準備しています。

 

 

Start()では、今回追加した参照のキャッシュ用変数に、それぞれのコンポーネントへのキャッシュを追加しています。

 

 

Update()はキーボードからの入力監視用メソッドを呼ぶように変更しました。また、角度の変更に関するメソッドもここから呼ぶようにしています。

新しく追加したメソッドの詳細は後述します。

 

 

お次はStopFlying()の変更。ボールが飛行中ではないときに矢印、ガイドを表示するようにします。

この中で、ガイドの表示に関しては、GetComponentで参照を行ったGuideManagerが持つメソッドを呼んでいます。

 

 

BoostSphere()も忘れずに。ボールの飛行中に矢印やガイドを非表示にしています。これを忘れると、矢印もガイドも一緒についてきます。

 

 

この3つのメソッドは冒頭で追加したEventTriggerコンポーネントに登録するために使います

OnPressedAngleUpButton()は角度変更ボタン(上)が押された時に呼ぶメソッドです。OnPressedAngleDownButton()は逆に角度変更ボタン(下)が押された時に呼びます。

どちらのメソッドでも、角度の増分angleDeltaに値を設定しており、angleDeltaが0でないとき、その値をforceAngleに加算または減算していきます。0のときは加減がないので処理を行わないようにしており、この変数がフラグのような役割も担っています。

どちらのボタンを押した場合も、離す時にはOnReleasedAngleButton()を呼びます。離した時の処理はどちらも同じく増分を0にしたいので、今回は共通化できました。

 

 

次はChangeForceAngle()メソッドです。こちらはforceAngleの値を変更するメソッドです。

増分が0の場合、つまりボタンが離された後は、すぐにreturnして抜けます。

forceAngleは拡張性を考えてfloat型にしていますが、実はangleDeltaがint型なので、1.0fをかけてfloat型に変換しています。

angleDeltaの値が増加時のものであれば、最大値であるMaxAngleと比較して、MaxAngleを超えないようにしています。減少時であれば逆にMinAngleより小さくならないようにしています。

 

 

ChangeArrowAngle()では矢印の向きを操作しています。RectTransformUtility.WorldToScreenPoint(Camera.main, transform.position)は、3D空間のゲームオブジェクトの位置を取得して、スクリーン上の位置に変換するメソッドです。

座標の変換についてはテラシュールブログさんが超詳しいのでこちらも読むと吉。困ったときはテラシュールブログさんに行くとだいたい解決します。

次のQuaternion.AngleAxis(forceAngle, Vector3.forward)は、指定した軸に関して指定した角度の回転を作ります。回転はダイレクトに値をいじれないので、Quaternionを使っています。Quaternionが何者か、という点についてはまた機会を改めて。今は「回転を表すなにか」くらいの認識でOK。

飛行中でない場合は、GuideManagerのSetGuidePositions()を呼んでガイドの位置を角度変更に合わせて移動させます。

 

 

SetAngleButtonState()では、ボタンの状態を示すinteractableフィールドに値をセットします。これがtrueの場合はボタンが押せる状態、falseの場合はボタンが押せない状態です。

今回の実装ではButtonコンポーネントから処理を呼んでいる訳ではないのですが、このinteractableフィールドをfalseにするとボタンが押せない時の色に変化してくれるため、見た目のために値をセットしています。

今ボタンが押せるのかどうか、プレイヤーに伝わるように処理を入れているのがこのメソッドです。あぁ、なんて素晴らしいことでしょうか!

……いつ操作できるのか分からないとプレイヤーが混乱するので、レビューが荒れる可能性が。レビュー荒れ怖い(本音)

 

 

最後にCheckInput()です。このメソッドはキーボード入力を検知するために毎フレームUpdate()から呼ばれます。

Bキーについては以前のままで、今回は新たに上矢印キー、下矢印キーの処理を追加しています。上矢印キーが押された時にOnPressedAngleUpButton()を呼び、上矢印キーが離された時にOnReleasedAngleButton()を呼んでいます。

これは画面から角度変更ボタンを押した時と同じ動作になるようにしています。

 

今回のスクリプトの全文は『GitHub Gist』にあります。SphereBoosterGuideManagerの2つをコピペすればすぐ動きを確認できます。

EventTriggerへの登録

んじゃ動作確認を……の前に、EventTriggerにメソッドを登録しておきましょ。

まずは『AngleUpButton』オブジェクトから。

Pointer Downの[+]をクリックして画像のようなフィールドを表示させたら、『Hierarchy』ウィンドウの『Sphere』オブジェクトをオブジェクト 選択フィールドにドラッグ&ドロップします。

そのフィールドに指定したオブジェクトが持つスクリプトからメソッドを選択できるので、[SphereBooster] -> [OnPressedAngleUpButton]を選択します。

Pointer Upの方でも『Sphere』オブジェクトを選択し、[SphereBooster] -> [OnReleasedAngleButton]を選択します。

EventTriggerの登録
EventTriggerの登録

 

『AngleDownButton』オブジェクトのEventTriggerについても同様にメソッドを登録します。

Pointer Downの方には『Sphere』オブジェクトの[OnPressedAngleDownButton]を登録、Pointer Upの方には[OnReleasedAngleButton]を登録します。

AngleDownButtonのEventTrigger
AngleDownButtonのEventTrigger

 

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

いつも忘れるオブジェクトの参照セット。

今回は『Sphere』オブジェクトのSphereBoosterで参照をセットする必要があります。

  1. Angle Arrow Object …… 『AngleGuide』オブジェクト
  2. Angle Arrow Button Up Object …… 『AngleUpButton』オブジェクト
  3. Angle Arrow Button Down Object …… 『AngleDownButton』オブジェクト
  4. Guide Manager Object …… 『GuideParent』オブジェクト

それぞれ、『Hierarchy』ウィンドウからドラッグ&ドロップするか、右の丸ボタンから選択します。そろそろオブジェクトの数が増えてきたので、丸ボタンから選ぶのは大変かもしれません。

SphereBoosterの参照
参照がいっぱいなのだポッター

 

動作確認

んじゃ確認しましょ(GIFは等速)

角度変更のGIF
無事、角度を変えられた

 

OK、無事にプレイヤーが角度を変えられるようになりました。以前作った軌道予測のガイドもうまく機能しています。

Boost! ボタンを押した後はガイドを非表示にして、ボタンは押せない状態(の色)になっています。

ちゃんとキーボードの方でもボタンと同じように操作できるので、どうやらうまくいっていそうです。

この後の実装予定

プレイヤーが操作できる部分が増えてきたので、後何を盛り込めばゲームっぼくなるか考えてみると、

  • ゴルフのようにゴールを用意する
  • 落下判定をコース全体に用意する
  • コースそのものを作成する
  • ボールや地面の見た目を変える

あたりかな。

だいたい30回くらいでこの初心者向けチュートリアルを終えたいと思っています。

……。

初心者向け……?

そう、このチュートリアルは初心者向けチュートリアルなのでした。初心者向けと言いながら、がっつりスクリプトを組むハードなブートキャンプになってますが、なるべくUnityの機能を紹介をしようとしたらこんなことに……。

新しいチュートリアルではもう少し突っ込んだ話をして、よりゲーム開発をブーストさせられるようにしたいなーと。

まとめ

今回はプレイヤーが画面から角度を変えられる処理を実装するチュートリアルでした。

これでボールを斜方投射する角度とパワーを操作できるようになりました。

次回はTextureのインポートを行い、ボールや地面の見た目を変更していきます。

アセット作ってます!

CTA-IMAGE

Unityでの開発に役立つアセットを作っています。

3DダンジョンRPGを開発するスピードを200%加速するAssetや、ファンタジーRPGのダンジョンを彩るパーツを取り揃えています。

特に3DダンジョンRPGのゲームを1から作るのは結構時間がかかります。ダンジョン部分の作成はこうしたアセットを使って、開発をブーストさせてみませんか?