質問するログイン新規登録
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

2052閲覧

【Unity】[C#]インスペクターやプロパティ 値の設定、取得方法のコードについて

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/07/09 04:01

0

0

前提・実現したいこと

UnityでRPGを作成しようと思っています。
値の設定方法等を調べていくうちに
「インスペクターで設定をすると共同作業者に変えられる場合がある」とか
「どこで値が変わったのか追いづらいのでやめたほうが良い」とかいろんな情報を見かけました。
後からHPなり色々変更するのは大変な作業になると思うため、
なるべく今から一番良い状況でコードを書いていきたいと思っています。
クラスやら色々とごっちゃになってしまっているという自覚はあります…。
以下コードで問題なく参照ができるのかどうか、判断頂けないでしょうか。

該当のソースコード

参考:https://qiita.com/RyotaMurohoshi/items/b64b36009ba652b21e2c
インスペクターで値も設定したいけど,プロパティを使いたい。めんどくさいのも嫌!

C#

1[値を設定する側] 2 3//Personというclassに記載している設定にしました。 4class Person 5 { 6 [SerializeField] 7 private int level; 8 public int Level { 9 get { return level; } 10 private set { level = value; } 11 } 12}

levelがプログラム上でのみ利用するもので
Levelがインスペクターで設定したものでしょうか?

[利用する側の想定]
載っていなかったので、想定になります。

C#

1//プロパティ上から100レベルに設定している? 2Person player = new Person(Level=100);

C#

1//これだとインスペクターの値を取得できる? 2Person player = new Person(); 3Debug.Log (string.Format ("{0}",player.Level));

試したこと

インスペクターとプロパティで変更できるコードについては調べました。
しかし、参照方法については基本的な事だからか記載がありません。
PCが不調の為、明日にならないとテストは出来なさそうです。
明日自分でも試行錯誤する予定です。
上記だと、エラーが出るのだろうと思うのですが
どのように組めば良いのか分からない状況になっています。
大変申し訳ありませんが、回答のほどよろしくお願いいたします。

補足情報(FW/ツールのバージョンなど)

Unity 2018.3.0f2
VisualStudio 2019
Windows10

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

BluOxy

2019/07/09 04:21

「私ならこうする」と一方的に答える事は簡単ですが、それがtarokoさんにとって最適なものだとは限りません。tarokoさんにとって「一番良い状況」とは何でしょう。 もしかして、「インスペクターで設定をすると共同作業者に変えられる場合がある」とか「どこで値が変わったのか追いづらいのでやめたほうが良い」とかをされないような手段であれば良いということでしょうか。
退会済みユーザー

退会済みユーザー

2019/07/09 06:22 編集

BluOxy様 質問頂きありがとうございます。 複数人でゲームを作成していく予定ですので、一番良い状況としては 見やすいソースになっていることや、急な仕様変更や仕様追加があっても対応しやすい汎用性の高いものでしょうか。バグがあった際に、値の変化を追いやすいということも重要だと思っています。 変更したい値のみインスペクターで作業できるようにし、それ以外のものはクラスにカプセル化?して分かりやすくまとめたいという気持ちがあります。 たぶん、C#をしっかり勉強すれば分かることなのだと思いますが、 書籍を数種類持っているのですがカプセル化などについてはあまり詳細に書いておらず分かっていないので、その辺でごちゃごちゃしているのだと思います。
guest

回答2

0

質問の意図が良く分からないので、質問の回答になっているか怪しいですが、突っ込みどころがあるので記載します。
(たぶん、BluOxyさんの回答のほうが、質問の意図に近いような気もします)

まず、PersonにMonoBehaviourが継承されていません。
そうしないと、ゲームオブジェクトにアタッチすることが出来ません。
アタッチ出来ないということは、インスペクターから設定することも不可能なため、インスペクターとは全く縁のないことになります。

ただ、MonoBehaviourを継承したクラスをnewすることは、普通はしません。
代わりにInstantiate()を使います。
もし、newしたいクラスなのであれば、MonoBehaviourの関数などが使えなくなりますが、MonoBehaviourを継承しない、という判断もあり得ます。

levelがプログラム上でのみ利用するもので
Levelがインスペクターで設定したものでしょうか?

MonoBehaviourを継承した前提で話を進めますが、この場合は逆になります。
levelは変数で、Levelはプログラム上からlevelを変更するためのものです。
また、levelは[SerializeField]によって、インスペクターから変更できるようになっています。
そのlevelはprivateになっており、値を別のクラス上から変更することはできなくなっております。
よって、Levelはプログラム上で利用するもので、インスペクターで設定するのはlevel(の初期値)といった具合になります。

このプロパティを参照したい場合は(Personを代入している変数をpersonとすると)person.Levelとすればよいです。

なお、あえてプロパティを使わない場合は、以下のような感じになります。

C#

1 [SerializeField] 2 private int level; 3 4 public int getLevel() 5 { 6 return level; 7 } 8 private void setLevel(int value) 9 { 10 level = value; 11 }

この場合だと、get~()やset~()と関数を呼び出さないといけないので、やや面倒です。
それを簡略化したのがプロパティだと思ってください。

投稿2019/07/09 04:41

fiveHundred

総合スコア10466

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/07/09 06:57

fiveHundred様 回答ありがとうございます。 「PersonにMonoBehaviourが継承されていません」 あぁあ、仰るとおりです。忘れておりました。 Levelの説明をとても丁寧に記載頂きありがとうございます! 複雑で頭がこんがらがったりもしましたが、 [SerializeField]の下の行はインスペクタ表示、 privateは変更不可、Publicは変更可能というのはきっちり理解できました。 level = value; のvalueはどこから出てきたのかというのが分かりませんが、それはたぶんC#の基礎知識なのでしょう。勉強してきます。 また、色々教えていただいているうちに、結局 ・インスペクタに表示する必要があるのか? ・外部CSにまとめてカプセル化などして分かりやすく管理する? など考えはじめてしまったので、少し整理したいと思います。
guest

0

ベストアンサー

例えばPerson playerをパブリックなメンバーで定義した場合は、インスペクタ上で中の値を設定することができます。

C#

1public class Script : MonoBehavior{ 2 public Person player; 3}

そして、外部スクリプトから変更を加えることもできます。

C#

1public class OtherScript : MonoBehavior{ 2 private Script s; 3 void Start(){ 4 s = GetComponent<Script>(); 5 s.player = new Person(){Level = 32}; 6 } 7}

上記のように書けてしまうことが

「インスペクターで設定をすると共同作業者に変えられる場合がある」とか
「どこで値が変わったのか追いづらいのでやめたほうが良い」

と言われている所以だと思います。

解決策として一番単純な方法はパブリックではなくプライベートなメンバーで定義することです。

C#

1public class Script : MonoBehavior{ 2 private Person player = new Person(); 3}

このように書くとインスペクタ上からは見えなくなり、外部スクリプトから値を取ることもできなくなります。

この、publicprivateといったキーワードはアクセス修飾子と言われており、C#の機能の一つです。

privateをつけることで、クラス内部からのみアクセス可能になりますから、下記のように書くことができます。

C#

1public class Script : MonoBehavior{ 2 private Person player = new Person(); 3 void Start(){ 4 //Scriptクラス内部からはアクセス可能 5 player.Level = 32; 6 } 7}

このように書く事でScriptクラスに定義されているplayerというメンバーがどのように変更されるかは、Scriptクラスしか知らなくなるため、「外部から変えられたくない値をインスペクターで設定できてしまう」「どこで値が変わったのか追いづらい」と言った問題を回避することができます。

余談ですが、SerializeFieldという属性をprivateなメンバーに付与することでインスペクタ上から見ることもできます。ですが、外部から弄られたくないのであれば使う必要はありません。

投稿2019/07/09 04:37

編集2019/07/09 04:40
BluOxy

総合スコア2663

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/07/09 06:47

BluOxy様、回答ありがとうございます! 具体例も出して頂き、わかりやすいです。じっくり読み込もうと思います。 また、「SerializeFieldという属性をprivateなメンバーに付与することでインスペクタ上から見ることもできます」とコメント頂きましたが レベルデザインのためにHPや経験値をインスペクタ上から急に参照したくなった場合は、[SerializeField]と宣言すれば使えるという事でしょうか。 それであれば、自分が利用する場合のみ追記して、インスペクタで作業すれば良い気もしてきました。
BluOxy

2019/07/09 07:10 編集

>レベルデザインのためにHPや経験値をインスペクタ上から急に参照したくなった場合は、[SerializeField]と宣言すれば使えるという事でしょうか。 その認識で問題ないと思います。 こういった記事( https://qiita.com/makopo/items/8ef280b00f1cc18aec91 )もあるので参考にどうぞ。
退会済みユーザー

退会済みユーザー

2019/07/10 12:33

BluOxy様 丁寧にありがとうございます! 参考サイトまでいただいて、本当にありがたいです。 しっかり読み込んで理解したいと思います!ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.30%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問