Unityの学習方法はたくさんあります。公式のチュートリアルや書籍、ブログ、YouTubeやUdemyなどの動画教材、有料のオンラインスクールなどがあります。
今回は『i-school』というオススメのサイトを紹介させてもらいます。
i-school
https://i-school.memo.wiki
i-schoolはUnityのゲーム制作を学ぶためのサイトで、無料で利用できます。豊富な教材があり、どれを始めればいいか迷うこともあるかもしれません。
Unity初心者の悩み:
ゲーム開発を始めたいけれど、どの教材を選べばいいのか、どうやって始めればいいのかわからない。特に、初心者向けのわかりやすい教材が欲しい。
今回はその中から1つ、『2Dタップシューティング』を学習しましたので、その内容を共有したいと思います。
i-schoolの『2Dタップシューティング』について
ゲーム内容
i-schoolの『2Dタップシューティング』は、プレイヤーは動かず、マウスをクリックすると弾を発射するゲームです。敵は画面上部から現れ、一定数の雑魚が出現するとボスが登場します。プレイヤーの下の拠点に敵が当たるとライフが減り、ライフがゼロになるとゲームオーバーになります。ボスを倒すとゲームクリアです。
発展編の学習内容
今回学んだ発展編では、攻撃の種類の追加や経験値要素など、エネミーの攻撃とエネミーに属性要素を実装し、相性によってダメージが変動する要素。ゲーム開始やボス出現の演出をアニメーションで行ったりも。
ゲームを賑やかにするためのBGMやSE、ボイスなども実装したりしました。
発展編の学習時間
参考までに、現在、私はUnityのチュートリアルを少し、本の教材を3冊、Udemyの教材を3つほど(ヴァンサバ風ゲーム、脱出ゲームを2つ)、YouTubeの動画を見ながらFlappyBirdなどを作ってみました。Unityの学習レベルでは初心者だと思います。
前回の基礎編が手順28まであり、学習時間は約30時間くらいでした。
今回の発展編は発展41まであり、かかった日数は10日ほどで、合計30時間はかかっていたと思います。前回の基礎編より難しい部分もあり時間がかかりました。
学習の振り返り
それでは、実際に作ってみて学んだ内容を振り返りたいと思います。
発展編は発展41まであります。
各手順を振り返る
発展1~4 プログラムの視認性、拡張への利便性向上
プログラムを見やすくしたり、ゲームを拡張しやすくするための変更や追加を行いました。
発展1 -UI関連処理の統合-
DefenseBase.csで行っていた耐久力ゲージの処理をUIManager.csで実行するように修正しました。
発展2 -エネミー用のデータベース作成-
EnemyType.csの作成
enum(列挙型)で、エネミーをNormal,Elite,Bossの3種類の値を用意。
EnemyDataSO.csの作成
スクリプタブルオブジェクトを作成するためのスクリプト
・エネミー1体単位でのデータ(Hp、攻撃力、画像などのデータ群)を扱うクラス
・エネミーのデータをまとめるList

EnemyDataSO
EnemyDataSO.csを元にEnemyDataクラスのスクリプタブルオブジェクトを作成。
InspectorからHPや攻撃力などのパラメーターを入力し、3種類のエネミーのデータを作成しました。

発展3 -エネミー用のデータベースの利用-
EnemyControllerを修正し、スクリプタブルオブジェクトのデータを参照してエネミーを生成するようにしました。
EnemyGeneratorを修正し、エネミーのタイプごとに処理を分岐するようにしました。
ノーマルタイプの場合、リストからランダムにエネミーを生成されるようにしました。(現在の設定ではキノコと蛇のランダム)
発展4 -エネミーのデータを外部のスクリプトで参照する処理の実装-
拠点へのダメージをEnemyDataのエネミーの攻撃力を参照し、処理するように修正しました。
発展5~7 Exp要素追加
敵を倒した際にExpを獲得するようにして、倒したときにExpを表示させたりします。
発展5 -Exp の設定追加と Exp 表示用のゲームオブジェクトの作成-
Canvas内に表示用のオブジェクトを作成しました。
数値を表示させるためのTextと、「EXP」というImageです。

