この記事はハクスラローグライク×デッキ構築型カードバトルRPG「呪術迷宮」の作り方講座の第7回です。
前回で一通りのカードデータとカード効果の設定を行いました。Unityで実践的なカードバトルゲームのカード効果の開発を経験できたかと思います。
前回の記事:
ですが、現在はまだScriptableObjectがカードのデータを持っているだけです。
これからゲーム中に生成されるカードオブジェクトのUIにそれらのデータを適用させていきましょう。
また、最後にシングルトンを用いたカードデータの保存システムを作成し、日英翻訳機能を実装。ローカライズ対策にも備えたゲームシステムを構築していきます。
カードオブジェクト側のカードデータ管理
現在カードオブジェクトにアタッチされているスクリプト(Card.cs)が保持しているデータは位置情報のみですので、「どのデータ(ScriptableObject)が対応しているか」そして「どの効果を今持っているか」などを管理する機能を追加します。
このゲームでは合成によってカードの効果が増える事がありますので、あくまでScriptableObject側のデータは参照のみで扱い、効果データは別の変数で管理しておく必要があります。
Card.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 126 127 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using DG.Tweening; /// <summary> /// カード処理クラス /// </summary> public class Card : MonoBehaviour, IPointerDownHandler, IPointerUpHandler { // オブジェクト・コンポーネント参照 private FieldManager fieldManager; // フィールド管理クラス public RectTransform rectTransform; // オブジェクトのRectTransform // カードデータ [HideInInspector] public CardDataSO baseCardData; // 基となるScriptableObject側カードデータ [HideInInspector] public List<Sprite> iconSprites; // カードアイコンリスト [HideInInspector] public List<CardEffectDefine> effects; // カード効果リスト [HideInInspector] public int forcePoint; // 強度 [HideInInspector] public int controllerCharaID; // カードの使用キャラクターID(後述の定数を使用) // 各種変数 private Vector2 basePos; // 基本座標(ドラッグ終了後に戻ってくる座標) private Tween moveTween; // 移動Tween [HideInInspector] public CardZone.ZoneType nowZone; // このカードが置かれているカードゾーン // キャラクターID定数 public const int CharaNum = 2; // 戦闘内のキャラクター人数 public const int CharaID_Player = 0;// キャラクターID:主人公(プレイヤーキャラ) public const int CharaID_Enemy = 1; // キャラクターID:敵 public const int CharaID_None = -1; // キャラクターID:(無し) // その他定数 private const int MaxIcons = 6; // カードアイコンの最大数 private const int MaxEffects = 6; // カード効果の最大数 /// <summary> /// 初期化処理 /// </summary> /// <param name="_fieldManager">FieldManager参照</param> /// <param name="initPos">初期座標</param> public void Init (FieldManager _fieldManager, Vector2 initPos) { // 参照取得 fieldManager = _fieldManager; // 変数初期化 rectTransform.position = initPos; basePos = initPos; nowZone = CardZone.ZoneType.Hand; iconSprites = new List<Sprite> (); effects = new List<CardEffectDefine> (); } /// <summary> /// (初期化時に呼出) /// カード定義データから各種パラメータを取得してセットする /// </summary> /// <param name="cardControllerCharaID">使用者キャラクターID(定数を使用)</param> public void SetInitialCardData (CardDataSO cardData, int cardControllerCharaID) { baseCardData = cardData; // カードアイコン AddCardIcon (cardData.iconSprite); // カード効果リスト foreach (var item in cardData.effectList) AddCardEffect (item); // 強度 SetForcePoint (cardData.force); // カード使用者データ controllerCharaID = cardControllerCharaID; } #region オブジェクト移動・表示演出 (省略) #endregion #region パラメータ変更・追加処理 /// <summary> /// カードアイコンを追加する /// </summary> public void AddCardIcon (Sprite newIcon) { // カードアイコン数上限なら終了 if (iconSprites.Count >= MaxIcons) return; // アイコンリストに追加 iconSprites.Add (newIcon); } /// <summary> /// カード効果を新規追加する /// </summary> /// <param name="newEffect">効果の種類・数値データ</param> private void AddCardEffect (CardEffectDefine newEffect) { // カード効果数上限なら終了 if (effects.Count >= MaxEffects) return; // 効果データを新規作成する var effectData = new CardEffectDefine (); effectData.cardEffect = newEffect.cardEffect; effectData.value = newEffect.value; // 効果リストに追加 effects.Add (effectData); } /// <summary> /// カードの強度をセットする /// </summary> public void SetForcePoint (int value) { // パラメータをセット forcePoint = value; } #endregion #region タップイベント処理 (省略) #endregion } |
- 今後、スクリプト内で変化の無い箇所はここでの記載を省略する場合があります。
新しくカードオブジェクトを生成する時、Initメソッド呼び出しの後にSetInitialCardDataメソッドも呼び出すことによってカード情報のセッティングを行えるようになりました。
ただしUIを変更していないのでFieldManager側の処理を追加しても画面に変化はありません。このままCardクラスを拡張してUI表示にまで対応していっても良いのですが、スクリプトが長くなりすぎるのでUI処理だけを担当する別クラスを用意しましょう。
Scripts/Battle以下に新クラスCardUIを作成し、以下のような表示処理を組み込みます。
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 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /// <summary> /// カードのUI表示設定クラス /// </summary> public class CardUI : MonoBehaviour { // このカードの処理クラス private Card card; // UIプレハブ [SerializeField] private GameObject cardIconPrefab = null; // カードアイコンPrefab [SerializeField] private GameObject cardEffectTextPrefab = null;// カード効果テキストPrefab // オブジェクト内UI参照 [SerializeField] private Image cardBackImage = null; // カード背景Image [SerializeField] private Text cardNameText = null; // カード名Text [SerializeField] private Transform cardIconParent = null; // カードアイコンリストの親Transform [SerializeField] private Transform cardEffectTextParent = null; // カード効果テキストリストの親Transform [SerializeField] private Text cardForceText = null; // カード強度Text [SerializeField] private Image cardForceBackImage = null; // カード強度Textの背景Image [SerializeField] private Text quantityText = null; // カード数量Text [SerializeField] private Image quantityBackImage = null; // カード数量Textの背景Image [SerializeField] private GameObject hilightImageObject = null; // 選択時強調表示画像Object // 各種スプライト素材 [SerializeField] private Sprite cardBackSprite_Player = null; // プレイヤー側カード背景スプライト [SerializeField] private Sprite cardBackSprite_Enemy = null; // 敵側カード背景スプライト // 作成した効果Textリスト private Dictionary<CardEffectDefine, Text> cardEffectTextDic; // 初期化関数(Card.csから呼出) public void Init (Card _card) { card = _card; cardEffectTextDic = new Dictionary<CardEffectDefine, Text> (); // UI初期化 quantityText.text = ""; quantityBackImage.color = Color.clear; } /// <summary> /// プレイヤー側用・敵側用のカード背景画像をセット /// </summary> public void SetCardBackSprite (int cardControllerCharaID) { if (cardControllerCharaID == Card.CharaID_Player) cardBackImage.sprite = cardBackSprite_Player; else if (cardControllerCharaID == Card.CharaID_Enemy) cardBackImage.sprite = cardBackSprite_Enemy; } /// <summary> /// カード名表示 /// </summary> /// <param name="name_JP">カード名(日本語)</param> /// <param name="name_EN">カード名(英語)</param> public void SetCardNameText (string name_JP, string name_EN) { cardNameText.text = name_JP; } /// <summary> /// カードアイコンUIを追加 /// </summary> public void AddCardIconImage (Sprite sprite) { // オブジェクト作成 var obj = Instantiate (cardIconPrefab, cardIconParent); // スプライトを設定 obj.GetComponent<Image> ().sprite = sprite; } /// <summary> /// カード効果Textを追加 /// </summary> public void AddCardEffectText (CardEffectDefine effectData) { // オブジェクト作成 var obj = Instantiate (cardEffectTextPrefab, cardEffectTextParent); // TextUIとカード効果を紐づける cardEffectTextDic.Add (effectData, obj.GetComponent<Text> ()); // Textの内容を更新 ApplyCardEffectText (effectData); } /// <summary> /// カード効果Textの表示内容を更新 /// </summary> public void ApplyCardEffectText (CardEffectDefine effectData) { // 対象のTextUIを取得 var targetText = cardEffectTextDic[effectData]; // 効果量を取得 int effectValue = effectData.value; string effectValueMes = ""; // 効果量を文字列化 effectValueMes = effectValue.ToString (); // UI表示 targetText.text = string.Format (CardEffectDefine.Dic_EffectName_JP[effectData.cardEffect], effectValueMes); } /// <summary> /// カード強度Text表示 /// </summary> public void SetForcePointText (int value) { if (value > 0) {// 表示 cardForceText.text = value.ToString (); cardForceBackImage.color = Color.white; } else {// 非表示 cardForceText.text = ""; cardForceBackImage.color = Color.clear; } } /// <summary> /// カード数量Text表示 /// </summary> public void SetAmountText (int value) { quantityText.text = "x" + value; quantityBackImage.color = Color.white; } /// <summary> /// カード強調表示画像を表示・非表示にする /// </summary> public void SetHilightImage (bool mode) { hilightImageObject.SetActive (mode); } /// <summary> /// アイコンと効果の表示をリセットする /// </summary> public void ClearIconsAndEffects () { // アイコン初期化 int length = cardIconParent.childCount; for (int i = 0; i < length; i++) { Destroy (cardIconParent.GetChild (i).gameObject); } // 効果初期化 length = cardEffectTextParent.childCount; for (int i = 0; i < length; i++) { Destroy (cardEffectTextParent.GetChild (i).gameObject); } } } |
合成によって効果が後から増えたり、効果量が変化した時にも対応できるような実装にしました。また、カードの使用者(自分もしくは敵)ごとに使用する背景画像も変更するようにします。
文章の表示については今は日本語にのみ対応しています。
これらの処理をCardクラス側から呼び出すようにしていきましょう。
Card.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 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using DG.Tweening; /// <summary> /// カード処理クラス /// </summary> public class Card : MonoBehaviour, IPointerDownHandler, IPointerUpHandler { // オブジェクト・コンポーネント参照 [SerializeField] private CardUI cardUI = null; // カードUI表示設定クラス private FieldManager fieldManager; // フィールド管理クラス public RectTransform rectTransform; // オブジェクトのRectTransform // カードデータ [HideInInspector] public CardDataSO baseCardData; // 基となるScriptableObject側カードデータ [HideInInspector] public List<Sprite> iconSprites; // カードアイコンリスト [HideInInspector] public List<CardEffectDefine> effects; // カード効果リスト [HideInInspector] public int forcePoint; // 強度 [HideInInspector] public int controllerCharaID; // カードの使用キャラクターID(後述の定数を使用) // 各種変数 private Vector2 basePos; // 基本座標(ドラッグ終了後に戻ってくる座標) private Tween moveTween; // 移動Tween [HideInInspector] public CardZone.ZoneType nowZone; // このカードが置かれているカードゾーン // キャラクターID定数 public const int CharaNum = 2; // 戦闘内のキャラクター人数 public const int CharaID_Player = 0;// キャラクターID:主人公(プレイヤーキャラ) public const int CharaID_Enemy = 1; // キャラクターID:敵 public const int CharaID_None = -1; // キャラクターID:(無し) // その他定数 private const int MaxIcons = 6; // カードアイコンの最大数 private const int MaxEffects = 6; // カード効果の最大数 /// <summary> /// 初期化処理 /// </summary> /// <param name="_fieldManager">FieldManager参照</param> /// <param name="initPos">初期座標</param> public void Init (FieldManager _fieldManager, Vector2 initPos) { // 参照取得 fieldManager = _fieldManager; // 配下コンポーネント初期化 cardUI.Init (this); // 変数初期化 rectTransform.position = initPos; basePos = initPos; nowZone = CardZone.ZoneType.Hand; iconSprites = new List<Sprite> (); effects = new List<CardEffectDefine> (); } /// <summary> /// (初期化時に呼出) /// カード定義データから各種パラメータを取得してセットする /// </summary> /// <param name="cardControllerCharaID">使用者キャラクターID(定数を使用)</param> public void SetInitialCardData (CardDataSO cardData, int cardControllerCharaID) { baseCardData = cardData; // カード名 cardUI.SetCardNameText (cardData.cardName_JP, cardData.cardName_EN); // カードアイコン AddCardIcon (cardData.iconSprite); // カード効果リスト foreach (var item in cardData.effectList) AddCardEffect (item); // 強度 SetForcePoint (cardData.force); // カード使用者データ controllerCharaID = cardControllerCharaID; cardUI.SetCardBackSprite (cardControllerCharaID); // カード背景UIに適用 } #region オブジェクト移動・表示演出 (省略) #endregion #region パラメータ変更・追加処理 /// <summary> /// カードアイコンを追加する /// </summary> public void AddCardIcon (Sprite newIcon) { // カードアイコン数上限なら終了 if (iconSprites.Count >= MaxIcons) return; // アイコンリストに追加 iconSprites.Add (newIcon); // UI表示 cardUI.AddCardIconImage (newIcon); } /// <summary> /// カード効果を新規追加する /// </summary> /// <param name="newEffect">効果の種類・数値データ</param> private void AddCardEffect (CardEffectDefine newEffect) { // カード効果数上限なら終了 if (effects.Count >= MaxEffects) return; // 効果データを新規作成する var effectData = new CardEffectDefine (); effectData.cardEffect = newEffect.cardEffect; effectData.value = newEffect.value; // 効果リストに追加 effects.Add (effectData); // UI表示 cardUI.AddCardEffectText (effectData); } /// <summary> /// カードの強度をセットする /// </summary> public void SetForcePoint (int value) { // パラメータをセット forcePoint = value; // UI表示 cardUI.SetForcePointText (forcePoint); } #endregion #region タップイベント処理 (省略) #endregion } |
そしてのちほど動作確認を行うためにFieldManagerを拡張しておきます。
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 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 163 164 165 166 167 168 169 170 171 172 173 174 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using DG.Tweening; /// <summary> /// フィールド管理クラス /// </summary> public class FieldManager : MonoBehaviour { // オブジェクト・コンポーネント参照 private BattleManager battleManager; // 戦闘画面マネージャ public RectTransform canvasRectTransform; // CanvasのRectTransform public Camera mainCamera; // メインカメラ [SerializeField] private DammyHandUI dammyHandUI = null; // ダミー手札制御クラス // カード関連参照 [SerializeField] private GameObject cardPrefab = null; // カードプレハブ [SerializeField] private Transform cardsParent = null; // 生成するカードオブジェクトの親Transform [SerializeField] private Transform deckIconTrs = null; // デッキオブジェクトTransform // 各種変数・参照 private Card draggingCard; // ドラッグ操作中カード private List<Card> cardInstances; // 生成したプレイヤー操作カードリスト private bool reserveHandAlign; // 手札整列フラグ private bool isDrawing; // true:手札補充中である // 表示テスト用:カードデータ [SerializeField] private CardDataSO testCardData; // 初期化処理 public void Init (BattleManager _battleManager) { // 参照取得 battleManager = _battleManager; // 変数初期化 cardInstances = new List<Card> (); // デバッグ用ドロー処理(遅延実行) DOVirtual.DelayedCall ( 1.0f, // 1.0秒遅延 () => { DrawCardsUntilNum (5); } ); } // Update void Update() { // ドラッグ操作中の処理 if (draggingCard != null) { // 更新処理 UpdateDragging (); } } // OnGUI(Updateのように繰り返し実行・UI制御用) void OnGUI () { // 手札整列フラグが立っているなら整列 if (reserveHandAlign) { AlignHandCards (); reserveHandAlign = false; } } #region プレイヤー側手札・デッキ処理 /// <summary> /// デッキからカードを1枚引き手札に加える /// </summary> /// <param name="handID">対象手札番号</param> private void DrawCard (int handID) { // オブジェクト作成 var obj = Instantiate (cardPrefab, cardsParent); // カード処理クラスを取得・リストに格納 Card objCard = obj.GetComponent<Card> (); cardInstances.Add (objCard); // カード初期設定 objCard.Init (this, deckIconTrs.position); objCard.PutToZone (CardZone.ZoneType.Hand, dammyHandUI.GetHandPos (handID)); objCard.SetInitialCardData (testCardData, Card.CharaID_Player); } /// <summary> /// 手札が指定枚数になるまでカードを引く /// </summary> /// <param name="num">指定枚数</param> private void DrawCardsUntilNum (int num) { // 現在の手札枚数を取得 int nowHandNum = 0; foreach (var card in cardInstances) { if (card.nowZone == CardZone.ZoneType.Hand) nowHandNum++; } // 新たに引くべき枚数を取得 int drawNum = num - nowHandNum; if (drawNum <= 0) return; // 手札UIに枚数を指定 dammyHandUI.SetHandNum (nowHandNum + drawNum); // 連続でカードを引く(Sequence) const float DrawIntervalTime = 0.1f; // ドロー間の時間間隔 var drawSequence = DOTween.Sequence (); isDrawing = true; for (int i = 0; i < drawNum; i++) { // 1枚引く処理 drawSequence.AppendCallback (() => { DrawCard (nowHandNum); nowHandNum++; }); // 時間間隔を設定 drawSequence.AppendInterval (DrawIntervalTime); } drawSequence.OnComplete (() => isDrawing = false); } /// <summary> /// 手札のカードを整列させる /// </summary> private void AlignHandCards () { // 手札整列処理 int index = 0; // 手札内番号 // ダミー手札を整列 dammyHandUI.ApplyLayout (); // 各カードをダミー手札に合わせて移動 foreach (var card in cardInstances) { if (card.nowZone == CardZone.ZoneType.Hand) { card.PutToZone (CardZone.ZoneType.Hand, dammyHandUI.GetHandPos (index)); index++; } } } /// <summary> /// 現在の手札の枚数を手札UI処理クラスに反映させて整列する /// </summary> private void CheckHandCardsNum () { // 現在の手札枚数を取得 int nowHandNum = 0; foreach (var item in cardInstances) { if (item.nowZone == CardZone.ZoneType.Hand) nowHandNum++; } // ダミー手札に枚数を指定 dammyHandUI.SetHandNum (nowHandNum); // 手札枚数に合わせて手札を整列 // (手札枚数を変更した同フレームではダミー手札オブジェクトが動いていない為一瞬だけ遅延実行) reserveHandAlign = true; } #endregion #region カードドラッグ処理 (省略) #endregion } |
- constやstatic、enumなどで定義された定数は「(クラス名).(定数名)」で他クラスからそのまま取得する事が可能です。
効果名・アイコン表示用プレハブを作成
まだ効果名Textおよびアイコン表示用Imageについては、入れ物である親オブジェクトしか用意してません(EffectsとIcons)。
複数の効果名・アイコン表示に対応できるように、それぞれ1個当たりのパーツをプレハブで用意しておく必要があります。
Cardプレハブの編集画面にて設定を開始しましょう。
アイコン表示用オブジェクト
アイコン画像はCard/Iconsオブジェクト以下に横並びで表示される為、まずはIconsオブジェクトに対してHorizontal Layout Groupをアタッチします。
中央揃え設定(Middle Center)で、Child Force Expandはオフにします。
ここにプレハブ化を行うベースとなる画像UIとしてCardIconオブジェクトを作成します。
UI>ImageオブジェクトをIconsの子に作成し、CardIconと命名。transformの値を以下の画像のように調整。
Source Imageはスクリプト内においてScriptableObjectの設定をもとに行いますのでここでは変更不要です。
ここまで設定できたらCardIconをプレハブ化し、元となったオブジェクトはCardプレハブ内から取り除きます。
効果名表示用オブジェクト
効果名TextはCard/Effects以下に縦並びで表示されるため、Effectsオブジェクトに対してVertical Layout Groupをアタッチします。
中央揃え設定(Middle Center)にし、他は変更しなくてもOKです。
同様にプレハブ化のためのベースオブジェクトとしてCardEffectというTextUIオブジェクトをここに作成します(UI > Legacy > Textで作成)。
効果の表示が5個並んでもギリギリ読めるくらいの大きさに設定すると良いでしょう。
文字が少しでも読みやすくなるようにShadowコンポーネントでの修飾も行っています。これは各種UIコンポーネントと組み合わせる事で文字や画像に影を設定する事ができるものです。似たような機能としてOutlineコンポーネントもあり、こちらは縁取りに対応しています。
設定が完了したらこのCardEffectオブジェクトもプレハブ化し、元となったオブジェクトは削除します。
CardUIクラスをアタッチ
残りの操作として、先ほどスクリプトを作成したCardUIのアタッチや他コンポーネントへの参照設定が必要です。
まずはCardプレハブに対してCardUIのアタッチから行います。量が多いですが1つずつドラッグ&ドロップで指定しましょう。
- 各UIオブジェクトはHilightFrameを除いて全てアクティブにしておきます。
- cardBackSprite_Player(プレイヤー側カード背景画像)とcardBackSprite_Enemy(敵側背景画像)の素材はTextures/GUIs/Cards以下に存在します。
プレハブ側の設定を終えたら先ほど用意した動作確認を実行する為に、シーン内のManagersオブジェクトのField Managerコンポーネント、[Test Card Data]パラメータに任意のカードデータ(ScriptableObjectファイル)を指定します。
これでテストプレイを行えば手札のカードに対して全て指定したカードのデータが反映されつつ表示されていることが確認できます。色々なカードデータで表示テストを行い、効果が2種類あるカードでも問題なく表示できているか確かめておくと良いでしょう。
なおFieldManager.csの89行目で使用者キャラクターIDを敵のものに変更すればカード背景が変更される事も確認できます。
シングルトンのデータ管理クラスを作成 日英翻訳機能の実装
現状では固定のカードデータのみをドロー時に反映させているので全てのカードが同じ種類になっています。そして文章表示も日本語でしか行っていません。
まずは言語設定に対応していきますが、この言語設定というのは複数のシーン(画面)をまたいでも同じ設定になるようにしなければいけません。
今はプロジェクト内には1つシーン(SampleScene.unity)しか存在しておらず、その中でオブジェクトの作成や配置を行っていますが将来的に別のシーンとしてタイトル画面を作成予定です。
ゲーム中にシーンを切り替えると基本的に前のシーンに存在した全てのオブジェクトは破棄されます。なのでBattleManagerクラスに言語設定を保存させても、シーン切り替えでManagersオブジェクト自体が消滅するのでタイトル画面シーンにその設定を引き継げません。
これを解決するために保存したいデータを持つクラス(がアタッチされているオブジェクト)にはシーンをまたいでも破壊されない設定を付与する必要があります。
注意点としてただ非破壊設定を付与してもそのオブジェクトがシーン内に初期から配置されている限り、そのシーンに切り替えるたびに同じオブジェクトがずっと増え続けてしまいます(オブジェクトが引き継がれて破棄されないので)。
データ管理用オブジェクトは1つしか必要ないので、2個目以上に生成されたものは生成された直後に削除される機能も必要になります。
これらの要点を踏まえて「ゲーム実行中に常に1つだけ存在するクラス(オブジェクト)」を作成します。このような特性をシングルトンと言います。シングルトンなオブジェクトにアタッチされた他のクラスも同様な特性を持つようになります。
シーン内にデータ管理用の空オブジェクトDataManagerを作成します。子オブジェクトである必要はなく、座標も設定不要です。
これにアタッチするスクリプト、Dataも作成します。フォルダ分けはおまかせします(ここではScripts以下にCommonフォルダを作成してここに格納しています。)
まとめ
カードの処理システムを拡張し、前回の記事で作成したカードデータをオブジェクトに反映させ、カードのUIを整えました。
また、シングルトンのデータ保存クラスを作成してシーン間での情報の受け渡しが可能になりました。今後タイトル画面を作成した時にこのシステムが活きてきます。シングルトンの機能を1つ作っておくと他のゲーム制作でも流用可能なのでぜひ覚えておきましょう。
次回もこのデータ保存クラスの特性を活かしてプレイヤーの初期デッキを設定できるようにしていきます。
次の記事:
コメント