C# 为什么Unity会忽略非静态公共字段的初始化值?

C# 为什么Unity会忽略非静态公共字段的初始化值?,c#,serialization,unity3d,access-modifiers,C#,Serialization,Unity3d,Access Modifiers,我在游戏中调用一个方法。我在一个GameObject类的Start()方法中调用invokeerepeating()。要为invokererepeating()设置repeatRate参数,我将向其传递一个名为secondsbetween bombdrops的公共字段 Unity忽略我在代码中为secondsBetweenBombDrops指定的值,而是在声明secondsBetweenBombDrops时使用一些默认值(即1): public float secondsBetweenBombD

我在游戏中调用一个方法。我在一个
GameObject
类的
Start()
方法中调用
invokeerepeating()
。要为
invokererepeating()
设置
repeatRate
参数,我将向其传递一个名为
secondsbetween bombdrops
的公共字段

Unity忽略我在代码中为
secondsBetweenBombDrops
指定的值,而是在声明
secondsBetweenBombDrops
时使用一些默认值(即1):

public float secondsBetweenBombDrops = 10f;
void Start() {
    InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops);
}
但是,一旦我将
static
修饰符添加到bombdrops之间的
seconds,代码的行为将与预期的一样,并使用正确的值10:

public static float secondsBetweenBombDrops = 10f;
void Start() {
    InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops);
}
为什么此字段要求
静态
修饰符使用适当的值

在Unity inspector中,脚本组件显示bombdrops之间的
secondsbetween
为1。无论我是在游戏开始时实例化预置,还是在游戏运行时创建预置实例,都会出现默认值1。

序列化的双刃剑 Unity希望让每个人都能更轻松,包括编码知识有限的人(初学者、设计师)

为了帮助他们,Unity在inspector中显示数据。这允许程序员通过调整值进行编码,而设计师则通过调整值进行设计,而无需打开MonoDevelop/IDE

有两种方法可以在检查器中显示值:

public int myVar = 10;
[SerializeField] private int myOtherVar = 0; // Can also be protected
第二个更好,因为它符合封装原则(变量是私有的/受保护的,并通过方法或属性进行修改)

在编辑器中显示变量时,脚本中给定的值仅在拖动脚本时使用。Unity然后序列化这些值,不再关心任何脚本修改。例如,如果脚本中的
myVar
被设置为20,那么这可能会导致混淆,因为它将不被使用。序列化将写入场景文件中

示例中的两行的工作方式完全相同

可能的解决方案 可以通过在脚本组件的设置轮上按下重置来获得一个脚本中的新值。这也将重置组件的所有其他变量,因此仅在需要时才执行此操作

将变量设为private并省略属性
[SerializeField]
将禁用序列化过程,因此Unity将不再在场景文件中查找要显示的值,而是在运行时由脚本创建该值

向Unity添加组件时,将创建组件类型的新对象。显示的值是该对象的序列化值。因此,只能显示成员值,不能显示静态变量,因为它们不可序列化。(这是一个.NET规范,不是严格针对Unity的。)因为,这就是为什么添加
static
修饰符似乎可以解决问题的原因

解释OP 在OP案例中,根据注释,您的公共字段在编辑器中显示的值为1。您认为该值是默认值,而实际上它是您在最初声明字段时最有可能赋予该字段的值。将脚本添加为组件后,将值设为10,并认为它有问题,因为它仍然使用值1。你现在应该明白,它工作得很好,就像设计的那样

Unity系列化了什么? 默认情况下,Unity将序列化和显示值类型(int、float、enum等)以及字符串、数组、列表和MonoBehavior。(可以使用编辑器脚本修改它们的外观,但这与主题无关。)

以下是:

public class NonMonoBehaviourClass{
   public int myVar;
}
默认情况下不会序列化。这里再次说明,这是.NET规范。Unity默认情况下将MonoBehavior序列化为引擎要求的一部分(这将把内容保存到场景文件中)。如果您希望在编辑器中显示“classic”类,只需这样说:

[System.Serializable]
public class NonMonoBehaviourClass{
   public int myVar = 10;
}
显然,您无法将其添加到游戏对象中,因此需要在MonoBehavior中使用:

public class MyScript:MonoBehaviour{
     public NonMonoBehaviourClass obj = new NonMonoBehaviourClass();
}
这将在检查器中显示对象,并允许修改
非单调行为类
实例中的
myVar
变量。同样,在将值序列化并存储到场景中后,脚本中对
myVar
的任何更改都不会被考虑

关于在inspector中显示内容的额外提示 最后,接口也不会显示在inspector中,因为它们不包含任何变量,只包含方法和属性。在调试模式下,默认情况下不显示属性。您可以使用Inspector右上角有三行的按钮更改此模式。前两个设置为正常/调试。第一个是默认值,第二个也将显示私有变量。这对于查看它们的值很有用,但不能从编辑器中更改

因此,如果需要显示一个接口,就必须考虑一个抽象类,因为它提供了类似的功能(除了多继承),但可以是单行为。 参考资料:


感谢您为这个问题添加了完整的答案!希望您不介意我添加一条说明,说明为什么MsYvette添加的
static
似乎解决了这个问题。您能提供unity文档的链接吗?从哪里获得这些信息?哪部分?因为在大多数情况下,你可以看到它自己运行的引擎。对于序列化部分,我在末尾添加了一些链接。其中一个视频涉及可编写脚本的对象,但在开始时触及了主题。