如何在“编辑器”窗口中编辑和持久化可序列化资产?

阿列克谢·希曼斯基(Alexey Shimansky)

我的项目中保存了一个资产,它代表可序列化的可脚本编写对象该对象的代码很简单:

using UnityEngine;
using System.Collections;

public class TestScriptable : ScriptableObject {   
    public float gravity = .3f;
    public float plinkingDelay = .1f;
    public float storedExecutionDelay = .3f;    
}

在检查器中更改此对象的值没有问题,并且更改确实会保留并在退出→进入Unity后仍然存在

在此处输入图片说明

我试图模仿检查员的行为Editor Window但是,我对所做的任何更改Editor Window(虽然反映在中Inspector)都不会持续存在。这是Editor文件夹中的两个脚本

第一个(辅助)脚本-该脚本用按钮替换了检查器字段(请参见上图),该按钮调用了我的custom EditorWindow

using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(TestScriptable))]
public class TestScriptableEditor : Editor {
  public override void OnInspectorGUI() {
    if (GUILayout.Button("Open TestScriptableEditor"))
      TestScriptableEditorWindow.Init();
  }
}

在此处输入图片说明

第二个(有我的问题)-脚本,我尝试在其中更改资产值:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.Linq;


public class TestScriptableEditorWindow : EditorWindow {
    public static TestScriptableEditorWindow testScriptableEditorWindow;
    private TestScriptable testScriptable;

    [MenuItem("Window/TestTaskIceCat/TestScriptableEditor")]
    public static void Init() {
        // initialize window, show it, set the properties
        testScriptableEditorWindow = GetWindow<TestScriptableEditorWindow>(false, "TestScriptableEditorWindow", true);
        testScriptableEditorWindow.Show();
        testScriptableEditorWindow.Populate();
    }

    // initialization of my troubled asset              
    void Populate() {
        Object[] selection = Selection.GetFiltered(typeof(TestScriptable), SelectionMode.Assets);        
        if (selection.Length > 0) {
            if (selection[0] == null)
                return;

            testScriptable = (TestScriptable)selection[0];
        }
    }

    public void OnGUI() {
        if (testScriptable == null) {
            /* certain actions if my asset is null */
            return;
        }

        // Here is my tries to change values
        testScriptable.gravity = EditorGUILayout.FloatField("Gravity:", testScriptable.gravity);
        testScriptable.plinkingDelay = EditorGUILayout.FloatField("Plinking Delay:", testScriptable.plinkingDelay);
        testScriptable.storedExecutionDelay = EditorGUILayout.FloatField("Stored Execution Delay:", testScriptable.storedExecutionDelay);
        // End of the region of change values
    }    

    void OnSelectionChange() { Populate(); Repaint(); }
    void OnEnable() { Populate(); }
    void OnFocus() { Populate(); }

}

我的问题是:我在做什么错?可能是什么问题呢?如何解决?我是否在编辑器窗口中错误地加载资产?要不然是啥?任何帮助/想法,将不胜感激。

阿列克谢·希曼斯基(Alexey Shimansky)

好吧,一切都是简单而复杂的,并且同时又变得简单。

尽管检查器发生了视觉上的变化-这并不意味着数据实际上已更改。看起来一切正常,但是...我认为这是Unity的缺点

为了正常工作,您应该使用一些东西:

  • GUI.changed-如果任何控件更改了输入数据的值,则返回true。我们将使用它进行更改检测。
  • Undo.RecordObject-在RecordObject函数之后记录对对象所做的任何更改。Undo state被记录下来,让您使用恢复的变化Undo系统。
  • EditorUtility.SetDirty!!!!!!!!最重要的事情!)-不久:将目标对象标记为“脏”,因此需要保存。有关更多信息,请单击链接。

现在,我们需要做的就是在OnGUI()方法的底部编写一些代码

if (GUI.changed) {
    // writing changes of the testScriptable into Undo
    Undo.RecordObject(testScriptable, "Test Scriptable Editor Modify"); 
    // mark the testScriptable object as "dirty" and save it
    EditorUtility.SetDirty(testScriptable); 
}

即您的代码将是这样的:

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.Linq;


public class TestScriptableEditorWindow : EditorWindow {
	public static TestScriptableEditorWindow testScriptableEditorWindow;
	private TestScriptable testScriptable;

	[MenuItem("Window/TestTaskIceCat/TestScriptableEditor")]
	public static void Init() {
		// initialize window, show it, set the properties
		testScriptableEditorWindow = GetWindow<TestScriptableEditorWindow>(false, "TestScriptableEditorWindow", true);
		testScriptableEditorWindow.Show();
		testScriptableEditorWindow.Populate();
	}

