シンプルなタワーディフェンスゲームを作る part12
こちらのようなシンプルなタワーディフェンスゲームを作っています。本記事では「Data Table」を使って、下の動画のように「敵ユニット」の出現数や種類を制御することでタワーディフェンスゲームのウェーブ設計を行えるようにします。
コンセプト
以下のような形でウェーブデータテーブルの設計を行います。
必要な情報としては、今どの「Stage」で何「Wave」目か?またその「Wave」においてどの「敵ユニット」を何体どれくらいの間隔で、どの「敵スポナー」から出現させるのか?といったものを定義します。
「敵ユニット」のバリエーションを増やす
どの「敵ユニット」を出現させたかを分かりやすくするために「敵ユニット」のバリエーションを増やします。
「Enemy」フォルダを開きます。「Enemy」フォルダの下に「Enemy Variations」というフォルダを作ります。ここに「敵ユニット」のバリエーションを入れていきます。
「Enemy Variations」フォルダ内で右クリック→「ブループリントクラス」を選択し、継承するブループリントクラスとして「BP_Enemy」を指定します。
下図のように「すべてのクラス」から「BP_Enemy」を検索して選択します。
「BP_Enemy」を継承したブループリントを二つ作成し、一つ目を「BP_Enemy1」二つ目を「BP_Enemy2」という名称にします。
「BP_Enemy1」を開きます。
こちらは足が遅いユニットにしたいと思います。
コンポーネントで「BP_Enemy1(Self)」を選択した状態で右の詳細パネルの「Max Walk Speed」を100cm/sにします。
「BP_Enemy2」を開きます。
こちらは足は速い代わりに体力の低いユニットとし、少し色を変更します。
単色のマテリアル「M_Enemy2」を作成します。このマテリアルは少し濃い赤色にしておきます。
単色のマテリアルの作り方はこちらを参照ください。
コンポーネントで「SM_Enemy」を選択し、マテリアルに「M_Enemy2」を割り当てます。
コンポーネントで「BP_Enemy2(Self)」を選択した状態で右の詳細パネルの「デフォルト」/「Max Health」を50に設定、「money」を60に設定します。
また「Max Walk Speed」を200cm/sにしておきます。
構造体を使ってウェーブ情報を作る
ウェーブ情報を表現する構造体を作ります。
まずウェーブ関係の部品を入れるための「wave_manager」というフォルダを作成します。
フォルダ内で右クリック→「ブループリント」→「構造体」を選択し、名称を「ST_wave」とします。
「ST_wave」を開きます。
左上の「変数を追加」から変数を追加することが出来るので以下のような変数を並べます。
- Name型:stage_name(ステージ名)
- Integer型:wave_number(何ウェーブ目か)
- BP_Enemy型:Enemy_class(どの敵ユニットを出現させるか)
- Integer型:enemy_count(何体出現させるか)
- Float型:spawn_frequency(何秒間隔で出現させるか)
- Integer型:spawner_number(どのスポナーから出現させるか)
ウェーブ情報を表すデータテーブルを作る
次にウェーブ情報を表すデータテーブルを作ります。
「wave_manager」フォルダで右クリック→「その他」→「データテーブル」を選択します。「行構造を選択」というポップアップが出るので「ST_wave」を選択しOKボタンを押します。
作成したデータテーブルは「DT_wave」という名称にします。
「DT_wave」を開きます。
左上の「追加」ボタンから新しい行を作ることが出来るので下図のように設定していきます。
- 1行目「mock_level」ステージの「1」wave目で「敵スポナー0」が「BP_Enemy1」を4体出現させる
- 2行目「mock_level」ステージの「1」wave目で「敵スポナー0」が「BP_Enemy2」を2体出現させる
- 3行目「mock_level」ステージの「1」wave目で「敵スポナー1」が「BP_Enemy1」を2体出現させる
- 4行目「mock_level」ステージの「1」wave目で「敵スポナー1」が「BP_Enemy2」を1体出現させる
データテーブルに従いウェーブを管理する
データテーブルに従いウェーブを管理するオブジェクトとして「ウェーブマネージャー」というものを作り、「ウェーブマネージャー」がデータテーブルを読んで、各「敵スポナー」に何を何体出現させるように指示を出すような仕組みにします。
「wave_manager」フォルダ内で右クリック→「ブループリントクラス」→「Pawn」を選択して新しいブループリントを作成し、名称を「BP_wave_manager」とします。
「BP_wave_manager」を開き、イベントグラフに移動します。
BP_enemy_spawner型の配列変数「enemy_spawner」を作ります。
「Event BeginPlay」に「Get All Actors Of Class」を追加「Actor Class」に「BP_Enemy_Spawner」を割り当て、変数「enemy_spawner」に代入します。
「Event BeginPlay」の続きに、「現在のステージのwave情報を取得する」処理を作ります。
ST_wave配列型変数の「ST_wave_in_stage」を作成します。
「Get Current Level Name」を作り、その続きに「Get Data Table Row Names」、「Table」ピンに「DT_wave」を割り当てます。
「For each Loop」で「Get Data Table Row Names」の出力ピン毎にループさせます。
「loop body」の次に「Get Data Table Row」ノードを追加、「Data Table」ピンに「DT_wave」を割り当て、「Row Name」に「For each Loop」の「Array Element」を繋ぎます。
「Break ST_wave」から「stage_name」を抜き出し、「Current Level Name」と一致するか判定します。
一致する場合「ST_wave_in_stage」に追加(配列 add)します。
「Add Custom Event」で新規イベントを作成し、名称を「call_next_wave」とします。
「現在のステージのwave情報を取得する」処理のループ完了後「call_next_wave」を呼ぶようにします。
いったん「BP_enemy_spawner」に移ります。
「Add Custom Event」で新規イベントを作成し名称を「set_wave」とします。
「set_wave」にインプットを追加し、ST_wave配列型の変数「wave」を作成します。
「BP_wave_manager」に戻り、「call_next_wave」の続きを書いていきます。
ST_wave配列型変数の「ST_wave_at_spawner」、Integer型の「wave_count」を作成します。
「call_next_wave」の初めに「wave_count」をインクリメント(++)します。
「enemy_spawner」で「for each loop」し、「loop body」で「ST_wave_at_spawner」をクリアします。その次に「ST_wave_in_stage」で「for each loop」し、「loop body」で「enemy_spawner」の「Array Index」と「ST_wave」の「spawner_number」が一致かつ、「wave_count」と「ST_wave」の「wave_number」が一致するか判定します。
一致する場合「ST_wave_at_spawner」に「Array Element」を追加します。
「ST_wave_in_stage」の「for each loop」が完了後、「ST_wave_at_spawner」が1つ以上存在するか判定し、Trueなら「enemy_spawner」の「for each loop」Index目の「enemy_spawner」の「set_wave」を呼び「wave」に「ST_wave_at_spawner」を接続します。
これで「wave_manager」から「enemy_spawner」に対して、今どの「wave」を作ればよいかを指示する処理を作成しました。
「BP_enemy_spawner」に移ります。
先ほど作成した「set_wave」の続きの処理を書いていきます。
ST_wave配列型変数の「wave」とInteger型の「wave_count」を作成します。
「Add Custom Event」で新規イベントを作成し名称を「make_wave」とします。
イベント「set_wave」の続きから、インプット「wave」を変数「wave」に代入し、「wave_count」を0に初期化し、「make_wave」を呼びます。
「make_wave」の続きに、前partで作成した一定間隔で「敵ユニット」を出現させる処理を繋ぎます。この時「Event BeginPlay」に繋がっていた処理は消しておきます。
「wave_count」番目の「wave」を取得し「Break ST_wave」で中身にアクセスします。「spawn_frequency」を取得し「Set Timer by Event」の「Time」に接続します。
前partで作成した一定間隔で「敵ユニット」を出現させる処理の次に「Delay」を追加し「Duration」に(「Enemy_count」+1)×「spawn_frequency」を計算した値を接続します。
続きを書きます。
「Delay」の続きに、「Clear and Invalidate Timer by Handle」ノードを追加し「Handle」ピンに「Set Timer by Event」の「Return Value」を接続します。
これにより、「Delay」後に「Set Timer by Event」を中断することが出来ます。
その後「wave_count」をインクリメントし、「wave_count」が「wave」の長さに収まるか判定、収まる場合はもう一度「make_wave」を呼びます。
「mock_level」のビューポートに移動します。
「BP_enemy_spawner」を二つと、「BP_wave_manager」を一つ配置します。
ここまで実装してゲームを実行すると、冒頭の動画のような振る舞いを確認することが出来ます。
コメント