2016-03-02 64 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

相关问题