	// initialization of troubled asset	
	void Populate() {
		Object[] selection = Selection.GetFiltered(typeof(TestScriptable), SelectionMode.Assets);        
		if (selection.Length > 0) {
			if (selection[0] == null)
				return;

			testScriptable = (TestScriptable)selection[0];
		}
	}

	public void OnGUI() {
		if (testScriptable == null) {
			/* certain actions if my asset is null */
			return;
		}

		testScriptable.gravity = EditorGUILayout.FloatField("Gravity:", testScriptable.gravity);
		testScriptable.plinkingDelay = EditorGUILayout.FloatField("Plinking Delay:", testScriptable.plinkingDelay);
		testScriptable.storedExecutionDelay = EditorGUILayout.FloatField("Stored Execution Delay:", testScriptable.storedExecutionDelay);
		
		// Magic of the data saving
		if (GUI.changed) {
			// writing changes of the testScriptable into Undo
			Undo.RecordObject(testScriptable, "Test Scriptable Editor Modify");
			// mark the testScriptable object as "dirty" and save it
			EditorUtility.SetDirty(testScriptable); 
		}
	}    
		
	void OnSelectionChange() { Populate(); Repaint(); }
	void OnEnable() { Populate(); }
	void OnFocus() { Populate(); }
}

就这样。这很简单。


现在,故事的复杂部分...

SetDirty-肯定不错。但是,此功能将在Unity> 5.3的版本中弃用。并且在某些版本中也会将其删除。什么时候?我不知道。除了使用之外,SetDirty您还可以使用另一种方法:

您应该在两次调用之间执行自定义Editor或EditorWindow中的所有操作:

serializedObject.Update()

// Here is some of your code

serializedObject.ApplyModifiedProperties()

该代码包含:

最后四个就像SetDirty::它们会将修改后的对象(或场景)标记为“脏”并Undo states为您创建

因此,知道了这一点,我们可以获得以下内容:

using UnityEngine;
using UnityEditor;

public class TestScriptableEditorWindow : EditorWindow {
    public static TestScriptableEditorWindow testScriptableEditorWindow;
    private TestScriptable testScriptable;
    // declaring our serializable object, that we are working on
    private SerializedObject serializedObj;

    [MenuItem("Window/TestTaskIceCat/TestScriptableEditor")]
    public static void Init() {
        testScriptableEditorWindow = GetWindow<TestScriptableEditorWindow>(false, "TestScriptableEditorWindow", true);
        testScriptableEditorWindow.Show();
        testScriptableEditorWindow.Populate();
    }

    // initialization of troubled asset
    void Populate() {
        Object[] selection = Selection.GetFiltered(typeof(TestScriptable), SelectionMode.Assets);
        if (selection.Length > 0) {
            if (selection[0] == null)
                return;

            testScriptable = (TestScriptable)selection[0];
            // initialization of the serializedObj, that we are working on
            serializedObj = new SerializedObject(testScriptable);
        }
    }

    // our manipulation
    public void OnGUI() {
        if (testScriptable == null) {
            /* certain actions if my asset is null */
            return;
        }

        // Starting our manipulation
        // We're doing this before property rendering           
        serializedObj.Update();
        // Gets the property of our asset and скуфеу a field with its value
        EditorGUILayout.PropertyField(serializedObj.FindProperty("gravity"), new GUIContent("Gravity"), true);
        EditorGUILayout.PropertyField(serializedObj.FindProperty("plinkingDelay"), new GUIContent("Plinking Delay"), true);
        EditorGUILayout.PropertyField(serializedObj.FindProperty("storedExecutionDelay"), new GUIContent("Stored Execution Delay"), true);
        // Apply changes
        serializedObj.ApplyModifiedProperties();
    }

    void OnSelectionChange() { Populate(); Repaint(); }
    void OnEnable() { Populate(); }
    void OnFocus() { Populate(); }
}

所以,这很简单,因为您应该只使用

Update→动作→ ApplyModifiedProperties

但它是复杂的,因为你应该做了很多工作,有一大堆财产类:FindPropertyPropertyFieldи SerializedProperty

但是,当您了解它的工作原理时-它变得如此简单...

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在Visual Studio编辑器窗口中隐藏或显示自定义边距

来自分类Dev

如何在“图表编辑器”窗口中为用户创建的新按钮提供父项?

来自分类Dev

如何在 Unity 编辑器窗口中正确绘制预览缩略图?

来自分类Dev

如何在Slickgrid中正确使用格式化程序和编辑器

