我目前在Unity中设置了两个脚本来处理一些UI音频。一个是经理,另一个是为特定的UI元素播放声音。我所拥有的简化版本是:
public class AudioUIManager : MonoBehaviour //Only one of these in the scene
{
public AudioClip genericUISound; //This is set in the inspector.
}
public class AudioUITextAnimation : MonoBehaviour
{
[SerializeField]
private AudioClip specifiedUISound; //This is not set in the inspector
[SerializeField]
private AudioUIManager audioUIManager; // I get a reference to this elsewhere
void Start()
{
//Use generic sounds from audio manager if nothing is specified.
specifiedUISound = specifiedUISound ?? audioUIManager.genericUISound;
print(specifiedUISound);
}
}
我在此尝试实现的是让specifiedUISound
字段使用在检查器中为其分配的声音。如果未分配声音,则使用UI管理器中的通用声音。这样可以节省我为需要相同声音的数百万个按钮分配相同的声音,但如果我愿意,我可以选择为一个按钮设置特定的声音。
然而,null-coalessing运算符将null
设置为specifiedUISound
,即使它为空并且audioUIManager
的声音不是即可。另外,如果我使用三元运算符来检查null,我可以使用它:
specifiedUISound = specifiedUIsound == null ? audioUIManager.genericUISound : specifiedUISound;
我是否误解了空合并运算符?为什么会这样?
编辑:Jerry Switalski指出,这只会在specifiedUISound
序列化时发生。 (如果是public
或者如果它具有[SerializeField]
属性)。任何人都可以了解这里发生的事情吗?
答案 0 :(得分:10)
你正在遇到Unity的custom equality operator:
当MonoBehaviour有字段时,仅在编辑器中,我们不会将这些字段设置为“真正的空”,而是设置为“假空”对象。我们的自定义==运算符能够检查某些东西是否是这些假的空对象之一,并且相应地表现。虽然这是一个奇特的设置,它允许我们将信息存储在假的null对象中,当您在其上调用方法时,或者当您向对象请求属性时,它会为您提供更多上下文信息。如果没有这个技巧,你只会得到一个NullReferenceException,一个堆栈跟踪,但是你不知道哪个GameObject有MonoBehaviour,那个字段是null。
在编辑器中运行时,Unity会将序列化的null
替换为实际上不是null
的标记值。这允许他们在某些情况下提供更多信息性的错误消息。
specifiedUISound
是否等于null
?这取决于你的要求。 C#有多个“平等”概念,包括data equality and reference equality。
有些检查会说值相等:==
和Object.Equals
其他人会说他们不平等:??
和Object.ReferenceEquals
此行为仅在编辑器中发生。在独立版本中运行时,任何null
值都只是null
。
答案 1 :(得分:2)
对于你的问题和非常有趣的例子,它并不是真正完整的答案,但我运行了一些测试,看起来问题出现在SerializeField
属性中。
当我运行此操作时(someObj
从检查员nullObj
分配为空):
public AudioClip someObj;
[SerializeField]
private AudioClip nullObj;
void Start ()
{
Debug.Log("nullObj == null : " + (nullObj == null));
Debug.Log("someObj == null : " + (someObj == null));
nullObj = nullObj ?? someObj;
Debug.Log ("nullObj == null : " + (nullObj == null));
}
我有这个版画:
然而,摆脱SerializeField
属性,使事情按预期工作:
public AudioClip someObj;
private AudioClip nullObj;
void Start ()
{
Debug.Log("nullObj == null : " + (nullObj == null));
Debug.Log("someObj == null : " + (someObj == null));
nullObj = nullObj ?? someObj;
Debug.Log ("nullObj == null : " + (nullObj == null));
}
给出:
重新说明:
我真的不知道问题的根源,但事实是Unity3D序列化字段会破坏Mono引擎中的空合并运算符。我仍然不知道如何,但可能只是因为改变了==
的seriazlized类型的运算符?
无论如何,我希望它至少有一点帮助。