请阅读整个问题,然后在发布答案前运行示例。
在静态编辑器脚本中加载嵌套资源时,我在Unity 5.6.1中遇到了一些不一致的行为(所以在标有[InitializeOnLoad]
的类的静态构造函数中)。
我正在使用ScriptableObject
加载Resources.Load
资产,并且ScriptableObject具有对另一资产资源的公开引用,我们假设一个GameObject Prefab。从这一点开始,我将ScriptableObject称为' Wrapper',因为在这个简化的例子中,它是它所服务的唯一目的。
当Resources.Load
正确返回Wrapper时,嵌套的Prefab引用通常在第一次运行期间尚未加载,但在第二次运行后加载:
根据我的理解,这是一个执行问题的顺序,其中有问题的Prefab资源在静态构建期间尚未加载,并且在后续运行中它仍然被缓存。
我假设在加载具有对另一个资产的序列化引用的资产时,默认情况下将自动加载嵌套资产,无论这是否在静态init期间。然而,这似乎并非如此。
证明Wrapper资产确实在其序列化数据中正确引用了预制件(使用Asset Serialization set to Force Text):
我也尝试使用AssetDAtabase.LoadAssetAtPath
(至少在编辑器中),这没有什么区别。
您可以下载UnityPackage here,其中包含以下内容:
或者按如下方式重现:
脚本:
ExampleWrapper.cs:
using UnityEngine; public class ExampleWrapper : ScriptableObject { public GameObject Value; }
StaticLoader.cs:
using UnityEngine; #if UNITY_EDITOR using UnityEditor; [InitializeOnLoad] #endif public class Loader { static Loader() { var Wrapper = Resources.Load<ExampleWrapper>("Wrapper"); Debug.Log(Wrapper); // Prints the Wrapper ScriptableObject Debug.Log(Wrapper.Value); // Prints the Wrapped GameObject } }
创建一个空的&#34; ExampleObject&#34;层次结构中的GameObject,然后将其另存为预制件Assets/Resources/ExampleObject.prefab
在Assets/Resources/Wrapper.asset
请注意,因为有时Unity会正确缓存资产,
此处的示例是有意简化的,但它基于使用ScriptableObjects
存储/共享自定义系统配置数据的实际项目。
请不要回复以下内容:
Object.Instantiate
&#34; - 不会更改结果,并且在某些情况下修改Resources.Load
返回的原始对象是可取的。< / LI>
[InitializeOnLoad]
?)并使用基于ScriptableObjects的资产存储这种系统的配置信息是一个非常真实的用例。在完全重新构建系统之前,我想看看其他可能的替代方案。我我寻找:
Resources.Load<GameObject>("ExampleObject")
,因为这样做会否定首先将其封装起来的全部内容。我可以修改ExampleWrapper
类,但任何可能的解决方案都需要足够自动化,以便在检查器中将预制件添加到字段中的工作流程就足够了。编辑:还应该注意到,奇怪的是,当我关闭项目并再次打开它时,我看到以下内容:
这个,我真的不明白。
答案 0 :(得分:3)
对你的问题存在误解。
引用 传递给Loader
类,您可以在场景初始化完成后通过记录Wrapper.Value
来检查它。
最有可能的问题是(正如你所指出的)在执行/序列化顺序中,显然它会发生这样的事情:
Loader
构造函数,并正确传递Wrapper
引用。Debug.Log(Wrapper.Value)
返回null
,因为脚本化对象的字段尚未序列化Wrapper
的字段已序列化,现在正在显示Wrapper.Value
正确显示ExampleObject
。因此,除非您计划在初始化期间对Wrapper
字段执行“特殊”操作,否则您的代码中确实没有问题:我试图在{{1}期间运行Debug.Log(Loader.Wrapper.Value)
} OnEnable
,我得到了正确的值。
关于您的修改,显然它是“按设计”发生的,正如本期中明确说明的那样:https://issuetracker.unity3d.com/issues/unityeditor-dot-initializeonload-calls-the-constructor-twice-when-the-editor-opens