この講座はハクスラローグライク×デッキ構築型カードバトルRPG「呪術迷宮」の作り方講座の第15回です。
前回はタイトル画面を作成し、ゲーム開始→ステージ選択→カードバトル→ゲームオーバーorゲームクリアという一連のカードバトルゲームの流れを完成させました。
前回の記事:
今回はカードゲームには欠かせない機能の一つ、デッキ編集システムを実装します。これによってプレイヤーは独自のデッキを用意してステージ攻略に挑めるようになります。
ローグライクカードゲームでは予めデッキを組んで進むゲームは少ないですが、呪術迷宮はデッキを作ってダンジョンに挑むタイプのゲームなのでこの機能は必須となります。
また、ローグライク形式に限らず、遊戯王やポケモンカードゲームのような通常の対戦型カードゲームでもこうしたデッキ編集・デッキ管理システムの実装は不可欠です。
ぜひ今回の講座でUnityにおけるデッキシステムの実装方法をマスターしていってください。
デッキ管理システムを作ろう
まずはプレイヤーのデッキを管理しているPlayerDeckDataクラスを拡張し、「デッキには入れていないけど所持しているカード」を保管中カードとして保持できるようにします。
PlayerDeckData.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 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
using System.Collections; using System.Collections.Generic; using System.Linq; 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 static Dictionary<int, int> storageCardList; // 初期化処理 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); } // 保管中カード情報クリア storageCardList = new Dictionary<int, int> (); foreach (var playerCard in allPlayerCardsList) { storageCardList.Add (playerCard.serialNum, 0); } // (デバッグ用)全部のカードを1枚ずつ保管中リストに加える List<int> keys = storageCardList.Keys.ToList(); // DictionaryのKeyのリストを作成(List<int>) for (int i = 0; i < storageCardList.Count; i++) { // Dictionaryの全てのKeyに対応するValueをそれぞれ1ずつ加算 storageCardList[keys[i]] += 1; } } /// <summary> /// デッキにカードを1枚追加する /// </summary> /// <param name="cardSerialNum">カードの通し番号</param> public static void AddCardToDeck (int cardSerialNum) { deckCardList.Add (cardSerialNum); deckCardList.Sort (); } /// <summary> /// デッキからカードを1枚削除する /// </summary> /// <param name="cardSerialNum">カードの通し番号</param> public static void RemoveCardFromDeck (int cardSerialNum) { deckCardList.Remove (cardSerialNum); } /// <summary> /// 保管中のカード数量を変更する /// </summary> /// <param name="cardSerialNum">カードの通し番号</param> /// <param name="amount">変更量(+で追加)</param> public static void ChangeStorageCardNum (int cardSerialNum, int amount) { storageCardList[cardSerialNum] += amount; } } |
- 当面の動作確認のためにDataInitializeメソッド内にて「全部のカードを1枚ずつ保管中カードとして入手する」処理を追加します。
これをもとに、保管中のカードをデッキ内に組み込んだり外したりという操作ができるデッキ編集ウィンドウを作成していきます。
デッキ編集ウィンドウの作成
DeckEditWindowオブジェクト
デッキ編集画面は情報量が多いので全画面に表示させます。画像UIとして作成しますがPanelでもOKです。(Panelで作成するとImageのcolorが半透明になるので修正してください)
- オブジェクト名:DeckEditWindow
- 親:GameWindow
- PosX:0 PosY:0
- Width:1080 Height:540
- (Image)Source Image:Textures/GUIs/DeckBackGround.png
ウィンドウを閉じるボタン
StageSelectWindow内のCloseButtonオブジェクトをコピー&ペーストします。
- オブジェクト名:CloseButton
- 親:DeckEditWindow
- PosX:492 PosY:220
保管中カードリスト:背景画像+ロゴText
デッキ編集ウィンドウの左側に保管中カードのリストを、右側に現在デッキに入っているカードのリストを表示するようにします。
まずは左側、保管中カードの表示欄であることを示す文字および文字背景画像を配置します。
背景画像
- オブジェクト名:LogoFrame_Storage
- 親:DeckEditWindow
- PosX:-290 PosY:205
- Width:232 Height:44
- (Image)Source Image:Textures/GUIs/deck_window_0.png(DeckWindow.pngを展開して選択)
ロゴText
UI > Legacy > Textで作成し、画像のように適宜パラメータを設定。
- オブジェクト名:LogoText
- 親:LogoFrame_Storage
- PosX:0 PosY:0
- Width:220 Height:40
- SimpleTranslationTextをアタッチ:(日本語)所持カード (英語)Storage
デッキカードリスト:背景画像+ロゴText
続いて右側にもこれを配置します。LogoFrame_Storageオブジェクトをコピー&ペーストして表示Textを変更します。
- オブジェクト名:LogoFrame_Deck
- 親:DeckEditWindow
- PosX:290 PosY:205
- 子のSimpleTranslationText:(日本語)デッキ (英語)Deck
なお、こちらのTextはデッキ内の枚数を表示する際にも使用するのでSimpleTranslationTextコンポーネントは外してもOKです。
デッキ操作ボタン2種類
画面左側に表示される保管中のカードをタップするとそれを選択状態にできる機能を作ります。
そのために選択したカードをデッキに入れるボタンを用意しておきましょう。
ボタンオブジェクトはStageSelectWindowのStartButtonなどからコピー&ペーストすると効率的です。
デッキに入れるボタン
- オブジェクト名:IntoDeckButton
- 親:DeckEditWindow
- PosX:-298 PosY:-210
- 子のSimpleTranslationText:(日本語)デッキに入れる (英語)Into deck
デッキから外すボタン
同様に選択中のデッキ内カードをデッキから外す(保管中リストに戻す)ボタンも用意しましょう。
- オブジェクト名:BackToStorageButton
- 親:DeckEditWindow
- PosX:298 PosY:-210
- 子のSimpleTranslationText:(日本語)デッキから外す (英語)Back to storage
保管中カードリストビュー
それでは保管中・デッキ内のカードをそれぞれリスト表示するための領域を作成していきます。
沢山のカードオブジェクトを並べて表示する事になるので、領域内をドラッグ操作によりスクロールできるようにします。
これでデッキ編集の操作を行えるようになりました。
更にこの状態でデッキ編集を終えてステージを開始すればステージ内でもデッキ内カードが変化している事も確認できます。
まとめ
「保管中カード」のデータを用意し、それをもとにデッキ内のカードを入れ替えできるシステムを実装しました。
デッキ編集・管理画面UIも整備し、これでステージ毎にデッキを変更してダンジョンを攻略するゲームシステムが出来上がりました。
現在はPlayerDeckDataクラス内のデバッグ用処理により常に全てのカードを1枚ずつ保管している状態になっていますが、ある程度開発が進んでバランス調整の段階に入ったらこの処理を削除すると良いでしょう。
次回はここで実装したシステムを活かし、ゲーム中に新たなカードを入手する処理を開発していきます。
敵を倒すと新しいカード・経験値・お金が手に入るようになります。強い敵を倒して得られる報酬を用意し、ワクワクする瞬間をプレイヤーに提供していきましょう。
次の記事:
コメント