gpt4 book ai didi

c# - 为什么 Unity 会忽略非静态公共(public)字段的初始化值?

转载 作者:IT王子 更新时间:2023-10-29 04:01:25 26 4
gpt4 key购买 nike

我正在使用 InvokeRepeating() 在游戏中调用方法。我打电话InvokeRepeating()Start()方法之一GameObject类。设置 repeatRate InvokeRepeating() 的参数,我正在传递一个名为 secondsBetweenBombDrops 的公共(public)字段.

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

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。

最佳答案

连载的双刃剑

Unity 希望让每个人都更轻松,包括编码知识有限的人(初学者、设计师)。

为了帮助他们,Unity 在检查器中显示数据。这允许编码人员编码和设计人员通过调整值进行设计,而无需打开 MonoDevelop/IDE。

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

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

第二个更好,因为它符合封装原则(变量是私有(private)的/ protected ,并通过方法或属性进行修改)。

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

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

可能的解决方案

通过按脚本组件的设置轮上的重置,可以让 Unity 考虑脚本中的新值。这也将重置组件的所有其他变量,因此仅在有意时才执行此操作。

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

向 Unity 添加组件时,会创建该组件类型的新对象。显示的值是来自该对象的序列化值。因此,只能显示成员值而不能显示静态变量,因为它们不可序列化。 (这是一个 .NET 规范,并非严格特定于 Unity。)因为 Unity does not serialize static fields ,这就是为什么添加 static修改器似乎解决了这个问题。

解释 OP

在 OP 案例中,根据评论,您的公共(public)字段在编辑器中显示的值为 1。您认为该值是默认值,但实际上它是您最初声明字段时最有可能提供给该字段的值。在您将脚本作为组件添加后,您将值设为 10,并认为它有问题,因为它仍在使用值 1。您现在应该明白它按照设计运行得很好。

Unity 序列化了什么?

默认情况下,Unity 将序列化和显示值类型(int、float、enum 等)以及字符串、数组、List 和 MonoBehaviour。 (可以使用编辑器脚本修改它们的外观,但这是题外话。)

下列:
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();
}

这将在检查器中显示对象并允许修改 myVar NonMonoBehaviourClass 实例中的变量.同样,对 myVar 的任何更改将值序列化并存储到场景后,将不考虑脚本内的值。

在检查器中显示内容的额外提示

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

因此,如果您需要显示一个界面,则必须考虑一个抽象类,因为它提供了类似的功能(多继承除外),但可以是 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

关于c# - 为什么 Unity 会忽略非静态公共(public)字段的初始化值?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35744405/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com