この記事はUnityでハクスラローグライク×デッキ構築型カードバトルRPG「呪術迷宮」を作る講座の第22回目です。
前回までの記事で基本的なシステムは全て完成しましたが、さらにこのゲームを改良して遊びやすくしたいという方のために、改良の一例としてデッキ編集画面の機能を追加する流れを解説します。
前回の記事:
ここでは「デッキ編集画面でもカードの効果を確認できる」機能と「保管中カードリストを並び替えして表示する」機能の2つを説明します。
カードの表示機能を改良 選択したカード効果をデッキ編集中に表示させる
現状ではタイトル画面内のデッキ編集機能において各カード効果の説明は表示されていません。そのため、カードの効果がわからない場合は一度デッキに組み込んでステージに入る必要があります。
ユーザーが遊びやすくなるように、デッキ編集画面でも選択したカードの効果を確認できる機能を実装していきましょう。
ここではカードの詳細表示ボタンをまず用意x。そしてそのボタンを選択したときに画面左側にカードの拡大画像、右側にその効果説明を表示する実装を行います。
カード詳細関連オブジェクトを作成 UI画面項目の追加
TitleシーンのDeckEditWindow以下にオブジェクトを追加していきます。
DeckEditWindowオブジェクトが非表示(非アクティブ)になっている場合は有効化しておきましょう。
カード詳細表示開始ボタン
DeckEditWindow以下のIntoDeckButton(またはBackToStorageButton)オブジェクトをコピー&ペーストしてカードの詳細を表示するボタンを作成します。
- オブジェクト名:CardDetailButton
- 親:DeckEditWindow
- PosX:0 PosY:-210
- Width:192 Height:55
- (Image)Source Image:buttons_3.png
- (子オブジェクトのSimple Translation Text)日本語:詳 細 英語:Detail
詳細表示時の背景パネル
カードの詳細表示を行っている間、後ろのUIを暗くすることで「詳細表示を行っている状態である」ことをわかりやすくしていきます。
そのために画面全体を覆う黒色の半透明なPanelUIオブジェクトを作成しましょう。
- オブジェクト名:EffectExplainBackGround
- 親:DeckEditWindow
- PanelUIとして作成
- (Image)Color:黒の半透明
カード効果説明オブジェクトの複製
効果説明のシステムは戦闘画面にて作成したものを流用して使います。
まずはBattleシーンのEffectExplainDisplayオブジェクトをコピーし、Titleシーンに戻ってDeckEditWindowオブジェクト以下に丸ごと複製しましょう。
画面のレイアウトとして「左側に拡大したカードの画像を表示」、「右側に効果説明」という並びにしていきます。
EffectExplainDisplayオブジェクトは画面右側にずらしておきます。(PosXが200辺り)
拡大カードオブジェクトを表示させる
先ほど空けた左側のスペースに、詳細表示の対象になっているカードを拡大して表示させましょう。
まずはEffectExplainDisplayオブジェクト以下にCardプレハブをドラッグ&ドロップして生成します。すると以下のようになるはずです。
EffectExplainDisplayオブジェクトにVertical Layout Groupがアタッチされているので、子オブジェクトは全て縦に並べられてしまいます。
しかし今回のCardオブジェクトはEffectExplainDisplayの子に置きたいけれどもLayoutの設定を無視したいです。このような場合はLayout Elementコンポーネントを使用します。
Layout ElementにはIgnore Layoutというパラメータがありますが、これをオンにするとそのオブジェクトは親のLayout設定を無視するようになります。
それでは生成したCardオブジェクトにLayout Elementをアタッチし、Ignore Layoutをオンにしてみましょう。これで自由にオブジェクトの位置や大きさ等を変更できるようになるので、画面の左側に配置&Scale値を変更して拡大表示しましょう。
(Anchorsの設定が変わっているので指定する座標が普段とやや異なっています。今回の場合はPosXに-240、PosYに-200くらいで丁度よくなるはずです。)
Scaleのx,yを2にして拡大カードの表示が実現します。
詳細表示画面は画面のどこかをタップすれば閉じる仕様にするので、閉じるボタンの追加は不要です。
カード詳細表示システムを実装しよう
いくつかのスクリプトを編集した後にインスペクタから必要な参照をそれぞれセットし、詳細ボタンの動作を設定すれば完了します。
Card.cs内 新規メソッド
拡大カードオブジェクトの表示に対応できるようCardスクリプトから拡張していきます。
今回のカードオブジェクトは同じものを何度も使いまわすので、その度にアイコン等のUI表示をリセットする機能を追加します。
1 2 3 4 5 6 7 8 9 |
/// <summary> /// カードのアイコンと効果の表示をリセットする /// </summary> public void ClearIconsAndEffects () { iconSprites.Clear (); effects.Clear (); cardUI.ClearIconsAndEffects (); } |
EffectExplainDisplay.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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 複数のカード効果説明オブジェクトの管理クラス /// </summary> public class EffectExplainDisplay : MonoBehaviour { // 効果説明クラスリスト [SerializeField] private List<EffectExplainPart> partsList = null; // カード効果実行クラス [SerializeField] private PlayBoardManager playBoardManager = null; // (デッキ編集画面用)詳細説明時に表示するカード [SerializeField] private Card detailExplainCard = null; // 初期化処理(各呼び出し元クラスから実行) public void Init () { // 各効果説明クラスの初期化 foreach (var explainPart in partsList) { explainPart.Init (this); } // オブジェクトが非アクティブならアクティブに gameObject.SetActive (true); // 詳細時表示用カード初期化 if (detailExplainCard != null) { detailExplainCard.Init (null, detailExplainCard.rectTransform.position); detailExplainCard.gameObject.SetActive (false); } } /// <summary> /// 効果の説明を表示する /// </summary> /// <param name="effectDatas">効果データリスト</param> /// <param name="charaID">カード使用者のキャラクターID</param> public void ShowExplains (List<CardEffectDefine> effectDatas, int charaID) { // 表示処理 int listLength = partsList.Count; int effectNum = effectDatas.Count; // 効果数 for (int i = 0; i < listLength; i++) { // 効果データが存在する場合に表示 if (i < effectNum) partsList[i].ShowExplain (effectDatas[i], charaID); else partsList[i].HideExplain (); } } /// <summary> /// 効果の説明を表示する(カードデータを直接指定) /// </summary> public void ShowExplains (CardDataSO cardDataSO, int charaID) { // 詳細時表示用カード設定 if (detailExplainCard != null) { detailExplainCard.ClearIconsAndEffects (); detailExplainCard.SetInitialCardData (cardDataSO, charaID); detailExplainCard.gameObject.SetActive (true); } // 説明表示 ShowExplains (cardDataSO.effectList, charaID); } /// <summary> /// 状態異常の説明を表示する /// </summary> /// <param name="statusEffectType">状態異常の種類</param> /// <param name="value">効果量</param> public void ShowStatusEffectExplain (StatusEffectIcon.StatusEffectType statusEffectType, int value) { // 表示処理 partsList[0].ShowExplain_StatusEffect (statusEffectType, value); // 使わない説明欄を非表示 int listLength = partsList.Count; for (int i = 1; i < listLength; i++) { partsList[i].HideExplain (); } } /// <summary> /// 効果の説明を非表示にする /// </summary> public void HideExplains () { // 非表示処理 int listLength = partsList.Count; for (int i = 0; i < listLength; i++) { partsList[i].HideExplain (); } // 詳細時表示用カード非表示 if (detailExplainCard != null) detailExplainCard.gameObject.SetActive (false); } /// <summary> /// 戦闘中の場合武器攻撃の回数を返す。(非戦闘中は0を返す) /// </summary> /// <param name="charaID">対象キャラID</param> public int GetBattleCount_WeaponDamage (int charaID) { if (playBoardManager == null) return 0; return playBoardManager.weaponCount[charaID]; } /// <summary> /// 戦闘中の場合回復回数を返す。(非戦闘中は0を返す) /// </summary> /// <param name="charaID">対象キャラID</param> public int GetBattleCount_Heal (int charaID) { if (playBoardManager == null) return 0; return playBoardManager.healCount[charaID]; } } |
DeckEditWindow.cs(一部省略)
詳細ボタンが押された時に上記の効果説明システムを表示するようにします。
Update内でタップ判定を待つことで画面のどこをタップしても詳細画面を閉じれるようにします。
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 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using DG.Tweening; /// <summary> /// デッキ編集ウィンドウクラス /// </summary> public class DeckEditWindow : MonoBehaviour { // タイトル管理クラス private TitleManager titleManager; [SerializeField] private GameObject cardPrefab = null; // カードプレハブ // UIオブジェクト [SerializeField] private Text deckLogoText = null; // デッキ名+右上デッキ枚数文字列 [SerializeField] private Button backToStorageButton = null; // デッキから外すButton [SerializeField] private Button IntoDeckButton = null; // デッキに入れる [SerializeField] private EffectExplainDisplay effectExplainDisplay = null; // カード効果説明表示クラス [SerializeField] private GameObject effectExplainBackGroundObject = null; // カード効果説明表示時の背景オブジェクト // 保管中カード一覧オブジェクトTransform [SerializeField] private Transform storageCardsAreaTransform = null; // 生成済み保管中カードリスト private List<GameObject> storageCardObjects; private Dictionary<GameObject, Card> dic_StorageCardObjectByCard; // デッキオブジェクトTransform [SerializeField] private Transform deckAreaTransform = null; // 生成済みデッキ内カードリスト private List<GameObject> deckCardObjects; private Dictionary<GameObject, Card> dic_DeckCardObjectByCard; // 選択中カード情報 private Card selectCard; // 定数定義 public const int MinDeckNum = 1; // 最小デッキ枚数 public const int MaxDeckNum = 60; // 最大デッキ枚数 // 初期化関数(TitleManager.csから呼出) public void Init (TitleManager _titleManager) { // 変数初期化 deckCardObjects = new List<GameObject> (); dic_DeckCardObjectByCard = new Dictionary<GameObject, Card> (); storageCardObjects = new List<GameObject> (); dic_StorageCardObjectByCard = new Dictionary<GameObject, Card> (); // UI初期化 gameObject.SetActive (false); effectExplainDisplay.Init (); effectExplainBackGroundObject.SetActive (false); } // Update void Update() { // タップでカード効果説明を非表示化 if (Input.GetMouseButtonDown (0)) { effectExplainDisplay.HideExplains (); effectExplainBackGroundObject.SetActive (false); } } /// <summary> /// ウィンドウを表示する /// </summary> public void OpenWindow () { (省略) } /// <summary> /// ウィンドウを非表示にする /// </summary> public void CloseWindow () { (省略) } /// <summary> /// 保管中カードオブジェクトを作成する /// </summary> private void CreateStorageCardObject (CardDataSO cardData) { (省略) } /// <summary> /// デッキ内カードオブジェクトを作成する /// </summary> private void CreateDeckCardObject (CardDataSO cardData) { (省略) } /// <summary> /// デッキカードオブジェクトの並びを変更する /// </summary> public void AlignDeckList () { (省略) } /// <summary> /// 保管中カードオブジェクトの並びを変更する /// </summary> public void AlignStorageList () { (省略) } /// <summary> /// タップ先のカード選択処理 /// </summary> public void SelectCard (Card targetCard) { (省略) } /// <summary> /// カードの選択を解除する /// </summary> public void DeselectCard () { (省略) } /// <summary> /// デッキ枚数の表示を更新する /// </summary> private void RefreshDeckNumToUI () { (省略) } #region ボタン押下時処理 // デッキから外すボタン public void Button_BackToStorage () { (省略) } // デッキに入れるボタン public void Button_IntoDeck () { (省略) } // 詳細ボタン public void Button_CardDetail () { if (selectCard == null) return; // カード効果の説明を表示 effectExplainDisplay.ShowExplains (selectCard.baseCardData, Card.CharaID_Player); effectExplainBackGroundObject.SetActive (true); // SE再生 SEManager.instance.PlaySE (SEManager.SEName.DecideA); } #endregion } |
動作確認
Inspectorから各種参照をセットします。
DeckEditWindowコンポーネントにはeffectExplainDisplay(効果説明システム)とeffectExplainBackGroundObject(詳細説明時背景パネル)を、
EffectExplainDisplayコンポーネントにはEffectExplainDisplayの子オブジェクトに作成したCard(拡大したカードオブジェクト)をそれぞれ指定しましょう。
最後にCardDetailButtonの押下時処理にButton_CardDetailメソッドを指定すれば実装完了です。
これでデッキ編集画面からカードの効果を確認できるようになりました。
確認したいカードをタップして選択した状態で「詳細」ボタンを押せば拡大したカード画像と共に説明が表示され、もう一度タップで終了します。
途中でアタッチ先を間違えたりするとCardプレハブのゲームオブジェクト非アクティブになってる可能性があります。その影響でもしデッキ編集画面のデッキ欄カードが見えなくなっていたらプレハブ設定画面から再度アクティブにしてあげましょう。
【学歴不問・高卒、元ニートでも挑戦できる】
保管中カードリストの並べ替え機能 デッキソートシステムの実装
もう一つデッキ編集画面の改良を行ってみましょう。次は画面左側にある保管中カードのリストを並び替え表示するデッキソートシステムを作ってみます。
現状では全てのカードはserialNum(通し番号)の昇順で整列されていますが、それだけだとカードの種類が大量に増えた時に目的のカードを見つけにくいですよね。ユーザビリティを向上させるため、「カード番号順」、「効果量の大きさ順」、「強度順」の3種類の並び順に変更できるようにしていきましょう。
整列方法変更ボタンを作成する
ボタンを押す度に保管中カードの並び順が変更されるボタンを配置します。CardDetailButtonオブジェクト等をコピーペーストして作ると楽です。画面上部の空いているスペースに置きましょう。
DeckEditWindow以下に作成しますが、EffectExplainBackGroundより奥で表示されるように並び順を変更する必要があります。
- オブジェクト名:SortTypeButton
- 親:DeckEditWindow
- PosX:-80 PosY:205
- Width:150 Height:50
- (Image)Source Image:buttons_4.png
- 子オブジェクトのSimple Translation Textは削除
整列方法変更システム
スクリプトの実装に入っていきますが、まずは「効果量の大きい順に並べ替える」処理の実装のために必要なこととして、全てのカードの効果量の合計値を記録しておくようにします。
CardDataSO.cs
カードごとに効果量合計値を記録するのでまずはCardDataSOに記録用の変数を追加します。
アタッチしたら再生ボタンを押してデッキソートシステムがちゃんと動いているか確かめてみましょう。
これで画面上部のボタンを押す度に3種類の方法で並び替えを行ってくれるようになりました。
カードの種類が多くなればなるほど、プレイヤーは目的のカードを探しづらくなるのでこのようなユーザビリティ向上の配慮をしてあげると良いでしょう。
まとめ
以上がデッキ編集システムの改良の一例でした。
デッキ編集はこのゲームにおいてメインとなる要素ですので、プレイヤーが遊びやすくなるように引き続き改良を加えていけると良いでしょう。
アプリ版『呪術迷宮』ではこの他にデッキ切り替えのシステムもあります。Dataクラスで選択中のデッキIDを記憶し、PlayerPrefsでデッキIDごとにカードリストを保存する事で実装していますが、少々難易度が高いです。余裕がある方はチャレンジしてみると良いでしょう。
以上でこの講座は終了ですが、デッキ編集システムの他にも改良の余地は沢山ありますのでどんどん自分の発想で遊びやすくしていったりボリュームを増やしてみてください。
そしてゲーム開発の流れを覚えたらぜひオリジナルゲームの開発にも着手しましょう!あなたの作るゲームを楽しみに待っています。
最後に今回の講座で開発したゲームのサンプルプロジェクトファイルとスクリプト全文集を用意しました。
次の記事:
コメント