gpt4 book ai didi

c# - 在编辑器 session 之间存储编辑器值

转载 作者:行者123 更新时间:2023-12-05 02:12:00 25 4
gpt4 key购买 nike

我有以下创建自定义检查器窗口的 EditorWindow 脚本。在此窗口中按下按钮后,id 将递增 1。

static int id = 10000;

[MenuItem("Custom/CustomMenu")]
static void Init()
{
// Get existing open window or if none, make a new one:
CustomMenu window = (CustomMenu)EditorWindow.GetWindow(typeof(CustomMenu));
window.Show();
}

if (GUILayout.Button("someButton"))
{
id++;
Repaint();
EditorUtility.SetDirty(this);
}

这工作正常,但是当我启动播放模式或关闭 unity 编辑器时,id 的增量值丢失,并将重置回 10000。

使用 int id 的非静态版本将使该值在“播放” session 中持续存在,但一旦您关闭 unity 仍会丢失。

有没有办法在编辑器/unity session 之间存储这个值,类似于 playerprefs 但对于编辑器可能?

最佳答案

脚本对象

也许更像“统一”的方式是使用专用的 ScriptableObject (另见 Introduction to ScriptableObjects)

您可以将它与 [InitializeOnLoadMethod] 结合使用为了实现一个加载方法,该方法将在打开编辑器并重新编译以创建 ScriptableObject 一次后调用。

// we don't need the CreateAssetMenu attribute since the editor window
// will create the ScriptableObject once by itself
public class CustomMenuData : ScriptableObject
{
public int Id;
}

确保将其放在单独的脚本中。

public class CustomMenu : EditorWindow
{
// we can go privtae again ;)
private static CustomMenuData data;

// This method will be called on load or recompile
[InitializeOnLoadMethod]
private static void OnLoad()
{
// if no data exists yet create and reference a new instance
if (!data)
{
// as first option check if maybe there is an instance already
// and only the reference got lost
// won't work ofcourse if you moved it elsewhere ...
data = AssetDatabase.LoadAssetAtPath<CustomMenuData>("Assets/CustomMenuData.asset");

// if that was successful we are done
if(data) return;

// otherwise create and reference a new instance
data = CreateInstance<CustomMenuData>();

AssetDatabase.CreateAsset(data, "Assets/CustomMenuData.asset");
AssetDatabase.Refresh();
}
}

[MenuItem("Custom/CustomMenu")]
private static void Init()
{
// Get existing open window or if none, make a new one:
var window = (CustomMenu)EditorWindow.GetWindow(typeof(CustomMenu));

window.Show();
}

private void OnGUI()
{
// Note that going through the SerializedObject
// and SerilaizedProperties is the better way of doing this!
//
// Not only will Unity automatically handle the set dirty and saving
// but it also automatically adds Undo/Redo functionality!
var serializedObject = new SerializedObject(data);

// fetches the values of the real instance into the serialized one
serializedObject.Update();

// get the Id field
var id = serializedObject.FindProperty("Id");

// Use PropertyField as much as possible
// this automaticaly uses the correct layout depending on the type
// and automatically reads and stores the according value type
EditorGUILayout.PropertyField(id);

if (GUILayout.Button("someButton"))
{
// Only change the value throgh the serializedProperty
// unity marks it as dirty automatically
// also no Repaint required - it will be done .. guess .. automatically ;)
id.intValue += 1;
}

// finally write back all modified values into the real instance
serializedObject.ApplyModifiedProperties();
}
}

这样做的巨大优势:

  • 它比使用 FileIO 进行写入和保存更快/更有效,因为 Unity 会自动处理该 ScriptableObject 的(反)序列化。
  • 您不需要“手动”加载和保存数据。这是自动完成的,因为 ScriptableObject 的行为与任何其他预制件一样。
  • 您只需单击 Assets 中的 ScriptableObject 实例并直接更改值!

使用简单的文本文件

一个简单但不是那么有效的替代解决方案是将其存储到一个文件中,例如作为像这样的 JSON

using System.IO;
using UnityEditor;
using UnityEngine;

public class CustomMenu : EditorWindow
{
private const string FileName = "Example.txt";

// shorthand property for getting the filepath
public static string FilePath
{
get { return Path.Combine(Application.streamingAssetsPath, FileName); }
}

private static int id = 10000;

// Serialized backing field for storing the value
[SerializeField] private int _id;

[MenuItem("Custom/CustomMenu")]
static void Init()
{
// Get existing open window or if none, make a new one:
CustomMenu window = (CustomMenu)EditorWindow.GetWindow(typeof(CustomMenu));

if (File.Exists(FilePath))
{
// read the file content
var json = File.ReadAllText(FilePath)

// If the file exists deserialize the JSON and read in the values
// for only one value ofcourse this is overkill but for multiple values
// this is easier then parsing it "manually"
JsonUtility.FromJsonOverwrite(json, window);

// pass the values on into the static field(s)
id = window._id;
}

window.Show();
}

private void OnGUI()
{
id = EditorGUILayout.IntField(id);

if (GUILayout.Button("someButton"))
{
id++;
Repaint();
EditorUtility.SetDirty(this);

// do everything in oposide order
// first fetch the static value(s) into the serialized field(s)
_id = id;

// if not exists yet create the StreamingAssets folder
if (!Directory.Exists(Application.streamingAssetsPath))
{
AssetDatabase.CreateFolder("Assets", "StreamingAssets");
}

// serialize the values into json
var json = JsonUtility.ToJson(this);

// write into the file
File.WriteAllText(FilePath, json);

// reload the assets so the created file becomes visible
AssetDatabase.Refresh();
}
}
}

目前每次打开窗口时都会读取文件,每次单击按钮时都会写入文件。这仍然可以改进。

同样,您可以使用 [InitializeOnLoadMethod]为了只读取文件一次 - 即当您打开编辑器或重新编译时

public class CustomMenu : EditorWindow
{
// Instead of having the field values directly as static fields
// rather store the information in a proper serializable class
[Serializable]
private class CustomMenuData
{
public int Id;
}

// made this publlic for the saving process (see below)
public static readonly CustomMenuData data = new CustomMenuData();

// InitializeOnLoadMethod makes this method being called everytime
// you load the project in the editor or after re-compilation
[InitializeOnLoadMethod]
private static void OnLoad()
{
if (!File.Exists(FilePath)) return;

// read in the data from the json file
JsonUtility.FromJsonOverwrite(File.ReadAllText(FilePath), data);
}

...
}

为了优化保存并仅在您在 UnityEditor 中保存时执行文件写入,您可以实现专用的 AssetModificationProcessor喜欢

public class CustomMenuSaver : SaveAssetsProcessor
{
static string[] OnWillSaveAssets(string[] paths)
{
// do change nothing in the paths
// but additionally store the data in the file

// if not exists yet create the StreamingAssets folder
if (!Directory.Exists(Application.streamingAssetsPath))
{
AssetDatabase.CreateFolder("Assets", "StreamingAssets");
}

// serialize the values into json v That's why I made it public
var json = JsonUtility.ToJson(CustomMenu.data);

// write into the file v needs to be public as well
File.WriteAllText(CustomMenu.FilePath, json);

return paths;
}
}

关于c# - 在编辑器 session 之间存储编辑器值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56594340/

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