【ゲームの完成】ゲームループ処理の作成とレベルデザイン スクリプト全文まとめ | Unity入門の森 ゲームの作り方

【ゲームの完成】ゲームループ処理の作成とレベルデザイン スクリプト全文まとめ

Unity タワーディフェンスゲームの作り方


Unity入門の森オリジナル本格ゲーム制作講座はこちら
11種類の本格ゲームの全ソースコード公開・画像&動画による解説付き

前回(9回)は弓関連のUIを追加し、レベルアップや売却が実際に出来るようになりました。

前回の記事↓

武器や攻撃範囲の強化・武器の売買ができるお店システムの作り方
前回(第8回)では、プレイヤーによる弓の配置と、UI画面を作り始めました。 前回の記事↓ 今回はさらにUI画面を作り込み、弓オブジェクトのレベルや制作コスト・売却コスト等をやっていきます。 弓レベルの追加・コスト まず弓のアップグレードが出...

今回はついにこのタワーディフェンス講座も最終回。

タイトルやゲームクリア・ゲームオーバーなどの「ゲームループ」部分を主に作って完成させていきます。

また、これまで作ってきたC#スクリプト全文やゲームをより面白くするレベルデザインについても触れています。


【Line登録者限定のプレゼントもあるよ!】

EnemyManagerUIの作成

ゲームループの前に、EnemyManagerの情報表示を作りましょう。

第8回で作ったPlayerStatusUI オブジェクトを複製(CTRL+D)して作られるPlayerStatusUI (1) を EnemyManagerUIと名前を変更し、同じく複製されているPlayerStatusUIスクリプトは削除(右クリックしてRemoveComponent)します。

位置も重なってしまっているので Pos Yを下に下げます。 -500ぐらいが適当です。

そのまま複製され子要素の Text(HP)と Text(GOLD)も名前をText(WAVE)とText(ENEMY)に変更します。

EnemyManagerUI に AddComponent→New Script → EnemyManagerUI と選択し、EnemyManagerUIスクリプトを作成し、下記のように編集します。

メンバ変数は

  • どのEnemyManagerの情報を表示するか(Inspectorで設定)
  • EnemyManagerのWave情報を表示するためのText(Inspectorで設定)
  • EnemyManagerのEnemy数情報を表示するためのText(Inspectorで設定)

の3つです。 Update関数の中では UIのTextにWave情報と敵の数情報をセットしています。

ただ、この

enemyManager.EnemyCnt はまだEnemyManagerスクリプトに無いので EnemyCnt プロパティを追加します。

まだ現在のwaveで出現していない敵の数は waves[wave].patterns.Count になります。

そして、既に出現している敵(Enemy)は FindObjectsOfType<Enemy>().Length で取得し、それを足す事で敵残数を取得できるプロパティにしています(=>を使ったgetプロパティの省略記法です)。

注意点としては waves[wave].patternsListなのでCountで要素数を取得し、FindObjectsOfType<Enemy>()配列なのでLengthで要素数を取得しています。

2スクリプトを修正しましたので、忘れずに2つとも保存をしましょう。
UnityEditorのInspectorでEnemyManagerUIのEnemyManager、Text(WAVE)、Text(GOLD)をセットします。

それではプレイボタンを押して、確認してみましょう。

ENEMYを倒すたびに数字が減っているのが確認できます

GOLDの獲得とダメージ処理

大分ゲームが完成に近づいてきましたが、まだ

  • 敵を倒してもGOLDが増えない
  • 敵がゴール(本拠地)に到着してもHPが減らない

ので、そこもやってしまいましょう。

敵を倒したらGOLDを増やす

矢(Arrow)スクリプトで敵(Enemy)を倒した時に処理を追加します。

FindObjectOfType<Player>() でPlayerオブジェクトを探し、goldを倒した敵の金額(targetEnemy.gold)分増やしています。  

