この講座はハクスラローグライク×デッキ構築型カードバトルRPG「呪術迷宮」の作り方講座の第8回です。
前回の記事ではカード効果のUI反映、そしてシングルトンを用いたカードデータ管理のためのマネージャーシステムと日英ローカライズ機能を実装しました。
前回の記事:
今回は前回作成したシングルトンによるデータ管理のシステムを拡張してプレイヤーのデッキデータを管理する機能を作成します。
記事の後半ではこれから戦闘処理を実装していくにあたって必要になる敵キャラクターAIパラメータや行動データも設定していきます。
デッキ管理スクリプトを作成
Dataクラスを直接拡張してデッキ管理の機能を付けても良いですが、機能を分割する為に新しくPlayerDeckDataクラスを作成します。(Scripts/Commonフォルダ以下がおすすめです)
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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// プレイヤ側デッキ・所持カード管理クラス /// </summary> public class PlayerDeckData : MonoBehaviour { // 各種設定データ(Inspectorからセット) public List<CardDataSO> allPlayerCardsList; // プレイヤー側カード全部のリスト public List<CardDataSO> playerInitialDeck; // プレイヤー側初期デッキカードリスト // プレイヤー側全カードデータと通し番号を紐づけたDictionary public static Dictionary<int, CardDataSO> CardDatasBySerialNum; // 現在のプレイヤーデッキデータ(通し番号で管理) public static List<int> deckCardList; // 初期化処理 public void Init () { // プレイヤー側全カードデータと通し番号を紐づける CardDatasBySerialNum = new Dictionary<int, CardDataSO> (); foreach (var item in allPlayerCardsList) { CardDatasBySerialNum.Add (item.serialNum, item); } } /// <summary> /// ゲーム初回起動時の初期デッキを設定する /// </summary> public void DataInitialize () { // プレイヤーの現在デッキデータに初期デッキ設定を反映 deckCardList = new List<int> (); foreach (var cardData in playerInitialDeck) { AddCardToDeck (cardData.serialNum); } } /// <summary> /// デッキにカードを1枚追加する /// </summary> /// <param name="cardSerialNum">カードの通し番号</param> public static void AddCardToDeck (int cardSerialNum) { deckCardList.Add (cardSerialNum); deckCardList.Sort (); } } |
プレイヤーの初期デッキ、および現在設定中のデッキデータを管理します。Dataクラス同様にDetaManagerオブジェクトにアタッチして使用します。
まずはInspectorから初期デッキを表すplayerInitialDeckパラメータに対してカード設定ファイルをドラッグ&ドロップします。これにより初期データ(ゲーム起動時)でのプレイヤーデッキを作成します。何でも良いので適当なカードを合計10枚以上指定しておきます。
(上記の登録カードは一例です。6章で同じカードを作ってないですが気にしないでください)
今回の設計ではデッキに組み込んだカードのデータをint型のIDで管理しています。このIDは各カードの設定ファイル(CardDataSO)に入力した通し番号(serialNum)と同一です。
複数のデータを持っているCardDataSOファイルそのものでなくIDで管理する事によって今後の拡張の際に取り扱いやすくなります。
ただしIDだけで管理する場合は当然そのIDから該当のカードデータを取得できる機能を用意する必要があります。そのため、allPlayerCardsListパラメータを追加し、ここにプレイヤーが使用する全てのカードをまとめて登録します。IDとカードデータの紐づけをDictionary型であるCardDatasBySerialNumで記憶しておきます。
また、ここでプレイヤーが保有している全てのカードをallPlayerCardsListに登録します。
Inspectorからの操作でallPlayerCardsListに全プレイヤーカードを登録しますが、ファイルの1つ1つを順番にドラッグ&ドロップしているととても時間がかかってしまいます。まとめて操作する方法も学んでおきましょう。
Projectビューでの複数ファイルの同時選択自体はShiftキーを押しながらクリックまたは矢印キーの入力で可能です。又はCtrl+Aキーを押す事で開いているフォルダ内の全部のファイルが選択状態になります。
しかし複数のファイルを同時選択するとInspectorビューでの表示が切り替わってしまい先ほどのPlayerDeckDataコンポーネントに対してドラッグ&ドロップ操作が出来ません。
この切り替わりを防ぐ方法としてInspectorビューのロック機能があります。事前にDataManagerオブジェクトを選択しておき、Inspectorビュー右上の鍵マークのアイコンをクリックするとロック状態になり、他のファイルやオブジェクトなどを選択してもInspectorビューが切り替わらなくなります。
この状態でPlayerCardsフォルダ内のカードデータファイル全てをallPlayerCardsListにドラッグ&ドロップすれば完了です。
操作後は忘れずにInspectorのロックを解除しておきましょう。気づかずにロックしたままだと誤操作の原因になりやすいです。
なお、「敵が使用するカード全部のリスト」は用意しなくても大丈夫です。敵のデータを設定する際には使用するカードを直接それぞれの敵に対して指定するのでIDで管理する必要はありません。
PlayerDeckDataクラスは今後デッキ編集画面を作成した時に拡張を行う予定です。
Dataクラスからの参照をセット
他のクラスからPlayerDeckDataクラスにアクセスできるようにDataクラス内で参照を用意しておきます。
Data.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 62 63 64 65 66 67 68 69 70 71 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// (DataManagerオブジェクトにアタッチ) /// データマネージャー /// ゲーム起動中常に同じインスタンス(オブジェクト)が1つ存在している /// </summary> public class Data : MonoBehaviour { #region シングルトン維持用処理(変更不要) // シングルトン維持用 public static Data instance; // Awake(Startより前に1度だけ実行) private void Awake () { // シングルトン用処理 if (instance != null) { Destroy (gameObject); return; } instance = this; DontDestroyOnLoad (gameObject); // ゲーム起動時処理 InitialProcess (); } #endregion // 各種コンポーネント public PlayerDeckData playerDeckData; // デッキ管理クラス // シーン間保存データ public static SystemLanguage nowLanguage; // 現在の設定言語 /// <summary> /// ゲーム開始時(インスタンス生成時)に一度だけ実行される処理 /// </summary> private void InitialProcess () { // 乱数シード値初期化 Random.InitState (System.DateTime.Now.Millisecond); // 実行環境の言語設定を取得する nowLanguage = GetLanguageData (); //nowLanguage = SystemLanguage.English; // (テスト用)英語設定に変更する // プレイヤーデッキデータ初期化処理 playerDeckData.Init (); // プレイヤー所持カードデータ初期化(セーブ機能実装後は別のタイミングで呼び出し) playerDeckData.DataInitialize (); } /// <summary> /// 実行環境の言語設定を取得して返す /// </summary> /// <returns>言語データ</returns> private SystemLanguage GetLanguageData () { // 実行環境の言語設定を取得 var language = Application.systemLanguage; // 日本語以外の言語だった場合全て英語で対応する if (language != SystemLanguage.Japanese) language = SystemLanguage.English; return language; } } |
DataManagerオブジェクトのDataコンポーネントにDataManagerオブジェクト自身をアタッチしておきます。
FieldManagerクラスでの現在デッキ管理
FieldManager内にて戦闘中に使用するデッキ(山札)の状態を管理し、ドロー操作によってデッキの中からカードが引かれていく処理を追加します。
PlayerDeckDataクラス内ではプレイヤーの現在のデッキ設定をdeckCardList変数内に(通し番号で)格納していますがこれは「戦闘開始時の初期デッキ」として扱います。
戦闘中にデッキからカードを引く時はFieldManager内に用意する「現在デッキデータ」から引いていきます。このゲームが戦闘ごとに手札や山札の状態がリセットされるルールになっている為です。
まとめ
今回はDataクラスを拡張してデッキ管理の機能を追加しました。今後もセーブ&ロードが絡んでくる機能や全シーンで共通になる機能はDataクラスを拡張して実装していきます。
そしてプレイヤーのデッキを参照して戦闘開始時に山札を用意し、そこからカードをドローするという最初の流れを実装しました。Random.Rangeを使えば任意の範囲内の数値をランダムに得ることができます。
次回はさらに戦闘画面を充実させるための開発に踏み込んでいきます。
今回はその準備として敵キャラクターのデータ準備までを行いました。ひとまず1体分のデータだけ作っておけば動作確認可能です。
次の記事:
コメント