※長文となってしまったため、分けて投稿します
投稿に慣れていないため、分かりづらい点が多々あるかと思いますがよろしくお願い致します。
過不足があれば随時補足します。
使用アセット
CCGKit
マニュアル:https://www.ccgkit.com/wiki/index.php?title=Main_Page
実現したいこと
上記アセットを利用して、カードゲーム「ハースストーン」のコピーゲームを作成したいと考えています。
カードの能力拡張を行っているのですが、以下の点において作業が停滞しています。
・特定のカード(以下、カードAとします)を手札からボードに召喚(移動)した際、指定したカード(以下、トークンBとします)を別途、デッキ外から召喚する機能を実装したい
現状のクラス構成
各カードの情報はUnityのエディタ拡張により、JSON形式で保存しております。
以下に、あるカードの例を記します。
JSON
1 { 2 "cardTypeId": 0, 3 "name": "カード名を表す文字列(実際はUnicode表記です)", 4 "costs": [ 5 { 6 "statId": 1, 7 "value": 2, 8 "$type": "CCGKit.PayResourceCost" 9 } 10 ], 11 "properties": [ 12 { 13 "value": "能力の内容を表現するための文字列(実際はUnicode表記です)", 14 "name": "Text", 15 "$type": "CCGKit.StringProperty" 16 }, 17 { 18 "value": "Creature", 19 "name": "Picture", 20 "$type": "CCGKit.StringProperty" 21 }, 22 { 23 "value": 2, 24 "name": "MaxCopies", 25 "$type": "CCGKit.IntProperty" 26 }, 27 { 28 "value": null, 29 "name": "Material", 30 "$type": "CCGKit.StringProperty" 31 } 32 ], 33 "stats": [ 34 { 35 "baseValue": 2, 36 "statId": 0, 37 "name": "Attack", 38 "originalValue": 2, 39 "minValue": 0, 40 "maxValue": 99, 41 "modifiers": [] 42 }, 43 { 44 "baseValue": 3, 45 "statId": 1, 46 "name": "Life", 47 "originalValue": 3, 48 "minValue": 0, 49 "maxValue": 99, 50 "modifiers": [] 51 } 52 ], 53 "keywords": [], 54 "abilities": [ 55 { 56 "trigger": { 57 "zoneId": 2, 58 "$type": "CCGKit.OnCardEnteredZoneTrigger" 59 }, 60 "name": "heal 2", 61 "type": "Triggered", 62 "effect": { 63 "value": { 64 "constant": 2, 65 "$type": "CCGKit.ConstantValue" 66 }, 67 "duration": 0, 68 "statId": 1, 69 "gameZoneId": 2, 70 "cardTypeId": 0, 71 "$type": "CCGKit.IncreaseCardStatEffect" 72 }, 73 "target": { 74 "conditions": [], 75 "$type": "CCGKit.TargetCard" 76 }, 77 "$type": "CCGKit.TriggeredAbility" 78 } 79 ], 80 "id": 1
これらを読み込み、一枚のカードを描画する処理を組んでいます。
これらの値はRuntimeCardクラスというクラスで管理されており、カードをハンドからボードに移動する際にもこのクラスを利用しているように見えます。
C#
1using System; 2using System.Collections.Generic; 3 4namespace CCGKit 5{ 6 /// <summary> 7 /// This class represents a runtime instance of a card. 8 /// このクラスは、カードのランタイムインスタンス(プログラムの実行に必要な部品の集合)を表します。 9 /// </summary> 10 public class RuntimeCard 11 { 12 /// <summary> 13 /// The card identifier of this card. 14 /// カードの固有ID 15 /// </summary> 16 public int cardId; 17 18 /// <summary> 19 /// The instance identifier of this card. 20 /// このカードのインスタンス識別子。 21 /// </summary> 22 public int instanceId; 23 24 /// <summary> 25 /// The stats of this card, indexed by id. 26 /// このカードのスタッツはidで示されます。 27 /// </summary> 28 public Dictionary<int, Stat> stats = new Dictionary<int, Stat>(); 29 30 /// <summary> 31 /// The stats of this card, indexed by name. 32 /// このカードのスタッツは名前で示されます。 33 /// card.namedStats["Attack"];みたいな書き方で値を取得できる 34 /// </summary> 35 public Dictionary<string, Stat> namedStats = new Dictionary<string, Stat>(); 36 37 /// <summary> 38 /// The keywords of this card. 39 /// カードのキーワード 40 /// </summary> 41 public List<RuntimeKeyword> keywords = new List<RuntimeKeyword>(); 42 43 /// <summary> 44 /// The player that owns this card. 45 /// このカードを所有しているプレイヤー。 46 /// </summary> 47 public PlayerInfo ownerPlayer; 48 49 /// <summary> 50 /// The type of this card. 51 /// カードタイプ 52 /// ミニオン or スペル 53 /// </summary> 54 public CardType cardType 55 { 56 get 57 { 58 var gameConfig = GameManager.Instance.config; 59 var libraryCard = gameConfig.GetCard(cardId); 60 return gameConfig.cardTypes.Find(x => x.id == libraryCard.cardTypeId); 61 } 62 } 63 64 /// <summary> 65 /// The callback that is called when a keyword is added to this card. 66 /// このカードにキーワードが追加されたときに呼び出されるコールバック。 67 /// </summary> 68 public Action<RuntimeKeyword> onKeywordAdded; 69 70 /// <summary> 71 /// The callback that is called when a keyword is removed from this card. 72 /// このカードからキーワードが削除されたときに呼び出されるコールバック。 73 /// </summary> 74 public Action<RuntimeKeyword> onKeywordRemoved; 75 76 /// <summary> 77 /// Adds a keyword to this card. 78 /// このカードにキーワードを追加する 79 /// </summary> 80 /// <param name="keyword">The identifier of the keyword.</param> 81 /// <param name="value">The value of the keyword.</param> 82 public void AddKeyword(int keyword, int value) 83 { 84 var k = keywords.Find(x => x.keywordId == keyword && x.valueId == value); 85 if (k == null) 86 { 87 k = new RuntimeKeyword(); 88 k.keywordId = keyword; 89 k.valueId = value; 90 keywords.Add(k); 91 if (onKeywordAdded != null) 92 { 93 onKeywordAdded(k); 94 } 95 } 96 } 97 98 /// <summary> 99 /// Removes a keyword from this card. 100 /// カードからキーワードを削除する 101 /// </summary> 102 /// <param name="keyword">The identifier of this keyword.</param> 103 /// <param name="value">The value of this keyword.</param> 104 public void RemoveKeyword(int keyword, int value) 105 { 106 var k = keywords.Find(x => x.keywordId == keyword && x.valueId == value); 107 if (k != null) 108 { 109 keywords.Remove(k); 110 if (onKeywordRemoved != null) 111 { 112 onKeywordRemoved(k); 113 } 114 } 115 } 116 117 /// <summary> 118 /// Returns true if this card has the specified keyword and false otherwise. 119 /// このカードに指定されたキーワードがある場合はtrueを返し、そうでない場合はfalseを返します。 120 /// </summary> 121 /// <param name="name">The name of the keyword.</param> 122 /// <returns>True if this card has the specified keyword; false otherwise.</returns> 123 public bool HasKeyword(string name) 124 { 125 var gameConfig = GameManager.Instance.config; 126 var keywordId = -1; 127 var valueId = -1; 128 foreach (var keyword in gameConfig.keywords) 129 { 130 var selectedValue = keyword.values.FindIndex(x => x.value == name); 131 if (selectedValue != -1) 132 { 133 keywordId = keyword.id; 134 valueId = selectedValue; 135 break; 136 } 137 } 138 var k = keywords.Find(x => x.keywordId == keywordId && x.valueId == valueId); 139 return k != null; 140 } 141 } 142} 143