最初からHierarchyに置いてあるオブジェクトであれば、InscpectorからPlayerオブジェクトをセットしておけばいいのですが、動的に生成(Instantiate)されるArrowオブジェクトから、どうやってPlayerオブジェクトのgoldを増やすのか(どうやってPlayerオブジェクトを認識するのか)が結構悩みどころです(講座を作るにあたっても悩みどころです) これには以下のような色々な方法

  • Arrowを発射するBowに設置をしたPlayerオブジェクトを保持させ、バケツリレーのように渡していく
  • Playerオブジェクトは1つしかないので Playerオブジェクトをstatic を使ったシングルトンオブジェクトにする
  • Find系関数を使ってPlayerオブジェクトを探す

等々があるのですが、今回はFind系関数である FindObjectOfType<探したい型>() を使っていますが深い理由はありません(強いて言えば修正するスクリプトが少ない方が混乱が少ないという講座制作上の理由になります)他の方法を使っても問題ありません。

敵がゴール(本拠地)に到着したらHPを減らす

次に敵(Enemy)スクリプトを修正します。

続きを読む

このコンテンツはパスワードで保護されています。 コンテンツを読みたい方はUnity入門の森ショップ(https://unityforest.shop/)で講座閲覧権を取得してね。

Waveの追加・レベルデザイン

これで完成!! と言いたいところですが、この例だとWaveが一つしかないですね。

最後にWaveの追加方法と、さらなるレベルデザイン例を提示してこのタワーディフェンス制作講座の締めくくりとしたいと思います。(既にWaveを自分で量産している方は読み流してください)

敵のWaveを管理しているのは、EnemyManagerオブジェクトでしたね(タワーディフェンス講座 6/10参照)。

今は、Waves の Size が 1 となっているので、1waveで終わってしまいます。

なので Element  0 となっているところを右クリックし、「Dupulicate Array Element」を選択して複製することで、Element 1が増えます。
このWaveの複製を繰り返すことで何Wave構成にもできます。

なお、Element 0 の中にあった Patterns の中身もElement 1に複製されるため、多数Waveの複製をした状態で再生をして確認をすると全てのwaveが全く同じ敵構成の内容ということになります。

もちろんそれでは面白みが無いので、削除したり内容を変更していきます。

Wave2以降も作ってみたら、実際に敵の動きを確認してみたいですよね。

しかし、毎回Wave1から開始して敵を倒してやっとWave2の実際の動きを確認・・・では辛いです。

そんな時は EnemyManager のInscpectorビューで Wave を テストしたいwave番号に変更しましょう。指定Waveから開始することが出来るため時間を短縮できます。(もちろん通しでWaveをプレイするのも大事です)

テストが終わったら0に戻すのを忘れないようにしましょう。

レベルデザインの一例

例として簡単に5wave構成のレベルデザインを考えてみましょう。

  • wave1~3 は1wave内では各敵1種類だけ出現させ、「この色の敵は、このような特徴がある」というのをプレイヤーに示す、自己紹介waveとし、
  • wave4 で、複数の敵が混合で来ることで、難易度をちょっと上げていき、
  • wave5 で、計画的に弓を配置していないとゲームオーバーになってしまうような敵の量、経路で敵を配置。

という感じでしょうか。

もちろんもっとWaveを多くしても良いですし、ブロックの配置やゴール、経路も好きに変えてしまいましょう。
もっと硬いEnemyオブジェクトを新規で作っても良いです(ちょっと大きくして、最終Waveにボスとして出すというのも良いですね。)

Enemyの落とすGOLDの量を調整する事も必要かもしれません。

Playerの初期HPと所持金も非常に重要なレベルデザインになります。

ちょっと変則ですが、旗(敵からみたゴール)が複数あるステージも考えられます。

是非工夫を凝らしたステキなレベルデザインをしてみてください。
これは敵の速度やHP、GOLDを調整してみたレベルデザイン例になります。(ボスっぽい大型Enemyも作ってみました)

らくがきたわーでぃふぇんす | フリーゲーム投稿サイト unityroom

参考になれば幸いです。

おさらい

これにて、ゲームは完成し10回に渡ってお付き合いしていただいたタワーディフェンス制作講座も(ひとまず)終わりになります。

ここで終わりにさせず、別シーンでタイトル画面を作ったり、ステージセレクトを追加したり、効果音や演出を適切に入れる事でよりゲームとして完成されていくと思います。

(追記:例としてゲームルールにマイナーチェンジを加えたサンプルゲームも作ってみました。)

そろえてタワーディフェンス | フリーゲーム投稿サイト unityroom

このタワーディフェンス作成講座をベースに素敵なゲームが完成した際には是非一報頂けると嬉しいです。 ここまで読んでいただき誠にありがとうございます。

タワーディフェンスゲームの作り方講座に戻る↓

【unityで防衛ゲーム】タワーディフェンスゲームの作り方
今回のunityゲーム開発講座では2DUnityを用いたタワーディフェンスゲームシステムの制作を行っていきます! リアルタイムストラテジー(RTS)ゲームを作ってみたい方におススメです。 講座は全部で10回に分かれており、初めてunityを使ってゲームを作る人でもサクサク進められる講座になっています。 講座の中でunityエディターの使い方やUnity C#の活用法も学べるのでこれからunityでゲーム開発していきたい方はぜひ講座を見ながら実際にプログラムを書いていってください。 自分の好きなゲームステージを作成し、オリジナルのタワーディフェンスゲームを開発していきましょう!


Unity入門の森オリジナル本格ゲーム制作講座はこちら
11種類の本格ゲームの全ソースコード公開・画像&動画による解説付き

コメント

  1. サウスケイ より:

    一応完成しました!
    内容もわかりやすくまとめていてとても理解しやすかったです!
    これからUnityでゲームを作っていく上で参考にしていきたいと思います!
    ありがとうございました!

    • ばこ より:

      おお!完成おめでとうございます!
      完成報告いただけてとてもうれしいです。
      これからも新しい講座どんどん作っていくのでまたサイト見に来てもらえたらうれしいです。
      こちらこそ最後まで読んでいただきありがとうございました!^^

  2. おこめ より:

    ここ5日くらい、このブログを人生で初めてゲーム作りを完遂させました! 今までも何度か挑戦しようとしては挫折してを繰り返していたので、完成出来てめちゃくちゃ嬉しかったです!
    せっかくなのでこのままUnityゲームジャムに何かしらのゲームを投稿してみようかと思います!

    すばらしいコンテンツをありがとーございました!

    • ばこ より:

      おおー!初のゲーム完成おめでとうございます!^^
      この講座作った甲斐がありました。コメントもいただけてとてもうれしいです。
      ちょうどunityゲームジャムも始まりましたもんね!
      おこめさんの作るゲーム楽しみにしてます。
      次回作の講座ももうすぐ出来上がるのでまた読んでやってください(*’ω’*)

  3. bananan より:

    講座ありがとうございました!

    3週間くらいかけてじっくり読み込みながら作りました
    プログラムの書きかたがとても分かりやすく
    挫折せずに開発まで作りあげるが出来ました

    せっかく作ったので、忘れないうちにオリジナルのタワーディフェンス製作を
    やってみたいと思います!!
    目指せ! Kingdom Rush 超え!!(大きく出たな

    この講座がなければやってみようと思いませんでした
    本当に分かりやすい講座でした
    ありがとうございます!!

    • ばこ より:

      うれしいコメントありがとうございます!^^

      最後まで挫折せずに作れたとのことで講座制作者冥利に尽きます!
      プログラムの書き方なども今後もさらにブラッシュアップさせながら講座制作続けていきます。

      ぜひオリジナルゲーム完成まで進めていただければと思います。
      ゲーム完成したらまたコメント欄などでいつでも教えてくださいね!

      こちらこそ最後まで読んでいただき、実際に手を動かして作っていただきありがとうございました!
      いただいた声を励みにこれからもいろんなゲームプログラミング講座作っていきます!

  4. TETSU より:

    最後まで行くことは出来ましたが、敵が弓矢の射程に入ったら弓矢が飛んでいく矢ごと消えてしまいます。VECTOR3 position関連なのでで三次元座標の値がおかしいのだと思いますが講座通りにプログラムを打ち込んでるのに治らないので、解決方法を教えていただけると幸いです。よろしくお願いします

  5. Unity入門の森 より:

    既に完成させている方も出てきてますし、ちゃんと作ればそうはならないはずですね。

    TETSUさんのコードがどこか間違えてるんでしょうね。
    デバッグもゲームプログラミングにつきものですからね。
    コードやUnityのオブジェクトへのアタッチの過程にミスがないか確認してやってみてください。
    ファイトです!

  6. シモン より:

    C#、Unityの初学者です。
    ばこさんのtwitterを拝見し、こちらの講座を受講して最後まで完成させる事ができました!
    自分のPC上でゲームが遊べる事に感動しました。本当にありがとうございます。

    1点、疑問がありまして、タワーディフェンスの挙動でよく見る「一番ゴールに近い敵を優先で狙う」方法についてです。

    OverlapCircleのLayerMask.GetMask(“Enemy”)取得時に「自分の総合移動値」などをEnemyに持たせておいて条件を付ける事ができれば、やりたい事が可能かな…と想像してしたのですが、実現する方法が分からず、質問させて頂きました。
    よく見る挙動ですし、何かお決まりのプログラムでもあるのでしょうか…?

    長文失礼しました。
    他の講義も受講させて頂きます!

    • すずきかつーき より:

      タワーディフェンス制作講座を担当したすずきかつーきと申します。完成おめでとうございます!

      一番ゴールに近い敵を優先で狙う
      なるほど、確かによくある処理ですね。 そこは丁寧に作ると非常に難解になってしまうので、あえて雑にしてある箇所でした。
      色々な方法がありますが、まず現状の Physics2D.OverlapCircle では、範囲内のEnemyの「どれか」しか返却しないため、実際に複数のEnemyが範囲内に居た場合、どのEnemyを狙うのかはランダムになってしまっています
      (厳密にはUnity内部のルールに従っているとは思いますが)
      それを解消するには、まず Physics2D.OverlapCircle の使用をやめて、代わりに Physics2D.OverlapCircleAll を使う必要があります。
      こちらのメソッドは、範囲内のオブジェクト(正確にはCollider2D)「すべて」を配列にして返却してくれるため、そこからおっしゃる通り「最も移動距離が長いEnemy」を一つ取得するのは良い手だと思います。
      ただ、Enemyスクリプトのデータを扱いたい場合はGetComponent() などして、Collider2DからEnemyを取得する必要が出てきますので注意してください。
      コメント欄に書ききれないのであまり具体的な事が書けなくて申し訳ないですが、頑張ってみてください!!

      • シモン より:

        ご返答ありがとうございます!
        なるほど~ Physics2D.OverlapCircleAllといったメソッドがあるのですね
        こちらをヒントに思った挙動に改造できるか試してみます!

        ありがとうございました。

  7. TDまにあ より:

    なんとか最後まで作れました!
    とても勉強になる講座をありがとうございます。これからじっくり復習していきます!

    よろしければ、今後は『キャラクターにスキルを実装する』や『配置するキャラクターを選択できるようにする』といった機能を学べるとありがたいです。
    中・上級編の講座がでたらまた購入いたしますので、ご検討お願いします。

    • ばこ@Unity入門の森 より:

      最後まで講座取り組んでいただき、またコメントいただきありがとうございます!
      なるほど!
      『キャラクターにスキルを実装する』、
      『配置するキャラクターを選択できるようにする』といった機能
      ↑これら、タワーディフェンスではないですが、次回作のSRPG講座で同種の機能を実装する方法を掲載予定です(まだ執筆中なので必ずしもご希望のものになってるかはわからないですが)。

      今執筆中のものなどがある程度まとまったら初心者向け講座のブースターパックみたいなのを書いてみるのも面白そうだなと思いました。
      ご意見ありがとうございます!

  8. キュゥチャレ より:

    一昨日にこのサイトが気になって購入してしまいました。
    非常に丁寧な説明でわかりやすいですね。
    完成まで「なるほど、そうゆうことか!!」と疑問を残すことなく気持ちのいい講座でした。
    すぐに忘れてしまうので復習のため、また最初から読み直しますね。
    このサイトはすごく気に入りました。
    他の講座もやらせていただこうかと思います

    • Unity入門の森 より:

      嬉しいコメント&講座購入&お褒めの言葉ありがとうございます!
      気に入っていただけてよかったです^^
      まだまだ至らぬところも多いので今後とも精進してまいります。
      他講座も気に入っていただければ幸いです。

  9. たなち より:

    以前、こちらの講座で学んだ内容を応用して、クオリティはともかく、ようやくオリジナルゲームを1本リリースできました。作ったのはアクションゲームですが、ループ処理の実装方法や武器のレベルアップ処理など、多くの要素について、こちらの講座内容を応用させていただきました。アクション講座とSRPG講座は購入しておりますので、次回はこちらの内容も活かしつつ
    スマホアプリのリリース目指します。今後とも、よろしくお願いします。

    • ばこ@Unity入門の森 より:

      おおー!完成&リリースおめでとうございます!
      Unity入門の森の講座が実際にリリースされたゲームに役立ったとのこと、とても嬉しいです^^
      報告いただきありがとうございました。
      スマホアプリ化に関してもアクションゲーム講座やSRPG講座が役立つかと思います。
      こちらこそ今後ともよろしくお願いいたします!

  10. あさぼん より:

    講座を購入させていただき、完成させることができました。
    とても丁寧な説明でわかりやすく、大変参考になりました。

    一点、まだ理解できていないところがあり、完成したゲームでは、
    「Gameビュー」上は問題なくゲーム画面が表示されているのですが
    「Sceneビュー」ではGameFieldに対してCanvasが非常に大きく配置されています。

    1. わざとこのように配置したのか
    2. なぜこうなっているのにGameビューでは問題ないのか

    が気になっています。

    また、このくらいの規模のゲームでもきちんと「設計」しないとゲームを
    完成させるのは難しいんだな、と感じました。ですが、実際にどんな設計書を
    書けばいいのかまではイメージできておらず、何か参考情報でも教えて
    いただけますと幸いです。

    今後も他の講座も購入させていただきながら勉強していこうと思っています。
    よろしくお願いいたします。

    • Unity入門の森 より:

      講座購入&完成報告ありがとうございます!
      ゲーム完成したときはとても嬉しいですよね。
      解説もお褒めいただきありがとうございます。

      Canvasの大きさに関してはCanvasのRender ModeのScreen SpaceをOverlayからCameraに変更すればちょうど良いサイズに変更されます。
      手順に関してタワーディフェンスゲームの作り方講座の第2回目の記事に追記しました。
      詳しい解説は別講座の「クリッカーゲームの作り方講座」の第2回にあるので読んでみてください。
      https://feynman.co.jp/unityforest/game-create-lesson/clicker-game/making-ui-create-sheep/

      ゲームの設計に関しては難しいところですね。
      設計に関しては自分もまだまだといった感じですしプロの方も日々開発物に応じて良い形を模索してる印象があります。
      ゲームの場合、最初は小さな遊びの体験を作り、そこから肉付けしていく形で行うのが最初は良いと思います。
      慣れてきたら最初からある程度複雑なゲームシステムも作れるかもしれませんが、
      まずはどんな遊びを作りたいかを考えていくと良いのかなと。
      設計に閉じた本ではないですが、ゲームを形にする上でおすすめの書籍としては、
      「気持ちいい」から考えるゲームアイデア講座が良かったです。
      また、ゲームに限らず一般的なプログラミングを行う際の設計であればUMLモデリングの本などを見てみるのも良いかもしれません。

      • あさぼん より:

        ご返信ありがとうございました。
        追記と別講座や書籍のご紹介ありがとうございました。後ほど確認させていただきます。

        設計に関しては日々良い形の模索をしていこうと思います。
        今後ともよろしくお願いいたします。

  11. とーう より:

    なんとか最後まで作ることができました!!
    丁寧でわかりやすい講座でした。
    ありがとうございます。

  12. より:

    これは、本当はGAME_PLAY状態の時だけ敵を生成しないようにしなければいけないところで

    ここは生成するようにの誤字なのではないですか

    • Unity入門の森 より:

      コメントありがとうございます!
      “生成するようにしなければいけない”
      が正しいですね。訂正しておきました!

  13. ゴリィ より:

    最新版のunityでも完成できました!
    途中何回か検索したり、ユニティ側のUIが違うため試行錯誤ありましたが何とか出来ました!
    そのままリリースはしたくないのでアレンジしてリリース目指してみます。

    完全初心者向けではなく、一度無料でも何か学習した方向けかもしれないですね。特に困ったときは自分で検索して自分で解決するという学習法が無いと厳しいかなと思いました。
    ありがとうございました。
    他の講座も受けるかもしれないです。よろしくお願いいたします。

  14. みかんばこ より:

    本講座学習中のUnity、C#初心者です。

    EnemyManagerUIの作成 の箇所ですが、
    内容通りにEnemyManagerUI、EnemyManagerスクリプトともに修正し、
    EnemyManagerUIのインスペクター上でEnemyManager、Text(WAVE)、Text(GOLD)それぞれセットしてUIの動作確認しているのですが、動作はするもののエラーが出てしまいました。。

    エラー内容:
    NullReferenceException: Object reference not set to an instance of an object
    EnemyManagerUI.Update () (at Assets/Scripts/EnemyManagerUI.cs:14)

    UIの動作はウェーブ数も表示され、敵の数の表示の方も
    敵オブジェクトを倒したり、ゴールされて敵オブジェクトが消えることで
    正しい値が表示はされており、UIの動作に問題自体はなさそうなのですが。。
    EnemyManagerUI、EnemyManagerスクリプトのコード等の見直しをしても
    改善点がよくわからず、このまま次の項目を学習しても良いか分からない状態です。

    恐縮ですが、ご助言をいただけますでしょうか。。
    何卒よろしくお願いいたします。

    • Unity入門の森 より:

      エラーの原因は、NullReferenceExceptionが示している通り、どこかの参照がnullになっていることです。NullReferenceExceptionはアタッチミスなどで値やオブジェクトが入っているべきところに入っていないと出てくるエラーです。
      エラーはEnemyManagerUI.Update()の14行目で発生しているとのことですが、該当するコードがwaveText.textやenemyText.textを更新する部分です。

      以下の手順に従って、問題の原因を特定し、解決策を探りましょう。

      1. インスペクターの確認
      まずは、インスペクター上で必要な参照が正しく設定されていることを確認します。

      EnemyManagerUIスクリプトをアタッチしているGameObjectを選択します。
      EnemyManagerフィールドに正しいEnemyManagerオブジェクトが設定されていることを確認します。
      waveTextフィールドとenemyTextフィールドに正しいTextオブジェクトが設定されていることを確認します。

      public class EnemyManagerUI : MonoBehaviour
      {
      public EnemyManager enemyManager;
      public Text waveText;
      public Text enemyText;

      void Update()
      {
      if (enemyManager == null)
      {
      Debug.LogError(“EnemyManager is not set in the Inspector”);
      return;
      }

      if (waveText == null)
      {
      Debug.LogError(“WaveText is not set in the Inspector”);
      return;
      }

      if (enemyText == null)
      {
      Debug.LogError(“EnemyText is not set in the Inspector”);
      return;
      }

      waveText.text = $”WAVE:{enemyManager.wave + 1}/{enemyManager.waves.Length}”;
      enemyText.text = $”ENEMY:{enemyManager.EnemyCnt}”;
      }
      }

      このスクリプトを保存して再度実行し、コンソールに表示されるログを確認してください。エラーメッセージが表示された場合、そのフィールドがnullであることがわかります。

      3. スクリプトの確認
      EnemyManagerクラスが正しく設定されているか確認します。特に、waveとwaves、およびEnemyCntプロパティが存在し、正しく初期化されていることを確認してみてください。

      • みかんばこ より:

        EnemyManagerUIの作成に関するご助言、誠にありがとうございます。

        EnemyManagerUIのスクリプトがアタッチしているオブジェクトの方で、
        設定ミスがあったことを確認できました。
        初歩的なミスでした・・大変申し訳ございません。

        ゲームの作成完了後、本講座全体の流れの復習も兼ねて、
        本講座をベースに再度ゲームを作成してみます!

  15. すらい より:

    やっと10章全部完了してキッチリ動きました!

    が、9章10章あたりのC#で何を書いているか分からなくなってきたので
    今のこのある程度分かった状態で、もう一回第一章から同じ手順を追いかけつつ
    Unity C#プログラミング入門講座も触りながら勉強を続けます。

    ありがとうございます。引き続きもうちょっと頑張ります!

タイトルとURLをコピーしました