EnemyDataSO.csのEnemyDataにexpの項目を追加しました。エネミーを倒すと入手できるEXPになります。
発展6 -GameData の作成、Exp 獲得処理と Exp 表示更新処理の実装-
シングルトンでGameDataを作成しました。
GameData内で合計EXPの値を更新したり、外部からEXP情報を参照できるようにします。
UIManager,EnemyGenerator,EnemyControllerを修正し、エネミーを倒した際にEXPが加算されるようにしました。
発展7 -GameData の活用-
拠点の耐久力やエネミーの最大生成数などをGameDataクラスに集約し、各スクリプトが参照して受け取って利用していくという設計に変更します。
発展8~11 エネミーの移動方法追加
エネミーの移動方法を増やします。
発展8 -エネミーの移動方法を追加-発展8 -エネミーの移動方法を追加-
MoveType.csの作成
enum(列挙型)で、エネミーの移動方法を3種類用意。
EnemyDataSOにMoveTypeの値を追加。
発展9 -エネミーの移動方法に合わせた移動処理の実装①-
EnemyControllerのエネミーの移動方法の修正
MoveType.Starightの場合、直進移動
移動タイプがStarightの場合、エネミーが直進移動するようにしました。
MoveType.Meanderingの場合、蛇のように蛇行移動
DOTweenの機能を利用して、移動タイプがMeanderingの場合、蛇のように蛇行移動するようにしました。


発展10 -エネミーの移動方法に合わせた移動処理の実装②ー
MoveType.Boss_Horizontalの場合、ボス登場と水平移動
上からボスが登場し、右に移動し、しばらく止まって左に移動…といった細かい処理を行います。
DOTweenのOnCompleteメソッドやSequence機能を使用して一つの移動処理が終わってから次の処理を実行させます。



発展11 -エネミーの移動用のスクリプタブル・オブジェクトの作成と運用-
MoveEventSOを作成
EnemyControllerで行っていた移動方法のメソッドをMoveEventSOに移動させます。
UnityActionという処理を利用します。
メソッドを登録しておける変数という感じらしいです。
次に、蛇行移動の挙動が一定でなかったため修正しました。
発展12~16 エネミーによる攻撃、フロート表示の実装
エネミーが攻撃を行うようにします。
エネミーや拠点に攻撃が当たったらダメージを表示させるようにします。
発展12 エネミー用のバレットの作成と自動生成処理の実装-
エネミーが一定間隔でバレットを発射してくるように処理を追加しました。
エネミー用のバレットのプレファブを作り、タグをEnemyにしました。

コルーチンメソッドを使用して5秒ごとにバレットを発射する処理と、while文を使用し発射する処理をエネミーが消滅するまでループするようになっています。
発展13 ーバレット関連の追加処理の実装-
拠点に触れたコライダーにBulletスクリプトがアタッチされていたらバレットの攻撃力をダメージに代入するようにしました。(エネミーバレットのプレファブにBullet.csがアタッチされています)
エネミーバレットをプレイヤーのいる方向へ発射するようにしました。
ボスもバレットを発射できるようにしました。
発展14 -Listの作成と活用-
ゲーム終了時(ゲームクリアとゲームオーバー時)に画面に残っているエネミーとバレットを破壊するようにします。
エネミーを生成した段階でListに情報を登録し、そのListを使用してゲーム終了時にエネミーを破壊させます。
for文を使用し、Listから画面に残っているエネミーを確認し破壊させていきます。
発展15 ーフロート表示の作成ー
発展16 ーフロート表示の実装ー
エネミーにダメージを与えた時や、拠点がダメージを受けた時に数値を表示するようにします。


EXP獲得時にも数値を表示するようにします。

発展17~28 特殊バレットの実装
プレイヤーの攻撃の種類を増やします。
獲得したEXPを消費し、一定時間特殊なバレットを使用するという設計です。

こちらが完成形
発展17 ーバレット用のボタンの作成ー
耐久力ゲージの下にバレット用のボタンを作成しました。

発展18 ーバレット用のボタンの自動生成ー
バレットのボタンを処理をするBulletSelectDetail.csを作成し、バレット用のボタンオブジェクトにアタッチ。
BulletSelectManagerオブジェクトとBulletSelectManager.csを作成。
こちらのスクリプトからボタンを自動生成させます。

発展19 ー世界観に合わせたゲーム素材の選定ー
バレットとバレットボタンに使用する画像の用意
バレットに設定する画像とボタンに設定する画像をフリー素材から探し、SpriteEditor機能を使い分割しました。

発展20 ーバレット用のデータベース作成ー
BulletDataSO.csを作成
BulletData用のListとバレットの種類を分けるBulletTypeや利用者の種類を分けるLiberalTypeなども用意します。
バレットの攻撃力や速度、バレットとボタンの画像、その他にこれから使うメンバー変数を定義します。
スクリプタブルオブジェクトを作成
InspectorのBulletDataListから攻撃力などの数値や画像などを設定します。

