2016-03-02 27 views
30

私はInvokeRepeating()を使ってゲームのメソッドを呼び出しています。 GameObjectクラスのうちの1つのStart()メソッドでInvokeRepeating()と呼びます。 InvokeRepeating()repeatRateパラメータを設定するには、secondsBetweenBombDropsという名前のパブリックフィールドを渡します。Unityが非静的パブリックフィールドの初期化された値を無視するのはなぜですか?

Unityが、私はコード内secondsBetweenBombDropsに指定した値を無視し、代わりにいくつかのデフォルト値を使用しています(つまり、1)secondsBetweenBombDropsがstatic修飾子なしで宣言されている場合:私はstatic修飾子を追加すると、

public float secondsBetweenBombDrops = 10f; 
void Start() { 
    InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops); 
} 

しかし、 secondsBetweenBombDrops予想通り、コードが動作し、10の正しい値が使用される:

public static float secondsBetweenBombDrops = 10f; 
void Start() { 
    InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops); 
} 

なぜこのフィールドは、適切な値を使用するstatic修飾子を必要ですか?

が1であることを、Unityインスペクタで示しています。このデフォルト値1は、ゲーム開始時にプレハブをインスタンス化するか、ゲームの実行中にプレハブインスタンスを作成するかどうかに関係なく存在します。

答えて

29

シリアライズの両刃の剣

Unityは、限られたコーディングの知識を持つ人(初心者、デザイナー)を含め、すべての人のために物事を簡単にしたいです。

Unityを支援するために、Unityはインスペクタにデータを表示します。これによりコーダはコードを作成し、設計者はMonoDevelop/IDEを開かずに値を微調整することで設計することができます。

値がインスペクタに表示持っている2つの方法があります。

public int myVar = 10; 
[SerializeField] private int myOtherVar = 0; // Can also be protected 

それはカプセル化の原則に準拠していますので、二番目が優れている(変数はプライベート/メソッドやプロパティを経由して保護され、修正されているが)。

エディタに変数を表示すると、スクリプトで指定された値はスクリプトをドラッグするときにのみ使用されます。 Unityはこれらの値をシリアライズし、スクリプトの変更はもう気にしません。たとえば、myVarが実際にスクリプト内で20に設定されている場合、混乱の原因になることがあります。使用されません。シリアライズはシーンファイルに書き込まれます。

例の2行は、まったく同じ方法で動作します。

可能な解決策

Unityがスクリプトコンポーネントの設定ホイールにリセットを押して、スクリプト内の新しい値を検討するために取得することが可能です。それはコンポーネントの他のすべての変数もリセットするので、意図した場合にのみ実行してください。

属性をプライベートにして[SerializeField]属性を省略すると、シリアライズ処理が無効になります。そのため、Unityはシーンファイルで表示する値を探しません。その代わりに値はスクリプトによって実行時に作成されます。

Unityにコンポーネントを追加すると、コンポーネントのタイプの新しいオブジェクトが作成されます。表示される値は、そのオブジェクトからのシリアル化された値です。このため、メンバー値は表示でき、静的変数は直列化できないため、表示できません。 (これは.NETの仕様であり、Unity固有のものではありません)Unity does not serialize static fieldsなので、static修飾子を追加すると問題が解決したようです。コメントに基づいて、OPの場合はOP

を説明する

、あなたのパブリックフィールドは、エディタの1の値を示しました。この値は、最初に宣言したときに実際にフィールドに付けた値であったときのデフォルト値であると考えました。スクリプトをコンポーネントとして追加した後は、値10を設定していて、まだ値1を使用していたのでバグだと思っていました。これで、うまく機能していることが分かりました。

Unityは何をシリアル化しますか?

デフォルトでは、Unityは文字列、配列、リスト、MonoBehaviourだけでなく、値の型(int、float、enumなど)を直列化して表示します。 (エディタのスクリプトでその外観を変更することが可能であるが、これは、オフトピックです。)

public class NonMonoBehaviourClass{ 
    public int myVar; 
} 

はデフォルトによってシリアライズされていません。ここでも、これは.NET仕様です。 Unityはエンジン要件の一部としてデフォルトでMonoBehaviourをシリアライズします(これにより、コンテンツがシーンファイルに保存されます)。エディタで「クラシック」クラスを表示したい場合は、ちょうどそう言う:明らか

[System.Serializable] 
public class NonMonoBehaviourClass{ 
    public int myVar = 10; 
} 

あなたはMonoBehaviour内で使用する必要があるので、あなたはゲームオブジェクトに追加することはできません。

public class MyScript:MonoBehaviour{ 
    public NonMonoBehaviourClass obj = new NonMonoBehaviourClass(); 
} 

これにより、オブジェクトがインスペクタに表示され、NonMonoBehaviourClassのインスタンスの変数myVarに変更を許可します。また、スクリプト内のmyVarへの変更は、値がシリアライズされてシーンに保存された後は考慮されません。ただメソッドとプロパティ - 彼らはすべての変数を含んでいないため、終了するには、インスペクタ

で物事を表示するに

余分なヒントは、インターフェイスは、いずれかのインスペクタに表示されません。デバッグモードでは、プロパティはデフォルトでは表示されません。このモードは、インスペクタの右上隅にある3行のボタンを使用して変更できます。最初の2つの設定はNormal/Debugです。最初のものはデフォルトのもので、2番目のものは私的な変数も表示します。これは値を見るのに便利ですが、エディタから変更することはできません。

インタフェースを表示する必要がある場合は、同様の機能(マルチ継承を除く)を提供する抽象クラスを考慮する必要がありますが、MonoBehaviourでもかまいません。

参考資料:この質問への徹底した答えを追加するための

http://docs.unity3d.com/ScriptReference/SerializeField.html

http://docs.unity3d.com/Manual/script-Serialization.html

https://www.youtube.com/watch?v=9gscwiS3xsU

https://www.youtube.com/watch?v=MmUT0ljrHNc

+0

ありがとう!私がMsYvetteの 'static 'を追加したことが問題を解決したように見えるというメモを付け加えれば幸いです。 – Serlite

+0

このような良い答えを書く時間をとってくれてありがとう!最終的に二重ターゲットを見つけたとしても、サイト上で必要な資産です。 –

+2

追加/変更は歓迎します。 – Everts

関連する問題