访问自定义 Unity 编辑器的序列化列表对象 Window
Access Serialized List Object for Custom Unity Editor Window
我正在尝试创建自定义 EditorWindow
(TransporterToolKit.cs) -旅行积分。
我有一个GameObject
(TransporterSystem.cs,单身,经理:
有一个 LIST 子游戏对象,它们是节点(游戏对象快速移动点)。每个节点都有一个 Serializable TransporterLocation 来保存有关实际位置的详细信息。
我收到空对象错误:
NullReferenceException: Object reference not set to an instance of an
object
我是否正在运行游戏中使用我当前的TransporterToolKit.cs文件
如何访问节点列表以便获取它们的 Serializable
TransporterLocation?
EDITOW WINDOW:
我的问题是什么。
TransporterToolKit.cs
public class TransporterToolKit : EditorWindow {
[MenuItem("Project ToolKits/Transporter ToolKit")]
public static void ShowWindow() {
GetWindow<TransporterToolKit>("Transporter ToolKit");
}
public List<TransporterNode> nodes;
private void OnEnable() {
//ERROR COMES FROM THIS LINE
nodes = TransporterSystem.s_Instance.GetAllTransporterNodes();
}
private void OnGUI() {
GUILayout.Label("Transporter System", EditorStyles.boldLabel);
//Create a list of buttons with the location name
foreach (TransporterNode node in nodes) {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.BeginHorizontal();
if (GUILayout.Button(node.ThisLocation.locationName)) {
//Do something
}
GUILayout.EndHorizontal();
EditorGUILayout.EndVertical(); //end section outline
}
}
}
另一个类.
TransporterSystem.cs
public class TransporterSystem : Singleton<TransporterSystem> {
[Header("Transporter Nodes")]
[SerializeField]
private List<TransporterNode> nodeList;
public List<TransporterNode> GetAllTransporterNodes() {
return nodeList;
}
}
TransporterNode.cs
public class TransporterNode : MonoBehaviour {
[SerializeField]
private TransporterLocation thisLocation;
public TransporterLocation ThisLocation {
get {
return thisLocation;
}
set {
thisLocation = value;
}
void Awake() {
ThisLocation.locationName = gameObject.name;
ThisLocation.transporterLocation = transform.position;
}
}
TransporterNode.cs
public enum TRANSPORTER_NODE_STATE {
OFFLINE,
ONLINE
}
[Serializable]
public class TransporterLocation {
public Vector3 transporterLocation;
public TRANSPORTER_NODE_STATE locationState;
public string locationName;
public TransporterLocation() {
transporterLocation = Vector3.zero;
locationName = "NOT SET";
locationState = TRANSPORTER_NODE_STATE.OFFLINE;
}
}
看起来 s_Instance 为空。问题是,您在 EditorWindow 的 OnEnable 中请求 TransporterSystem 静态实例,但是,静态实例只会在播放模式期间设置为 Awake。 (至少这是我在我的项目中测试你的代码后的假设)。
我会通过在编辑器中主动搜索 TransporterSystem 来解决这个问题 window:
TransporterToolKit.cs
private void OnEnable()
{
TransporterSystem system = FindObjectOfType<TransporterSystem>();
if (system == null)
{
Debug.LogError("No TransporterSystem in scene.");
}
else
{
nodes = system.GetAllTransporterNodes();
}
}
或者,您也可以让您的单例实现变得惰性,类似于:
public class MonoSingleton
{
public static TransporterSystem instance
{
get
{
if (m_Instance == null)
m_Instance = Object.FindObjectOfType<TransporterSystem>();
if (m_Instance == null)
Debug.LogError("Unable to find TransporterSystem instance in scene.");
return m_Instance;
}
}
private static TransporterSystem m_Instance;
}
要解决节点仅在播放模式下更新的问题:
// Reset is called when the component is added to a GameObject or when Reset is selected from the inspector.
void Reset() {
#if UNITY_EDITOR
UnityEditor.Undo.RecordObject(gameObject, "Update LocationNode");
#endif
ThisLocation.locationName = gameObject.name;
ThisLocation.transporterLocation = transform.position;
}
您需要在编辑时分配值,而不是在 Awake 中分配值。最简单的示例是通过 Reset
回调(但您也可以从编辑器 window 或特殊按钮触发它)。重要的是,您不仅要设置值,还要将数据实际序列化到磁盘。这意味着,将场景标记为脏。 Unity推荐,使用Undo
class,不仅可以记录一个不可撤销的动作,还可以将场景设置为dirty。或者,您可以这样做:
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(gameObject.scene);
请注意,编辑器代码需要位于 Editor
文件夹中的文件中,或者被编译符号包围 UNITY_EDITOR
.
我正在尝试创建自定义 EditorWindow
(TransporterToolKit.cs) -旅行积分。
我有一个GameObject
(TransporterSystem.cs,单身,经理:
有一个 LIST 子游戏对象,它们是节点(游戏对象快速移动点)。每个节点都有一个 Serializable TransporterLocation 来保存有关实际位置的详细信息。
我收到空对象错误:
NullReferenceException: Object reference not set to an instance of an object
我是否正在运行游戏中使用我当前的TransporterToolKit.cs文件
如何访问节点列表以便获取它们的 Serializable
TransporterLocation?
EDITOW WINDOW:
我的问题是什么。
TransporterToolKit.cs
public class TransporterToolKit : EditorWindow {
[MenuItem("Project ToolKits/Transporter ToolKit")]
public static void ShowWindow() {
GetWindow<TransporterToolKit>("Transporter ToolKit");
}
public List<TransporterNode> nodes;
private void OnEnable() {
//ERROR COMES FROM THIS LINE
nodes = TransporterSystem.s_Instance.GetAllTransporterNodes();
}
private void OnGUI() {
GUILayout.Label("Transporter System", EditorStyles.boldLabel);
//Create a list of buttons with the location name
foreach (TransporterNode node in nodes) {
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
GUILayout.BeginHorizontal();
if (GUILayout.Button(node.ThisLocation.locationName)) {
//Do something
}
GUILayout.EndHorizontal();
EditorGUILayout.EndVertical(); //end section outline
}
}
}
另一个类.
TransporterSystem.cs
public class TransporterSystem : Singleton<TransporterSystem> {
[Header("Transporter Nodes")]
[SerializeField]
private List<TransporterNode> nodeList;
public List<TransporterNode> GetAllTransporterNodes() {
return nodeList;
}
}
TransporterNode.cs
public class TransporterNode : MonoBehaviour {
[SerializeField]
private TransporterLocation thisLocation;
public TransporterLocation ThisLocation {
get {
return thisLocation;
}
set {
thisLocation = value;
}
void Awake() {
ThisLocation.locationName = gameObject.name;
ThisLocation.transporterLocation = transform.position;
}
}
TransporterNode.cs
public enum TRANSPORTER_NODE_STATE {
OFFLINE,
ONLINE
}
[Serializable]
public class TransporterLocation {
public Vector3 transporterLocation;
public TRANSPORTER_NODE_STATE locationState;
public string locationName;
public TransporterLocation() {
transporterLocation = Vector3.zero;
locationName = "NOT SET";
locationState = TRANSPORTER_NODE_STATE.OFFLINE;
}
}
看起来 s_Instance 为空。问题是,您在 EditorWindow 的 OnEnable 中请求 TransporterSystem 静态实例,但是,静态实例只会在播放模式期间设置为 Awake。 (至少这是我在我的项目中测试你的代码后的假设)。
我会通过在编辑器中主动搜索 TransporterSystem 来解决这个问题 window:
TransporterToolKit.cs
private void OnEnable()
{
TransporterSystem system = FindObjectOfType<TransporterSystem>();
if (system == null)
{
Debug.LogError("No TransporterSystem in scene.");
}
else
{
nodes = system.GetAllTransporterNodes();
}
}
或者,您也可以让您的单例实现变得惰性,类似于:
public class MonoSingleton
{
public static TransporterSystem instance
{
get
{
if (m_Instance == null)
m_Instance = Object.FindObjectOfType<TransporterSystem>();
if (m_Instance == null)
Debug.LogError("Unable to find TransporterSystem instance in scene.");
return m_Instance;
}
}
private static TransporterSystem m_Instance;
}
要解决节点仅在播放模式下更新的问题:
// Reset is called when the component is added to a GameObject or when Reset is selected from the inspector.
void Reset() {
#if UNITY_EDITOR
UnityEditor.Undo.RecordObject(gameObject, "Update LocationNode");
#endif
ThisLocation.locationName = gameObject.name;
ThisLocation.transporterLocation = transform.position;
}
您需要在编辑时分配值,而不是在 Awake 中分配值。最简单的示例是通过 Reset
回调(但您也可以从编辑器 window 或特殊按钮触发它)。重要的是,您不仅要设置值,还要将数据实际序列化到磁盘。这意味着,将场景标记为脏。 Unity推荐,使用Undo
class,不仅可以记录一个不可撤销的动作,还可以将场景设置为dirty。或者,您可以这样做:
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(gameObject.scene);
请注意,编辑器代码需要位于 Editor
文件夹中的文件中,或者被编译符号包围 UNITY_EDITOR
.