発展21 ーバレット用のデータベースの利用①ー
Bullet.csを修正し、BulletDataSOのデータを参照して反映されるようにします。
攻撃力や速度に使用していた引数を変更。
画像を変更するためのSerializeField属性の変数の宣言、変更するための処理を行いました。
GameDataに変数を用意し、使用中のバレットのデータを代入される処理も行いました。
発展22 -バレット用のデータベースの利用②-
バレットの種類を合計4種類にするためにバレットデータを3つ増やす。
BalletDataを参照して画像やパラメーターが異なるボタンを生成させます。
発展23 -バレット用の発射時間の制御-
初期バレット以外は使用できる時間に制限があるため、残り時間に合わせてゲージが連動するようにします。
バレット選択ボタンを押すと青いゲージが表示されて減少していきます。
選択している状態を装填中、選択していない場合は未装填というようにします。


初期バレットの設定をします。
所持しているEXPを消費し、特殊なバレットを使用するという設計になるので、
必要EXPが0のものを初期バレットとします。
発展24 -バレット用の発射時間のボタン間の連動-
使用可能時間が残ってる状態で他のバレットを選択したとき、ゲージの減少を一時停止させる。再度選択したときにゲージの減少を再開させる。
使用可能時間が無くなったら2回目以降選択できないようにする。
再度使えるようにするために、使用可能時間を初期値に戻す処理を追加する。
選択中のバレットの使用可能時間が終わったら、初期バレットに切り替わる処理を実装。
発展25 -バレット選択用ボタンのコストによる制御-
特殊バレットを使用するために必要なコスト(EXP)を表示させます。
選択したときにはコスト(EXP)を非表示にする。


コストが足りない時はボタンを押せないようにするために、ButtonコンポーネントのInspectorの中にあるinteractableをスクリプトから操作する処理を作ります。

発展26 -バレット選択用ボタンのコストと Exp の現在値による、ボタンのオン・オフ制御の連動-
必要コストより所持コストが上回ったらボタンの押せるようにする。
所持EXPに変化があるたびに、ボタンが押せるかどうか確認します。
GameManager.csのStartメソッドの戻り値をvoidからIEnumerator型に変更する。
Start メソッドをコルーチン・メソッド化することが出来ます。
(遅延処理や一時中断処理が実装できるようになります)
コルーチンにしたため、バレット選択ボタンの生成が終了してから次の処理が行われるという処理になりました。
発展27 -バレット選択用ボタンのコストの支払い処理とボタンのオン・オフ制御の連動-
バレット選択ボタンを押した場合に、表示されているEXPを減算する処理を追加します。
それに連動してボタンのオン・オフを切り替える処理を追加します。
また、EXPが減少するので他のバレット選択ボタンが押せるかどうかの確認処理も行うようにします。
すでにコストを支払っているバレット選択ボタンはコストが足りなくてもオフにならないようにします。(残りゲージが残っているため)

発展28 ーバレットの種類による性能変更の追加ー
バレットの特性を変更します。
3方向に飛んで行くバレット、5方向に飛んで行くバレット、近くのエネミーに向かって飛んで行くバレットの3種類です。



BulletTypeは用意してあるので、それに合わせて処理を分岐させます。
Player_3ways_Piercing(3方向のバレット)だった場合for文を3回処理するようにし、バレットの座標をずらして生成させます。
(Player_5ways_Normal(5方向のバレット)なら5回for文を処理。)

Player_3ways_Piercing(3方向)とPlayer_Blaze(自動追尾するバレット)は貫通するようにする。(敵に当たってもバレットを破壊しないようにする)
自動追尾するバレットを実装する。
最も近いエネミーにバレットが飛んで行くという処理にしたいので、エネミーの位置情報を取得する必要があります。


画面内にEnemyタグのオブジェクトがいたらプレイヤーとの距離を確認します。
1体ずつ距離を比較していき、一番近いエネミーに向かってバレットが飛んで行くという設計になります。
発展29~32 アニメーション演出の実装
ゲーム開始時やクリア時、ボスの登場演出を追加します。
発展29 -ゲームクリア演出の追加①-
アセットを使用してゲームクリア時に花火にエフェクトを表示させます。
表示させる数と色をランダムにし、コルーチンを使って間隔をあけて表示させます。

発展30 -ゲームクリア演出の追加②-
DOtweenを使い、GameClearの文字をコミカルにアニメーションさせます。
TAP TO RESTARTの文字をフェードさせるアニメーションをループさせます。

発展31 -ゲームスタート演出の追加-
GAME STARTのロゴを左から跳ねながら登場させ、その後ロゴが退場してからゲームが開始されるようにします。


発展32 -ボス出現時の警告演出の追加-
ボス登場時に警告演出を実装させ、演出が終わったらボスが生成されるようにします。