来自分类Dev

如何在Atom编辑器中的其他选项卡而不是新窗口中打开新文件?

来自分类Dev

如何使用PUT方法编辑序列化数据

来自分类Dev

Ace 编辑器和最小化文件

来自分类Dev

如何在弹出窗口中编辑html?

来自分类Dev

Rails编辑序列化的JSON数据

来自分类Dev

如何激活Android本地化文件编辑器

来自分类Dev

ExtJS - 如何最小化行编辑器的高度?

来自分类Dev

如何在Sublime Text编辑器中格式化代码

来自分类Dev

如何在MATLAB编辑器中重新格式化代码?

来自分类Dev

如何在MATLAB编辑器中重新格式化代码?

来自分类Dev

如何在Vim编辑器中制作参数化的命令映射

来自分类Dev

动态实例化QuillJS编辑器

来自分类Dev

如何在Sagemaker 2中使用序列化器和反序列化器

来自分类Dev

如何在Power Query中格式化日期?(Microsoft Excel 2016-查询编辑器-高级编辑器?)

来自分类Dev

如何在Power Query中格式化日期?(Microsoft Excel 2016-查询编辑器-高级编辑器?)

来自分类Dev

Jqgird:如何在编辑对话框窗口中获取“取消格式化”单元格值

来自分类Dev

如何在Unity3d自定义编辑器窗口中为垂直GUILayout添加背景图像

来自分类Dev

如何在Visual Studio 2013中隐藏除编辑器窗口以外的所有窗口?

来自分类Dev

如何在Visual Studio 2013中隐藏除编辑器窗口以外的所有窗口?

来自分类Dev

如何在Atom编辑器中进行多行编辑?

来自分类Dev

如何在Spring集成中忽略序列化器/反序列化器?

来自分类Dev

如何在同一序列化器中使用嵌套序列化器?

来自分类Dev

如何在Progress 11.6 AppBuilder的部分编辑器和过程编辑器中获取语法突出显示

来自分类Dev

为什么在Visual Studio编辑器中得到“可本地化的字符串”?

来自分类Dev

如何在同一页面上初始化两个Draftjs编辑器?

Related 相关文章

  1. 1

    如何在Visual Studio编辑器窗口中隐藏或显示自定义边距

  2. 2

    如何在“图表编辑器”窗口中为用户创建的新按钮提供父项?

  3. 3

    如何在 Unity 编辑器窗口中正确绘制预览缩略图?

  4. 4

    如何在Slickgrid中正确使用格式化程序和编辑器

  5. 5

    如何在Atom编辑器中的其他选项卡而不是新窗口中打开新文件?

  6. 6

    如何使用PUT方法编辑序列化数据

  7. 7

    Ace 编辑器和最小化文件

  8. 8

    如何在弹出窗口中编辑html?

  9. 9

    Rails编辑序列化的JSON数据

  10. 10

    如何激活Android本地化文件编辑器

  11. 11

    ExtJS - 如何最小化行编辑器的高度?

  12. 12

    如何在Sublime Text编辑器中格式化代码

  13. 13

    如何在MATLAB编辑器中重新格式化代码?

  14. 14

    如何在MATLAB编辑器中重新格式化代码?

  15. 15

    如何在Vim编辑器中制作参数化的命令映射

  16. 16

    动态实例化QuillJS编辑器

  17. 17

    如何在Sagemaker 2中使用序列化器和反序列化器

  18. 18

    如何在Power Query中格式化日期?(Microsoft Excel 2016-查询编辑器-高级编辑器?)

  19. 19

    如何在Power Query中格式化日期?(Microsoft Excel 2016-查询编辑器-高级编辑器?)

  20. 20

    Jqgird:如何在编辑对话框窗口中获取“取消格式化”单元格值

  21. 21

    如何在Unity3d自定义编辑器窗口中为垂直GUILayout添加背景图像

  22. 22

    如何在Visual Studio 2013中隐藏除编辑器窗口以外的所有窗口?

  23. 23

    如何在Visual Studio 2013中隐藏除编辑器窗口以外的所有窗口?

  24. 24

    如何在Atom编辑器中进行多行编辑?

  25. 25

    如何在Spring集成中忽略序列化器/反序列化器?

  26. 26

    如何在同一序列化器中使用嵌套序列化器?

  27. 27

    如何在Progress 11.6 AppBuilder的部分编辑器和过程编辑器中获取语法突出显示

  28. 28

    为什么在Visual Studio编辑器中得到“可本地化的字符串”?

  29. 29

    如何在同一页面上初始化两个Draftjs编辑器?

热门标签

归档