2016-03-02 39 views
30

我使用InvokeRepeating()來調用遊戲中的方法。我在GameObject類之一的Start()方法中調用InvokeRepeating()。要爲InvokeRepeating()設置repeatRate參數,我將其傳遞給名爲secondsBetweenBombDrops的公共字段。爲什麼Unity忽略非靜態公共字段的初始化值?

團結忽略我在代碼secondsBetweenBombDrops指定的值,而是使用了一些默認值(即1)當secondsBetweenBombDrops是一個沒有static修飾符聲明:

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

但是,一旦我的static修改添加到secondsBetweenBombDrops,代碼的行爲與預期和10的正確值用於:

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

爲什麼這個領域需要static修改使用適當的價值?

在Unity檢查器中,腳本組件顯示secondsBetweenBombDrops爲1.無論我是在遊戲開始時實例化預製還是在遊戲運行時創建預製實例,都存在默認值1。

回答

29

系列化的雙刃劍

團結想使事情更容易爲每個人,包括有限的人的編碼知識(初學者,設計師)。

爲了幫助他們,Unity在檢查器中顯示數據。這允許編碼器進行編碼,設計者可以通過調整值來設計,而無需打開MonoDevelop/IDE。

有兩種方法具有的值顯示在檢查:

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

第二個是較好的,因爲它與封裝原理符合(變量是私人/保護和通過方法或屬性修改)。

當您在編輯器中顯示變量時,腳本中給出的值僅在拖動腳本時使用。 Unity然後序列化這些值並且不再關心任何腳本修改。這可能導致混淆,例如,如果myVar在腳本內設置爲20之後,則不會使用。序列化被寫入場景文件中。

示例中的兩條線完全相同。

可能的解決方案

很可能得到統一按上的腳本組件的設置復位輪在腳本中要考慮新的價值。這也將重置該組件的所有其他變量,因此只有這樣做,如果這是有意的。

使變量private並忽略屬性[SerializeField]將禁用序列化過程,因此Unity將不再在場景文件中查找要顯示的值 - 而是將在運行時通過腳本創建值。

向Unity添加組件時,會創建組件類型的新對象。顯示的值是該對象的序列化值。因爲這個原因,只有成員值可以顯示,靜態變量不是,因爲它們是不可序列化的。 (這是一個.NET規範,並非嚴格針對Unity。)因爲Unity does not serialize static fields,這就是添加static修飾符似乎可以解決問題的原因。

在解釋OP

在OP情況下,基於的意見,你的公共領域顯示了在編輯器中的值爲1。你認爲這個值是一個默認的值,當它實際上是你最初在聲明它時最可能給這個字段的值。將腳本作爲組件添加後,您將值設爲10,並認爲它是錯誤的,因爲它仍然使用值1。現在應該明白,按照設計,它工作得很好。

Unity是什麼序列化?

默認情況下,Unity將序列化並顯示值類型(int,float,enum等)以及字符串,數組,List和MonoBehaviour。 (這是可以修改他們與編輯腳本的外觀,但是這是題外話。)

以下:

public class NonMonoBehaviourClass{ 
    public int myVar; 
} 

默認情況下不會序列化。這裏又是.NET規範。默認情況下,Unity將MonoBehaviour序列化爲引擎要求的一部分(這會將內容保存到場景文件中)。如果你想在編輯器中顯示一個「經典」類,只是這麼說:

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

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

很顯然,你不能這樣,你需要一個MonoBehaviour中使用添加到遊戲對象

這將在檢查器中顯示對象,並允許修改NonMonoBehaviourClass實例中的myVar變量。再次,在該值被串行化並存儲到場景之後,腳本內對myVar的任何更改都不會被考慮。

在檢查員

結束顯示的東西小竅門,接口沒有在檢查器中顯示無論是因爲它們不包含任何變量 - 只是方法和屬性。在調試模式下,默認情況下不顯示屬性。您可以使用Inspector右上角的三行按鈕來更改此模式。前兩個設置是普通/調試。第一個是默認的,第二個也會顯示私有變量。這對於觀察它們的值是有用的,但不能從編輯器中改變。所以如果你需要一個接口來顯示,你將不得不考慮一個抽象類,因爲它提供了一個類似的功能(除了多繼承),但可以是一個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

相關問題