発展33~37 属性要素の実装
プレイヤーのバレットに属性要素を追加し、エネミーとの相性によってダメージを増加させます。
発展33 -属性の追加-
ElementType.csとElementDataSO.csを作成します。
スクリプタブルオブジェクトを作成して設定します。
画像と属性の項目を設定します。
BulletDataSO.csにelementTypeの項目を追加する。
EnemyDataSO.csにもelementTypeの項目を追加する。
ElementCompatibilityHelper.csを作成し、相性の判定を行います。
攻撃側と防御側の属性を確認して判定します。
発展34 -属性の要素の運用-
EnemyController.csを修正し、相性が良かった場合ダメージを増加させます
DefenceBase.csを修正し、拠点が受けるダメージも相性によって増加させる処理を行います。
発展35 -フロート表示に属性の要素の運用-
FloatingMessage.csを修正し、弱点属性によるダメージの場合表示する文字を大きくします。


発展36 -バレット選択ボタンに属性の情報を反映-
BulletSelectDetail.csを修正し、ElementDataSOからバレットボタンの背景画像を取得し反映させます。

発展37 -エネミーのバレット処理の修正-
エネミーのバレットにも攻撃力や速度、属性などの設定を実装します。
BulletDataSOのスクリプタブルオブジェクトのBulletDataListを2種類増やします。
(ノーマルエネミーとボス用のバレットを追加します)
EnemyController.cs、BulletSelectManager.cs、EnemyGenerator.csを修正し、エネミーのバレットにもBulletDataの情報を使用できるようにします。

発展38~41 サウンドの実装
ゲームを賑やかにするサウンドを追加します。
発展38 -BGMの準備-
ゲーム内で流すBGMを2つ用意します。
メインBGMとボスのBGMです。
SoundDataSO.csを作成します。
BgmTypeの列挙子でMain,Boss,Silence(無音)の3種類を用意。
BgmDataクラスにてオーディオファイルやBGMの種類、ボリュームなどのデータを用意します。
BGM用のクラスのデータをまとめるListも用意します。
発展39 -BGMの再生-
SoundManagerのゲームオブジェクトと、SoundManager.csを作成します。
SoundManagerはどのスクリプトからいつでも利用可能な状態にさせたいので、シングルトンデザインパターンを採用します。
AudioSource.PlayとAudioSource.Stopのメソッドを用意します。
任意のタイミングでメソッドを実行しBGMを再生したり停止したりさせます。
フェード効果をつけるためにAudioSource.DOFadeメソッドも用意します。
ボリュームを徐々に大きくしたり小さくしたりできます。BGMが切り替わるときに使用します。
GameManager.csを修正し、ゲーム開始時にメインBGMが鳴るようにします。
UIManager.csを修正し、ボス登場時にボス用BGMが鳴るようにします。
発展40 -SEの再生-
ゲーム内で鳴らすSEを3つ用意します。
ダメージ時、ゲームクリア時、ゲームオーバー時の3種類です。
SoundDataSO.csにSEの項目を追加し、スクリプタブルオブジェクトにもSEを追加します。
SoundManager.csにPlaySEメソッドなどを追加します。
任意のタイミングでPlaySEメソッドを実行しSEが鳴るようにします。
発展41 -ボイスの再生-
ゲーム開始、ゲームオーバー、ゲームクリア、攻撃、ダメージ、ボス警告演出時にボイスが鳴るようにします。
各場面のボイスを用意し、SoundDataSO.csに追加し、スクリプタブルオブジェクトに用意します。
SoundManager.csにPlayVoiceメソッドなどを追加します。
複数のボイスがある場合ランダムで再生するようにします。
(ゲーム開始時のボイスが2つある場合ランダムでどちらかが再生されます)
任意のタイミングでPlayVoiceを実行しボイスが再生されるようにします。
まとめ
発展編を終えてみて、基本編よりさらに難易度が上がった内容だと感じました。
特殊バレットによる属性相性のダメージ増加、使用するためのコストや使用時間など、ゲームの面白さを向上させる要素が多く、ゲーム開始やボスの登場演出を作る過程も非常に楽しかったです。
文章が多く、難しいと感じる箇所もありましたが、難しい部分は一度スクリプトを書いてからもう一度読み直すことで理解が深まりました。また、プログラムの流れを整理し、ゲームの拡張性を考えた設計は非常に勉強になりました。一から設計を考えるのは難しいですが、より多くの教材や動画を通じて学んでいこうと思います。
i-schoolの教材はオススメ!
i-schoolはとてもいいサイトです。
今回の教材に限らず、いい教材がたくさんあります。
是非Unityの学習に役立ててみてください。
この記事を読んで挑戦したり、実際に取り組んだ方々のコメントをお待ちしています。
発展編を終え、次は拡張編に挑戦しようと思います。