【问题标题】:How to update a prefab property from editor script and have the instances get the updates?如何从编辑器脚本更新预制属性并让实例获取更新?
【发布时间】:2016-12-11 18:07:08
【问题描述】:

这是对this question的跟进

假设我有一个简单的 MonoBehaviour

public class FooScript : MonoBehaviour {
  public int someValue = 0;
  public int otherValue = 0;
}

我把它放在一个空的游戏对象上,然后将游戏对象拖到项目中以创建一个预制件。

如果我选择预制件并编辑 someValue,那么如果我转到仍在场景中的实例,我会看到 someValue 已更新。

如果我在实例上编辑someValue,那么更新预制件上的someValue someValue 不会在实例上更新,但如果我在预制件上更新otherValue,它会更新实例。换句话说,每个实例属性都有自己的标志,是否已从源预制件修改。

但是,如果我创建一个编辑器脚本并在预制件上查找FooScript 并设置someValue,则实例更新,只有预制件。我希望它的行为就像我在编辑器中手动完成一样。换句话说,如果实例属性已被用户编辑,则不要更新。如果实例属性尚未编辑,请更新。

问题是这样做的正确方法是什么?查看PrefabUtilily 似乎没有ApplyPropertiesFromSourcePrefabOnAllUnmodifiedInstancePropreties 函数。

我能想到的唯一解决方案听起来极度令人费解。我不得不

  1. 查找所有实例(遍历整个层次结构,不确定在未加载的场景中会发生什么)
  2. 通过调用PrefabUtility.GetPropertyModifications 并将结果存储在一些Dictionary<GameObject, PropertyModifications[]> 中,对每个实例记录进行修改。 (大量内存)
  3. 将我的更改应用到预制件。
  4. 然后,对于每个没有修改我正在更新的字段的实例,也要更新实例上的该属性。

真的那么复杂还是有更简单的方法?

【问题讨论】:

  • 如果你使用PrefabUtility.MergeAllPrefabInstances()会发生什么?
  • 令人惊讶的是这似乎有效,但文档说“这是自动完成的,您不必手动调用此函数。”这表明我应该这样做别的东西。呼叫尝试呼叫EditorUtilitiy.SaveDirty(prefabGameobject),这似乎更合适?
  • 你的意思是EditorUtility.SetDirty(Object)?该文档还说您不应该使用它。
  • 是的,我就是这个意思。我看不出它在哪里说不要调用它。实际上它说“例如,如果您修改 prefab 的 MonoBehaviour 或 ScriptableObject 变量,您必须告诉 Unity 该值已更改。
  • 引用文档:''在 Unity 5.3 之前,这是将对象标记为脏的主要方法。从 5.3 开始,随着多场景编辑的引入,该功能不再用于修改场景中的对象。相反,您应该在对对象进行更改之前使用 Undo.RecordObject。这会将对象的场景标记为脏,并在编辑器中提供一个撤消条目。''

标签: c# unity3d


【解决方案1】:

从文档浏览中,Unity 似乎希望您在修改预制件上的属性之前在代码中使用 Undo.RecordObject(Object objectToUndo, string name),这也将有利于在 Unity 本身中创建撤消步骤,以便您可以还原任何变化。

您可以使用 EditorUtility.SetDirty(Object),但前提是您不想创建撤消步骤,并且 Unity 文档特别建议不要这样做。

【讨论】:

  • 从文档看来EditorUtility.SetDirty 适合我的确切用例。我不是在修改场景中的对象,而是在修改不在场景中的 AssetDatabase 中的预制件。就像正常的预制模块行为一样,当预制本身发生变化时,不应撤消实例。
猜你喜欢
  • 2015-04-07
  • 1970-01-01
  • 1970-01-01
  • 2016-12-11
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多