我正在尝试使用游戏快速旅行点的按钮创建自定义EditorWindow
( TransporterToolKit.cs )。
我有一个GameObject
( TransporterSystem.cs ,一个单身人士,经理):
具有 LIST 的子游戏对象是节点(GameObjects快速旅行点)。每个节点都有一个 Serializable TransporterLocation ,其中包含有关实际位置的详细信息。
我得到空对象错误:
NullReferenceException:未将对象引用设置为的实例 对象
我是否正在使用我当前的 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;
}
}
答案 0 :(得分:1)
看起来s_Instance为null。问题是,您要求在EditorWindow的OnEnable中使用TransporterSystem静态实例,但是,静态实例仅在播放模式下设置为Awake。 (至少这是我在项目中测试代码后的假设)。
我会通过在编辑器窗口中主动搜索TransporterSystem来解决这个问题:
<强> 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
回调(但您可以从编辑器窗口或特殊按钮触发它)。重要的是,您不仅要设置值,还要将数据序列化到磁盘。这意味着,将场景标记为脏。 Unity建议,使用Undo
类不仅可以记录可撤消的操作,还可以将场景设置为脏。或者,您可以这样做:
UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(gameObject.scene);
请注意,编辑器代码需要位于Editor
文件夹中的文件中,或者由编译符号UNITY_EDITOR
包围。