今回はユニティちゃんのRPGで使用するアイテムやステータス等のデータの作成についてやっていきたいと思います。
この記事から後のいくつかの記事はアイテムやステータスのデータを使ってコマンド画面での処理を作っていく事になるので少し難しいというか処理が複雑になってきます。
細かい部分の説明は入れているつもりですが、難しいのは否めません。
単純にわたくしのやり方が複雑にしている可能性もありますが・・・、わたくしのやり方がベストプラクティスではないのでより最適でわかりやすいやり方を模索してみてください。
前回はユニティちゃんの操作をゲームコントローラーで出来るようにしました。
ユニティちゃんのRPGを作ってみようの他の記事は
から見ることが出来ます。
アイテムやステータスのデータ管理をどうするか?
まずは最初にアイテムやステータスのデータをどうやって取り扱うかを考えます。
アイテムやステータスのデータは簡単に言えばテキストの集まりなので、外部ファイルにアイテムデータやステータスデータを保持して置き、必要に応じてそれらのデータを取得したり書き換えたりする事で実現出来ます。
ただ外部ファイルの読み込みや書き込みをするとなるとファイル操作が必要になるので慣れていない人には難しいところです。
外部ファイルにデータを保存するのではなくゲーム中にデータを保持しているクラスをインスタンス化してそこからデータの取得、書き換えをする方法もあります。
この場合はC#スクリプトをMonoBehaviourクラスを継承してクラスを作成するのではなく、objectクラスを継承する形でクラスを作成するか何も継承しない(デフォルトでobjectクラスを継承する事になる)形でクラスを作成する必要があります。
この場合はゲーム実行開始とともにクラスをインスタンス化しデータを取得したり書き換えたりすることは出来ますが、スクリプトの中にデータの情報を入れる必要があります。
その他、MonoBehaviourクラスを継承してクラスを作成し、その中でデータを保持しておき何らかのゲームオブジェクトに取り付けて利用する方法もあります。
この方法でもアイテムやステータスのデータは扱えますが、視覚的に分かり辛いというのがあります。
そんな時に便利なのがUnityのScriptableObjectです。
クラスをScriptableObjectクラスを継承して作成すると予めそのクラスをアセットファイルとしてファイル形式にしておくことが出来るので、ゲーム開始前からデータファイルとして存在させることが出来ます。
ScriptableObjectクラスを継承しなくてもデータの取り扱いは出来ますが、それらのデータを視覚的に確認するにはスクリプトの中身を見る必要があり実際のデータはゲームが開始するまで作成されません。
ScriptableObjectクラスを継承してクラスを作成すると存在するアセットファイルとしてそのデータを取り扱う事が出来るのでゲーム開始前にデータをセットし視覚的にわかりやすくなります。
ただ注意が必要なのがScriptableObjectクラスから作成したアセットファイルは視覚的に確認出来るアセットファイルとして存在しますが、エディターを開きなおしたりゲームをやめたあと再び再開した時は初期値に戻ります。
これは元のデータをインスタンス化して視覚化しているのがアセットファイルで次回開いた時はインスタンス化するところから始まっているからなのかも?
データを次回以降にも持ち越すにはScriptableObjectから作ったアセットファイルのデータを外部ファイル等に保存する必要があります(これは別の記事でやります)。
ScriptableObjectについては
上の記事を参照してください。
ScriptableObjectはシーン間の遷移をする時にも使っています。
これらの事を考慮してアイテムやステータス等のRPGで使用するデータ群はScriptableObjectクラスを継承して作成し、予めアセットファイルとして見てすぐわかるようにしておきます。
ユニティちゃんRPGで使用するデータの作成
ユニティちゃんRPGで使用するデータを作成するにはそのデータを作成するスクリプトが必要になります。
そこからアセットファイルデータを作成出来ます。
なので、わかりやすくする為にアイテムデータを作成するスクリプトはAssets/RPG/Scripts/Itemフォルダ、ステータスデータを作成するスクリプトはAssets/RPG/Scripts/Statusフォルダ内に作成する事にします。
それらのスクリプトから作成したアセットファイルはアイテムデータはAssets/RPG/Data/ItemDataフォルダ、ステータスデータはAssets/RPG/Data/Statusフォルダ内に作成します。
スクリプトやアセットファイルの保存先は各々わかりやすい階層に移動させてください。
ステータスデータの作成
キャラクターステータスは味方のキャラクターのステータスと戦闘時の敵のステータスと似たようなステータスを持つけど一部違うフィールドだったりメソッドを持たせたい事もあります。
そんな時に便利なのが継承で、継承を使うと継承元の持っているフィールドやメソッドを継承先のクラスが持つことが出来ます。
ただなんでもかんでも継承をすればよいというわけではなく『子(継承先)は親(継承元)である』という条件に合致する時だけ使用します。
例えば、親のキャラクターステータスをCharacterStatusクラスとして作ったならば、それを継承してAllyStatus(味方のステータス)とEnemyStatus(敵のステータス)を作成します。
『味方のステータスと敵のステータスはどちらもキャラクターステータスである』というのが成り立つので継承を使えます。
まったく関係ないHuman(人間)クラスを継承してSword(剣)クラスを作った場合は『剣は人間である』というのが成り立たない為、継承は使いません。
プログラム的に継承は使えますが意味が分からなくなるので使わないようにします。
リアルな世界で成立しているかどうかで判断すると良いようです。
今回の場合は特別に継承を使ってキャラクターステータスを作らなくても良いような気もしますが、色々試してみましょう。(-ω-)/
上の図では子クラスから親クラスへと矢印が向いていますが、これは子クラスは親クラスのフィールドや変数に入れることが出来るのでこの方向に矢印が向いています。
例えばBaseStatusクラスを継承してStatusAとStatusBクラスを作ったとします。
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 | using System.Collections; using System.Collections.Generic; using UnityEngine; public class Test : MonoBehaviour { // Start is called before the first frame update void Start() { BaseStatus[] baseStatus = new BaseStatus[2]; baseStatus[0] = new StatusA("StatusA", "頭突き"); baseStatus[1] = new StatusB("StatusB", "足蹴り"); foreach (var member in baseStatus) { Debug.Log(member.GetCharacterName()); Debug.Log(member.SpecialAttack()); } } class BaseStatus { private string characterName; private string specialAbilityName; public BaseStatus(string characterName, string specialAbilityName) { this.characterName = characterName; this.specialAbilityName = specialAbilityName; } public string GetCharacterName() { return characterName; } public virtual string SpecialAttack() { return specialAbilityName; } } class StatusA : BaseStatus { public StatusA(string characterName, string specialAttackName) : base(characterName, specialAttackName) { } public override string SpecialAttack() { return "これが俺の必殺技だ!" + base.SpecialAttack(); } } class StatusB : BaseStatus { public StatusB(string characterName, string specialAttackName) : base(characterName, specialAttackName) { } public override string SpecialAttack() { return "これが私の必殺技よ!" + base.SpecialAttack(); } } } |
上のようにBaseStatus型の変数にインスタンス化したStatusA、StatusBを入れることが出来ます。
BaseStatusではフィールドとコンストラクタ、特殊攻撃のメソッドを持っています。
SpecialAttackメソッドはvirtualを付け仮想メソッドとして定義し、子要素でoverrideされない場合は親クラスのSpecialAttackメソッドが実行されます。
StatusAとStatusBではoverrideでSpecialAttackメソッドを定義しているので子クラスのSpecialAttackメソッドが実行されます。
StatusAとStatusBではコンストラクタで受け取ったキャラクターの名前と、特殊攻撃の名前を:baseを使って親のコンストラクタにそのまま引数付きで渡しています。
StartメソッドではBaseStatus型の配列にStatusAとStatusBを入れているのでBaseStatusをforeachでループさせStatusAとStatusBのメソッドを呼び出せます。
同じSpecialAttackメソッドの呼び出しを行っていてもStatusAとStatusBでは実行する処理が違っています。
これを多態性と言います(実行するメソッドは同じでも違う振る舞いをする)。
継承や多態性についてはプログラムの書籍などを参照してみてください。(´Д`)
継承元のキャラクターデータを作成するスクリプトの作成
まずは継承元のCharacterStatusスクリプトを作成します。
CharacterStatusスクリプトはキャラクターが持っているべきフィールドとそれを設定・取得するメソッドを持つようにします。
Assets/RPG/Scripts/Statusフォルダ内に新しくCharacterStatusスクリプトを作成します。
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 | using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; [Serializable] public abstract class CharacterStatus : ScriptableObject { // キャラクターの名前 [SerializeField] private string characterName = ""; // 毒状態かどうか [SerializeField] private bool isPoisonState = false; // 痺れ状態かどうか [SerializeField] private bool isNumbnessState = false; // キャラクターのレベル [SerializeField] private int level = 1; // 最大HP [SerializeField] private int maxHp = 100; // HP [SerializeField] private int hp = 100; // 最大MP [SerializeField] private int maxMp = 50; // MP [SerializeField] private int mp = 50; // 素早さ [SerializeField] private int agility = 5; // 力 [SerializeField] private int power = 10; // 打たれ強さ [SerializeField] private int strikingStrength = 10; // 魔法力 [SerializeField] private int magicPower = 10; public void SetCharacterName(string characterName) { this.characterName = characterName; } public string GetCharacterName() { return characterName; } public void SetPoisonState(bool poisonFlag) { isPoisonState = poisonFlag; } public bool IsPoisonState() { return isPoisonState; } public void SetNumbness(bool numbnessFlag) { isNumbnessState = numbnessFlag; } public bool IsNumbnessState() { return isNumbnessState; } public void SetLevel(int level) { this.level = level; } public int GetLevel() { return level; } public void SetMaxHp(int hp) { this.maxHp = hp; } public int GetMaxHp() { return maxHp; } public void SetHp(int hp) { this.hp = Mathf.Max(0, Mathf.Min(GetMaxHp(), hp)); } public int GetHp() { return hp; } public void SetMaxMp(int mp) { this.maxMp = mp; } public int GetMaxMp() { return maxMp; } public void SetMp(int mp) { this.mp = Mathf.Max(0, Mathf.Min(GetMaxMp(), mp)); } public int GetMp() { return mp; } public void SetAgility(int agility) { this.agility = agility; } public int GetAgility() { return agility; } public void SetPower(int power) { this.power = power; } public int GetPower() { return power; } public void SetStrikingStrength(int strikingStrength) { this.strikingStrength = strikingStrength; } public int GetStrikingStrength() { return strikingStrength; } public void SetMagicPower(int magicPower) { this.magicPower = magicPower; } public int GetMagicPower() { return magicPower; } } |
非常にスクリプトが長いですが中で行っていることは単純です。
セッターやゲッターを容易するよりもプロパティとして作った方が楽かもしれません。
CharacterStatusスクリプトはScriptableObjectクラスを継承して作成し、
キャラクターが持っているべきステータスを保持し、それらの値を設定したり取得したりするメソッドが用意されているだけです。
SetHpとSetMpでは少し分かりずらい処理をしていますので、見ておきます。
1 2 3 4 5 | public void SetHp(int hp) { this.hp = Mathf.Max(0, Mathf.Min(GetMaxHp(), hp)); } |
SetHpでは引数で受け取ったhpをキャラクターのHPに入れる処理をしますが、まずキャラクター自身の最大HPと引数で受け取ったhpをMathf.Minで最小値を取得します。
これはHPに設定する値が最大HPを超えないようにする為です。
次に0とMathf.Minで取得した値をMathf.Maxで大きい方の値を取得します。
これは設定するHPが0より小さい値にならないようにする為の処理です。
SetMpでも同じことをしています。
クラス定義の前にアトリビュートを取り付けているので見ていきます。
1 2 3 4 | [Serializable] public abstract class CharacterStatus : ScriptableObject |
[Serializable]アトリビュートを取り付ける事で直列化(データ転送可)が可能なクラスとしています。
直列化が出来るとはバイト列に変換が出来るということです。
バイトとは8ビットの事で、1ビットは2進数(0か1)というコンピューターの最小単位の情報です。
つまり、データを0か1かの情報に変換してそれを送信して送信先で復元出来るようにする為に直列化をしています(たぶん)。
classの前にabstractを付けて抽象クラスにし、CharacterStatusクラス自体をインスタンス化出来ないようにします。
これはCharacterStatusクラスは継承に使う元のクラスであってCharacterStatusクラス自体をインスタンス化して使わせない為です。
今回の場合は別にインスタンス化しても問題はないですが、とりあえずCharacterStatus自体をインスタンス化出来ないようにしておきます。
キャラクターが持つステータスをフィールドとして用意し、それらにはSerializeFieldアトリビュートを付けインスペクタ上で設定出来るように直列化可能にしています。
アイテムデータの作成
アイテムは武器、鎧、HP回復アイテム、状態回復アイテム、貴重品などいくつか種類がありますのでアイテムの種類を選択出来るようにします。
Assets/RPG/Scripts/Itemフォルダに新しくItemスクリプトを作成します。
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 | using System; using System.Collections; using System.Collections.Generic; using UnityEngine; [Serializable] [CreateAssetMenu(fileName = "Item", menuName = "CreateItem")] public class Item : ScriptableObject { public enum Type { HPRecovery, MPRecovery, PoisonRecovery, NumbnessRecovery, WeaponAll, WeaponUnityChan, WeaponYuji, ArmorAll, ArmorUnityChan, ArmorYuji, Valuables } // アイテムの種類 [SerializeField] public Type itemType = Type.HPRecovery; // アイテムの漢字名 [SerializeField] private string kanjiName = ""; // アイテムの平仮名名 [SerializeField] private string hiraganaName = ""; // アイテム情報 [SerializeField] private string information = ""; // アイテムのパラメータ [SerializeField] private int amount = 0; // アイテムの種類を返す public Type GetItemType() { return itemType; } // アイテムの名前を返す public string GetKanjiName() { return kanjiName; } // アイテムの平仮名の名前を返す public string GetHiraganaName() { return hiraganaName; } // アイテム情報を返す public string GetInformation() { return information; } // アイテムの強さを返す public int GetAmount() { return amount; } } |
ItemクラスはScriptableObjectクラスを継承して作成します。
Typeはアイテムの種類を表します。
WeaponAllは誰でも装備出来る武器で、WeaponUnityChanはユニティちゃんしか装備出来ない武器です。
kanjiNameは漢字を含めたアイテムの名前でhiraganaNameは平仮名でのアイテム名を設定します。
なぜ二つのアイテム名を設定出来るようにしたかというと、複数のアイテムデータを取得する時に平仮名でアイテムデータをソートするのはそのまま出来ますが、漢字を含めると別に自分で実装しないとソートが出来ないからです。
Itemクラスでは漢字名、平仮名名、アイテムの情報、アイテムの強さというアイテムが持っているべき最低限の情報を持たせる事にしました。
アイテムクラスが出来たので、個々のアイテムを作成します。
データはそれぞれ異なるフォルダに作成します。
Assets/RPG/Data/ItemData/Armorに鎧のデータ
Assets/RPG/Data/ItemData/Recoveryに回復アイテムデータ
Assets/RPG/Data/ItemData/StateRecoveryに毒と痺れを回復するアイテムデータ
Assets/RPG/Data/ItemData/Valuablesに貴重品データ
Assets/RPG/Data/ItemData/Weaponに武器のデータ
個々のフォルダ内で右クリックからCreateItemを選択しデータを作成します。
上のようにデータを作成します。
継承先の味方のステータスを作成するスクリプトの作成
継承元のクラスCharacterStatusが出来たのでこれを継承し、味方のステータスファイルを作成するクラスを作ります。
Assets/RPG/Scripts/Statusフォルダ内にAllyStatusクラスを作成します。
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 | using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.UI; [Serializable] [CreateAssetMenu(fileName = "AllyStatus", menuName = "CreateAllyStatus")] public class AllyStatus : CharacterStatus { // 獲得経験値 [SerializeField] private int earnedExperience = 0; // 装備している武器 [SerializeField] private Item equipWeapon = null; // 装備している鎧 [SerializeField] private Item equipArmor = null; // アイテムと個数のDictionary [SerializeField] private ItemDictionary itemDictionary = null; public void SetEarnedExperience(int earnedExperience) { this.earnedExperience = earnedExperience; } public int GetEarnedExperience() { return earnedExperience; } public void SetEquipWeapon(Item weaponItem) { this.equipWeapon = weaponItem; } public Item GetEquipWeapon() { return equipWeapon; } public void SetEquipArmor(Item armorItem) { this.equipArmor = armorItem; } public Item GetEquipArmor() { return equipArmor; } public void CreateItemDictionary(ItemDictionary itemDictionary) { this.itemDictionary = itemDictionary; } public void SetItemDictionary(Item item, int num = 0) { itemDictionary.Add(item, num); } // アイテムが登録された順番のItemDictionaryを返す public ItemDictionary GetItemDictionary() { return itemDictionary; } // 平仮名の名前でソートしたItemDictionaryを返す public IOrderedEnumerable<KeyValuePair<Item, int>> GetSortItemDictionary() { return itemDictionary.OrderBy(item => item.Key.GetHiraganaName()); } public int SetItemNum(Item tempItem, int num) { return itemDictionary[tempItem] = num; } // アイテムの数を返す public int GetItemNum(Item item) { return itemDictionary[item]; } } |
アトリビュートでCreateAssetMenuを取り付けUnityのAssetメニューからAllyStatusクラスのファイルを作成する事が出来ます。
1 2 3 4 | [CreateAssetMenu(fileName = "AllyStatus", menuName = "CreateAllyStatus")] public class AllyStatus : CharacterStatus |
AllyStatusはCharacterStatusクラスを継承しているのでCharacterStatusクラスが持っているフィールドとメソッドを持っています。
味方が持つべきフィールドやメソッドを追加しています。
少し難しい処理をしている部分を見ていきます。
1 2 3 4 5 6 | // 平仮名の名前でソートしたItemDictionaryを返す public IOrderedEnumerable<KeyValuePair<Item, int>> GetSortItemDictionary() { return itemDictionary.OrderBy(item => item.Key.GetHiraganaName()); } |
GetSortItemDictionaryメソッドはキャラクターが保持しているアイテムのDictionaryデータをDictionaryのキーであるItemの平仮名の名前でソートをしたデータを返します。
アイテムデータを平仮名の順で並べ替えたデータを使いたい場合に使います。
OrderByの引数ではラムダ式を使って並べ替えの基準を指定しています。
itemDictionaryのキーであるItemクラスのGetHiraganaNameメソッドでそのアイテムの平仮名の名前を取得しそれを使ってソートしています。
OrderByメソッドで得られるのはIOrderdEnumerable<KeyValuePair<Item, int>>型になります。
ソートしたデータを取得しない場合はGetItemDictionaryメソッドを使います。
現時点ではItemDictionary型の部分でエラーが発生します。
ItemDictionaryのインスペクタでの表示
アイテムとその数はDictonaryクラスを使って(Dictionary<Item, int>)インスペクタで設定したいところですが、Dictionaryクラスの場合はキーと値が別々に表示されます。
例えばItemDictionaryではなくDictionaryでアイテム一覧を作った場合は以下のようになります。
(上の例ではデータが既に設定されていますが、通常はスクリプトで設定したデフォルト値が設定されているはずです)。
level、strikingStrength、magicPowerのパラメータが表示されてませんが、これは後でパラメータを加えたため画像を作る段階ではなかった為です。これ以降の画像も同様です。
そこでアセットストアで「SerializableDictionary」で検索して出てくるアセットをインポートします(無料のやつ)。
インポートしたらAssets/RPG/Scripts/Itemフォルダ内にItemDictionaryスクリプトを作成します。
1 2 3 4 5 6 7 8 9 10 11 | using System; using System.Collections; using System.Collections.Generic; using UnityEngine; [Serializable] public class ItemDictionary : SerializableDictionary<Item, int> { } |
ItemDictionaryクラスはSerializableDictionary
Assets/RPG内にEditorフォルダを作成しその中にSerializableDictionaryスクリプトを作成します。
1 2 3 4 5 6 7 8 9 10 11 | using System.Collections; using System.Collections.Generic; using UnityEditor; using UnityEngine; [CustomPropertyDrawer(typeof(ItemDictionary))] public class SerializableDictionary : SerializableDictionaryPropertyDrawer { } |
これでUnityChanStatusのItemDictionaryはキーにItem、値にそのアイテムの数が対応して表示されます。
キャラクターデータの作成
キャラクターデータを作成するスクリプトが出来たので、Assets/RPG/Data/Statusフォルダ内に移動し右クリックからCreateAllyStatusを選択します。
上の画像では他のユニティちゃんRPGデータの作成項目が出ていますが、これはわたくしの都合上出ているだけなのでその他の項目は表示されていないはずです。
CreateAllyStatusを選択するとAssets/RPG/Data/Statusフォルダ内にAllyStatusという名前のアセットファイルが作成されます。
AllyStatusファイルを選択した状態でF2キーを押し名前をUnityChanStatusと変更します。
同じようにもう一つAllyStatusファイルを作成し名前をYujiStatusと変更します。
ユニティちゃんとその仲間である大鳥ゆうじのステータスファイルが出来ました。
アイテムデータをUnityChanStatusやYujiStatusのEquipWeaponやEquipArmor、ItemDictionaryの右の+を押してアイテム欄を増やしアイテムをドラッグ&ドロップか◎を押して設定しておきます。
アイテムデータの保存先をフォルダ毎に分けたのでドラッグ&ドロップが出来なくなりますが、これを出来るようにする為にインスペクタをロックして行います。
UnityChanStatusデータにアイテムを設定する時はUnityChanStatusを選択し、インスペクタで鍵のマークを押します。
これでUnityChanStatusのインスペクタが固定された状態で他のフォルダに移動し武器のデータや鎧のデータが選択出来るので、それをドラッグ&ドロップします。
データを設定したらインスペクタの鍵のマークを押してロックを解除しておくことを忘れないでください。
でないとインスペクタにずっと同じゲームオブジェクトの情報が固定され、Unityが正常に動作しなくなった!?とパニックに陥る可能性がありますので・・・・(-_-)
今回はあらかじめユニティちゃんと大鳥ゆうじのステータスデータをアセットファイルに設定していますが、通常はゲーム開始時の値を設定しておき、CharacterStatusスクリプトのSetItemDictionaryメソッドを使って入手したアイテムを追加するようにします。
一つ注意が必要なのがこの記事の最初の方でも言及しましたが、キャラクターステータスやアイテムステータス等のアセットファイルの中身はゲームを終了したり、Unityエディター上でスクリプトで値を変化させてもゲームを終了したり、Unityエディターを閉じると元の値に戻ります。
単純にスクリプトから作成したインスタンスをファイルとして表示しているだけだからです(たぶん)。
なのでゲームのデータやロード機能を作る場合はPlayerPrefsを使ってレジストリにデータを保持しそれを読み込んだり、外部ファイルなどにデータを保存し再開する時に読みだす必要があります。
ここら辺は
を参照してみてください。
WebGL形式(ブラウザ)でのゲームの場合は外部ファイルが使えないので、サーバーにデータを保存出来るようにしたりする必要があります。
昔ながらのブラウザゲームのようにクッキーにデータ保存も出来るのかな?(-_-)
終わりに
今回はキャラクターのステータスとアイテムデータの作成をしました。
今回はアセットファイルとしてデータを作成しただけなので次回はキャラクターのステータスデータを取得して表示する機能を作成していきたいと思います。
この作品はユニティちゃんライセンス条項の元に提供されています