Unityを使った3Dゲームの作り方(かめくめ)Unityを使った3Dゲームの作り方(かめくめ)ゲーム開発エンジンUnityを使った3Dゲームの制作に参考になる情報を公開しています。0今回はユニティちゃんのRPGで使用するアイテムやステータス等のデータの作成についてやっていきたいと思います。この記事から後のいくつかの記事はアイテムやステータスのデータを使ってコマンド画面での処理を作っていく事になるので少し難しいというか処理が複雑になってきます。細かい部分の説明は入れているつもりですが、難しいのは否めません。単純にわたくしのやり方が複雑にしている可能性もありますが・・・、わたくしのやり方がベストプラクティスではないのでより最適でわかりやすいやり方を模索してみてください。前回はユニティちゃんの操作をゲームコントローラーで出来るようにしました。ユニティちゃんのRPGを作ってみよう8ーゲームコントローラーに対応するーユニティちゃんのRPGでゲームコントローラー(PS3コントローラーやPS4コントローラー)でゲームの操作が出来るようにしていきます。Unityを使った3Dゲームの作り方(かめくめ)ユニティちゃんの3DRPGを作っていくカテゴリです。gametukurikata.comから見ることが出来ます。スポンサーリンクアイテムやステータスのデータ管理をどうするか?まずは最初にアイテムやステータスのデータをどうやって取り扱うかを考えます。アイテムやステータスのデータは簡単に言えばテキストの集まりなので、外部ファイルにアイテムデータやステータスデータを保持して置き、必要に応じてそれらのデータを取得したり書き換えたりする事で実現出来ます。外部ファイルの読み込みや書き込みをするとなるとファイル操作が必要になるので慣れていない人には難しいところです。外部ファイルにデータを保存するのではなくゲーム中にデータを保持しているクラスをインスタンス化してそこからデータの取得、書き換えをする方法もあります。この場合はC#スクリプトをMonoBehaviourクラスを継承してクラスを作成するのではなく、objectクラスを継承する形でクラスを作成するか何も継承しない(デフォルトでobjectクラスを継承する事になる)形でクラスを作成する必要があります。この場合はゲーム実行開始とともにクラスをインスタンス化しデータを取得したり書き換えたりすることは出来ますが、スクリプトの中にデータの情報を入れる必要があります。その他、MonoBehaviourクラスを継承してクラスを作成し、その中でデータを保持しておき何らかのゲームオブジェクトに取り付けて利用する方法もあります。この方法でもアイテムやステータスのデータは扱えますが、視覚的に分かり辛いというのがあります。そんな時に便利なのがUnityのScriptableObjectです。クラスをScriptableObjectクラスを継承して作成すると予めそのクラスをアセットファイルとしてファイル形式にしておくことが出来るので、ゲーム開始前からデータファイルとして存在させることが出来ます。ScriptableObjectクラスを継承しなくてもデータの取り扱いは出来ますが、それらのデータを視覚的に確認するにはスクリプトの中身を見る必要があり実際のデータはゲームが開始するまで作成されません。ScriptableObjectクラスを継承してクラスを作成すると存在するアセットファイルとしてそのデータを取り扱う事が出来るのでゲーム開始前にデータをセットし視覚的にわかりやすくなります。注意が必要なのがScriptableObjectクラスから作成したアセットファイルは視覚的に確認出来るアセットファイルとして存在しますが、エディターを開きなおしたりゲームをやめたあと再び再開した時は初期値に戻ります。これは元のデータをインスタンス化して視覚化しているのがアセットファイルで次回開いた時はインスタンス化するところから始まっているからなのかも?データを次回以降にも持ち越すにはScriptableObjectから作ったアセットファイルのデータを外部ファイル等に保存する必要があります(これは別の記事でやります)。ScriptableObjectについてはUnityのScriptableObjectを使うUnityのScriptableObjectを使うと、メモリの節約が出来たり、シーン間の移動でデータを共有するのが簡単になります。この記事では基本だけを記述しています。22:32上の記事を参照してください。ScriptableObjectはシーン間の遷移をする時にも使っています。ユニティちゃんのRPGを作ってみよう7ーワールドマップの作成とシーン間の遷移ーユニティちゃんのRPGでワールドマップシーンの作成とワールドマップシーンと村のシーンの移動が出来るようにしていきます。15:37これらの事を考慮してアイテムやステータス等の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クラスを作ったとします。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スクリプトを作成します。magicPower;}}非常にスクリプトが長いですが中で行っていることは単純です。セッターやゲッターを容易するよりもプロパティとして作った方が楽かもしれません。CharacterStatusスクリプトはScriptableObjectクラスを継承して作成し、キャラクターが持っているべきステータスを保持し、それらの値を設定したり取得したりするメソッドが用意されているだけです。SetHpとSetMpでは少し分かりずらい処理をしていますので、見ておきます。hp));}SetHpでは引数で受け取ったhpをキャラクターのHPに入れる処理をしますが、まずキャラクター自身の最大HPと引数で受け取ったhpをMathf.Minで最小値を取得します。これはHPに設定する値が最大HPを超えないようにする為です。次に0とMathf.Minで取得した値をMathf.Maxで大きい方の値を取得します。これは設定するHPが0より小さい値にならないようにする為の処理です。SetMpでも同じことをしています。クラス定義の前にアトリビュートを取り付けているので見ていきます。ScriptableObject[Serializable]アトリビュートを取り付ける事で直列化(データ転送可)が可能なクラスとしています。直列化が出来るとはバイト列に変換が出来るということです。バイトとは8ビットの事で、1ビットは2進数(0か1)というコンピューターの最小単位の情報です。データを0か1かの情報に変換してそれを送信して送信先で復元出来るようにする為に直列化をしています(たぶん)。classの前にabstractを付けて抽象クラスにし、CharacterStatusクラス自体をインスタンス化出来ないようにします。これはCharacterStatusクラスは継承に使う元のクラスであってCharacterStatusクラス自体をインスタンス化して使わせない為です。今回の場合は別にインスタンス化しても問題はないですが、とりあえずCharacterStatus自体をインスタンス化出来ないようにしておきます。キャラクターが持つステータスをフィールドとして用意し、それらにはSerializeFieldアトリビュートを付けインスペクタ上で設定出来るように直列化可能にしています。継承元のクラスCharacterStatusが出来たのでこれを継承し、味方のステータスファイルを作成するクラスを作ります。Assets/RPG/Scripts/Statusフォルダ内にAllyStatusクラスを作成します。itemDictionary[item];}}アトリビュートでCreateAssetMenuを取り付けUnityのAssetメニューからAllyStatusクラスのファイルを作成する事が出来ます。CharacterStatusAllyStatusはCharacterStatusクラスを継承しているのでCharacterStatusクラスが持っているフィールドとメソッドを持っています。味方が持つべきフィールドやメソッドを追加しています。難しい処理をしている部分を見ていきます。item.Key.GetHiraganaName());}GetSortItemDictionaryメソッドはキャラクターが保持しているアイテムのDictionaryデータをDictionaryのキーであるItemの平仮名の名前でソートをしたデータを返します。アイテムデータを平仮名の順で並べ替えたデータを使いたい場合に使います。OrderByの引数ではラムダ式を使って並べ替えの基準を指定しています。itemDictionaryのキーであるItemクラスのGetHiraganaNameメソッドでそのアイテムの平仮名の名前を取得しそれを使ってソートしています。C#でデリゲートとラムダ式を使ってみるC#のデリゲートとラムダ式をUnity付属のMonoDevelopで使用してみます。int>>型になります。ソートしたデータを取得しない場合はGetItemDictionaryメソッドを使います。キャラクターデータの作成キャラクターデータを作成するスクリプトが出来たので、Assets/RPG/Data/Statusフォルダ内に移動し右クリックからCreateAllyStatusを選択します。上の画像では他のユニティちゃんRPGデータの作成項目が出ていますが、これはわたくしの都合上出ているだけなのでその他の項目は表示されていないはずです。CreateAllyStatusを選択するとAssets/RPG/Data/Statusフォルダ内にAllyStatusという名前のアセットファイルが作成されます。AllyStatusファイルを選択した状態でF2キーを押し名前をUnityChanStatusと変更します。同じようにもう一つAllyStatusファイルを作成し名前をYujiStatusと変更します。int>)インスペクタで設定したいところですが、Dictionaryクラスの場合はキーと値が別々に表示されます。(上の例ではデータが既に設定されていますが、通常はスクリプトで設定したデフォルト値が設定されているはずです)。level、strikingStrength、magicPowerのパラメータが表示されてませんが、これは後でパラメータを加えたため画像を作る段階ではなかった為です。これ以降の画像も同様です。そこでアセットストアで「SerializableDictionary」で検索して出てくるアセットをインポートします(無料のやつ)。インポートしたらAssets/RPG/Scripts/Itemフォルダ内にItemDictionaryスクリプトを作成します。{}ItemDictionaryクラスはSerializableDictionaryを継承して作成します。Assets/RPG内にEditorフォルダを作成しその中にSerializableDictionaryスクリプトを作成します。{}これでUnityChanStatusのItemDictionaryはキーにItem、値にそのアイテムの数が対応して表示されます。ユニティちゃんとその仲間である大鳥ゆうじのステータスファイルが出来ましたが、装備する武器や鎧、持っているアイテム等はまだ作っていないのでそれらを作っていきます。アイテムデータの作成これからアイテムデータを作成していきますが、やり方としてはキャラクターデータの作成と同じようにスクリプトを作成しUnityのAssetメニューからそのデータを作成します。アイテムは武器、鎧、HP回復アイテム、状態回復アイテム、貴重品などいくつか種類がありますのでアイテムの種類を選択出来るようにします。amount;}}ItemクラスはScriptableObjectクラスを継承して作成します。Typeはアイテムの種類を表します。WeaponAllは誰でも装備出来る武器で、WeaponUnityChanはユニティちゃんしか装備出来ない武器です。kanjiNameは漢字を含めたアイテムの名前でhiraganaNameは平仮名でのアイテム名を設定します。二つのアイテム名を設定出来るようにしたかというと、複数のアイテムデータを取得する時に平仮名でアイテムデータをソートするのはそのまま出来ますが、漢字を含めると別に自分で実装しないとソートが出来ないからです。アイテムの情報、アイテムの強さというアイテムが持っているべき最低限の情報を持たせる事にしました。アイテムクラスが出来たので、個々のアイテムを作成します。データはそれぞれ異なるフォルダに作成します。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を選択しデータを作成します。上のようにデータを作成し、UnityChanStatusやYujiStatusのEquipWeaponやEquipArmor、ItemDictionaryにアイテムをドラッグ&ドロップか◎を押して設定しておきます。アイテムデータの保存先をフォルダ毎に分けたのでドラッグ&ドロップが出来なくなりますが、これを出来るようにする為にインスペクタをロックして行います。UnityChanStatusデータにアイテムを設定する時はUnityChanStatusを選択し、インスペクタで鍵のマークを押します。これでUnityChanStatusのインスペクタが固定された状態で他のフォルダに移動し武器のデータや鎧のデータが選択出来るので、それをドラッグ&ドロップします。データを設定したらインスペクタの鍵のマークを押してロックを解除しておくことを忘れないでください。ないとインスペクタにずっと同じゲームオブジェクトの情報が固定され、Unityが正常に動作しなくなった!?とパニックに陥る可能性がありますので・・・・(-_-)今回はあらかじめユニティちゃんと大鳥ゆうじのステータスデータをアセットファイルに設定していますが、通常はゲーム開始時の値を設定しておき、CharacterStatusスクリプトのSetItemDictionaryメソッドを使って入手したアイテムを追加するようにします。一つ注意が必要なのがこの記事の最初の方でも言及しましたが、キャラクターステータスやアイテムステータス等のアセットファイルの中身はゲームを終了したり、Unityエディター上でスクリプトで値を変化させてもゲームを終了したり、Unityエディターを閉じると元の値に戻ります。単純にスクリプトから作成したインスタンスをファイルとして表示しているだけだからです(たぶん)。ゲームのデータやロード機能を作る場合はPlayerPrefsを使ってレジストリにデータを保持しそれを読み込んだり、外部ファイルなどにデータを保存し再開する時に読みだす必要があります。ここら辺はUnityでゲームデータのセーブ・ロードを行う方法Unityのゲームで進行具合やキャラクターのステータスをデータとして保存しておき、それらのデータを読みだして続きから再開するというのは必須の機能になっています。その為に今回はゲームデータのセーブとロードが出来るようにしてみたいと思います。23:19を参照してみてください。WebGL形式(ブラウザ)でのゲームの場合は外部ファイルが使えないので、サーバーにデータを保存出来るようにしたりする必要があります。昔ながらのブラウザゲームのようにクッキーにデータ保存も出来るのかな?(-_-)終わりに今回はキャラクターのステータスとアイテムデータの作成をしました。今回はアセットファイルとしてデータを作成しただけなので次回はキャラクターのステータスデータを取得して表示する機能を作成していきたいと思います。コメントをキャンセルメールアドレスが公開されることはありません。コメントデータの処理方法の詳細はこちらをご覧ください。サイト内検索が出来ますプロフィール管理人のかめくめちゃんです。(-_-)メールはこちらにお願いします(記事への質問はコメント欄にお願いいたします)。kamekumechan@gmail.comいずれはSIRENやバイオハザードみたいなアクションゲームを作りたいと思っています。ゲームシナリオが書けないので面白いゲームはなかなか作れません・・・・。(^_^;)名前の由来はカメが好きだからです。プロフィールになってないな・・・・(-.-)Unityをこれから始める人へこれからUnityを使ってみようという方はUnityを使った3Dゲームの作り方(かめくめ)の歩き方Unityを使った3Dゲームの作り方(かめくめ)で、はじめてUnityの学習をする時の当ブログの記事を読む順番を書きました。21:43の記事に記載の順番で見て頂くとUnityの基本的な使い方がわかり、簡単なTPSゲームの作成までが出来ます。かめくめちゃんが今遊んでいるゲーム零をまたやりたくなったので最初からやり直し。WiiUのもやりたいので本体と一緒に買うしかないなぁ・・・。お知らせ2020/02/21個人的にUnity2019.3.2f1をインストールしました。2020/01/31個人的にUnity2020.1.0a21(アルファ版)をインストールしました。2018/08/07コメント欄へのわたくしの返信は停止しております。わたくしに出来る事は既に記事にしてあるので、ブログ右上の検索窓を活用してください。(._.)またブログの最初の方の機能を積み上げていく記事に関しての疑問点は当ブログ記事のスクリプトの説明と寄せられた質問への回答Unityを使った3Dゲームの作り方(かめくめ)の機能積み上げ形式の記事のスクリプトの説明と寄せられた記事の機能についての質問への回答を掲載しています。21:41も参照してみてください。コメントの返信はありませんが、回答は記事に反映されている可能性があります。当ブログはハイスピードプランです。WordPressの編集画面の動作が早くなった。Unityを使った3Dゲームの作り方(かめくめ).。