この記事はUnityでハクスラローグライク×デッキ構築型カードバトルRPG「呪術迷宮」を作る講座の第20回です。
前回はバトル時にカード効果をわかりやすく表示するためのウィンドウシステムを実装しました。
前回の記事:
今回はリリース時のゲームをより長く楽しんでもらうための一つの方法として無限のダンジョン階層を実現する方法を解説します。
次に、長期戦になった際にデッキからカードを引けなくなる可能性があります。こうした場合のデッキ補充システムも実装します。
最後にデッキからカードを捨てる機能も併せて実装します。
Unityで無限ダンジョンステージを実装する
ゲームのやり込み性を向上させるために新たなシステムの実装を行います。
11章にてステージデータの定義を行いましたが、現状では全て「複数回の戦闘で生き残ればステージクリア」という設定になっています。
これでは最後のステージをクリアできる程強くなった後は目標が無くなってしまいます。
最後のステージをとてつもなく難しくしても良いのですが、今回は無限にステージ攻略が続いていく「無限ステージシステム」の実装を行ってみます。
ステージデータ(StageSO)設定
ステージデータを設定する際、無限ステージの設定に拡張できるよう修正していきます。
StageSO.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// ステージデータ定義クラス /// </summary> [CreateAssetMenu (fileName = "StageSO", menuName = " ScriptableObjects/StageSO")] public class StageSO : ScriptableObject { [Header ("ステージ名(日本語)")] public string name_JP; [Header ("ステージ名(英語)")] public string name_EN; [Space (10)] [Header ("難易度表示(日本語)")] public string difficulty_JP; [Header ("難易度表示(英語)")] public string difficulty_EN; [Space (10)] [Header ("ステージアイコン画像")] public Sprite stageIcon; [Header ("ステージ背景画像")] public Sprite stagePicture; [Space (10)] [Header ("各進行度別の敵の出現テーブル(通常ステージのみ)")] public List<appearEnemyTable> appearEnemyTables; [Space (10)] [Header ("戦闘報酬:経験値獲得量係数")] public int bonus_EXP; [Header ("戦闘報酬:金貨獲得量係数")] public int bonus_Gold; [Header ("戦闘報酬:体力回復量(固定)")] public int bonus_Heal; [Space (10)] [Header ("無限ステージモード")] public bool infinityMode; [Header ("無限ステージ用:出現ザコ敵リスト")] public List<EnemyStatusSO> infinity_EnemyDatas; [Header ("無限ステージ用:出現ボス敵リスト")] public List<EnemyStatusSO> infinity_BossDatas; [Header ("無限ステージ用:ボス敵出現間隔")] public int bossDistance; [Header ("無限ステージ用:敵HP増加量")] public int enemyHPIncrease; } /// <summary> /// 各進行度別の敵の出現テーブルクラス /// </summary> [System.Serializable] public class appearEnemyTable { // 敵出現テーブル(1体のみの指定でボス敵扱いにする) public List<EnemyStatusSO> appearEnemys; } |
infinityModeをONにしたステージだけ無限ステージとして扱うようにします。無限ステージの場合、進行度別の敵テーブルを格納するappearEnemyTablesパラメータは無視されます(よって設定不要)。
infinity_EnemyDatasリストにザコ敵データ、infinity_BossDatasリストのボス敵データをそれぞれ任意の個数格納していきます。進行度とは関係なく常に出現する敵はランダムに抽選されます。
ザコ敵をbossDistanceで決められた回数分倒すと次の敵はボス敵となります。
ステージ攻略に伴って少しずつ難易度を上げていくために、進行度が1進む度にenemyHPIncreaseで設定した分だけ敵最大HPが上昇していきます。
以上の設定を任意のStageSOファイルに行ってみましょう。
無限ステージスクリプト
スクリプトを拡張して無限ステージモードに対応できるようにしていきます。
CharacterManager.cs内 SpawnEnemyメソッド
まずは「ステージが進むごとに敵の最大HPが上がる」という仕様を満たすため、敵出現時の処理から変更します。
カードタップによって強制的にカード効果の発動が開始され、デッキ枚数回復とともに残りHPが半減します。
カードを捨てるシステムの実装
フィールドエリア左下にはトラッシュゾーンが存在します。これは戦闘中に不要となったカードを処分するための場所です。
手札の枚数を減らしておくことで次のターン開始時により多くの新しいカードを引けるようにするという戦術を可能にするシステムです。ここまで未実装でしたので併せて実装しておきましょう。
処分されるカードの動作は既にCardクラス内でHideMoveTweenというメソッドを用意しているのでこれを使います。
カードの処分を開始するタイミングは効果発動ボタンを押した時なので、FieldManagerのCardPlayButtonメソッドから追加メソッドを呼び出すようにします。
FieldManager.cs内 新規メソッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
/// <summary> /// トラッシュゾーン内にある全カードを画面外に退避・消去する /// </summary> private void DeleteCardsOnTrashArea () { var deleteSequence = DOTween.Sequence (); // 退避・消去演出Sequence var trashCard = new List<Card> (); // 消去対象カードリスト // トラッシュゾーン内カードリストを作成 foreach (var instance in cardInstances) { // トラッシュゾーンにあるカードをリストに追加 if (instance.nowZone == CardZone.ZoneType.Trash) trashCard.Add (instance); } // 消去対象カードリストをシーン内での表示順で並び替えする trashCard.Sort ((a, b) => b.transform.GetSiblingIndex () - a.transform.GetSiblingIndex ()); // トラッシュゾーン内カードを順番に画面外に退避 foreach (var card in trashCard) { deleteSequence.AppendCallback (card.HideMoveTween); deleteSequence.AppendInterval (0.4f); } // トラッシュゾーン内カードを消去 deleteSequence.OnComplete (() => { foreach (var card in trashCard) { DestroyCardObject (card); } }); } |
トラッシュゾーンに置かれている全てのカードをリスト化し、それらを順番に画面外へ退避させる演出を行ってからまとめてオブジェクト消去するという流れです。
退避演出を呼び出す時、ゾーン内に複数のカードが置かれている場合は上に積まれているカードから順番に演出開始するようにしています。
その為にゾーン内カードリストを、Sceneビューでのオブジェクトの並び順と同じになるようにSortで並べ替えをしています。
同じ親をもつオブジェクト間の並び順はTransform.GetSiblingIndexメソッドで取得する事が出来るので、これをSortの条件に指定しています。
このメソッドを効果発動のタイミングで呼び出すようにします。
FieldManager.cs内 CardPlayButtonメソッド
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/// <summary> /// カード効果発動ボタン押下時処理 /// </summary> public void CardPlayButton () { // カードドラッグ中なら処理しない if (draggingCard != null) return; // 実行ボタンを一時的に無効化 cardPlayButton.interactable = false; // 効果実行処理中フラグ isCardPlaying = true; // プレイボード上カードの配列を作成 Card[] boardCards = new Card[PlayBoardManager.PlayBoardCardNum]; // プレイボード上のカードを取得して配列に格納 foreach (var card in cardInstances) { // 配列内の指定の位置に該当カードを格納する if (card.nowZone >= CardZone.ZoneType.PlayBoard0 && card.nowZone <= CardZone.ZoneType.PlayBoard4) { int arrayID = (int)card.nowZone - (int)CardZone.ZoneType.PlayBoard0; boardCards[arrayID] = card; } } // 各カードの効果を実行 battleManager.playBoardManager.BoardCardsPlay (boardCards); // トラッシュゾーン内カードの消去処理 DeleteCardsOnTrashArea (); } |
これでトラッシュゾーンのシステムが実装できました。
まとめ
今回はカードゲームのやりこみ性を向上させるための工夫を多数行いました。
無限階層まで遊べるゲームの作り方に関してはカードゲーム以外でも応用できるテクニックなのでぜひ習得してもらえたらと思います。
また、ゲームの難易度に関わらず、ユーザーインターフェースはなるべく親切に設計してあげると誰が遊んでも楽しみやすいゲームになります。
次章は重要なセーブ&ロードのシステムとサウンドを実装し、このゲームを完成させていきましょう!
次の記事:
コメント