c# - 如何从脚本在 Unity 中创建窗口并将其附加到现有选项卡?

标签 c# unity-game-engine reflection unity-editor unity3d-editor

我正在尝试为 Unity 制作一个自定义编辑器脚本,但我陷入了我认为是一个简单的步骤。 使用 UnityEditor.GetWindow() 时,窗口不会在主选项卡中打开,而是作为单独的窗口打开。 The scene view is not attached to the main Unity window.

我尝试了一些解决方法,但似乎都不起作用:

  • 首先,我尝试使用 API 中的desiredDockNextTo 参数。 ,但我不断收到无法修复的错误。

      Type inspWndType = typeof(Editor).Assembly.GetType("UnityEditor.SceneView");
    
     EditorWindow[] allWindows = Resources.FindObjectsOfTypeAll<EditorWindow>();
     Type[] insWindTypeList = new Type[allWindows.Length];
     for(int i = 0; i < allWindows.Length; i++)
     {
         insWindTypeList[i] = allWindows[i].GetType();
     }
     var window = EditorWindow.GetWindow<typeof(inspWndType)>(insWindTypeList);
    

我一直在 中收到错误,说它是一个变量而不是类型(我也尝试过使用 inspWndType.gettype 或转换它,但没有任何效果)。

TLDR:我希望能够使用 EditorWindow.GetWindow() 创建一个窗口并将其从脚本中停靠。

感谢任何可以帮助我的人。

最佳答案

首先,typeof 需要编译时常量类型而不是动态变量。

所以如果有什么应该是例如

var inspWndType = typeof(UnityEditor.SceneView);

但是,第二个问题:您不能将其作为泛型类型参数。

您想要做的是假设您的编辑器窗口看起来像例如

public class YOURWINDOW : EditorWindow
{
    ...
}

那么应该是

var inspWndType = typeof(UnityEditor.SceneView);
var window = EditorWindow.GetWindow<YOURWINDOW>(inspWndType);

这里不需要反射,因为您不想处理任何运行时类型,并且 UnityEditor.SceneView 无论如何都是公共(public)的。


示例:

using System;
using UnityEditor;

public class ExampleWindow : EditorWindow
{
    [MenuItem("Examples/ExampleWindow")]
    private static void Init()
    {
        var inspWndType = typeof(SceneView);
        var window = GetWindow<ExampleWindow>(inspWndType);
    }

    private void OnGUI()
    {
        EditorGUILayout.LabelField("Tadaaaa!", EditorStyles.boldLabel);
    }
}

enter image description here


现在如果您确实希望无论打开哪个选项卡都将其停靠,您可以使用反射来查找EditorWindow的每个继承者并执行

using Linq;

...

var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).Where(type =>type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow))).ToArray();
// This kind of equals doing something like
//var typesList = new List<Type>();
//var assemblies = AppDomain.CurrentDomain.GetAssemblies();
//foreach(var assembly in assemblies)
//{
//    var allTypes = assembly.GetTypes();
//    foreach(var type in allTypes)
//    {
//        if(type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow)))
//        {
//            typesList.Add(type);
//        }
//    }
//}
//var types = typesList.ToArray();

var window = GetWindow<YOURWINDOW>(types);

请注意,由于顺序,ConsoleWindow 几乎是第一个条目,因此如果打开了一个控制台选项卡,它总是首先附加到该选项卡 ^^

您仍然可以添加您喜欢的内容,例如

var types = new List<Type>()
{ 
    // first add your preferences
    typeof(SceneView), 
    typeof(Editor).Assembly.GetType("UnityEditor.GameView"),
    typeof(Editor).Assembly.GetType("UnityEditor.SceneHierarchyWindow"),
    typeof(Editor).Assembly.GetType("UnityEditor.ConsoleWindow"), 
    typeof(Editor).Assembly.GetType("UnityEditor.ProjectBrowser"), 
    typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow")
};

// and then add all others as fallback (who cares about duplicates at this point ? ;) )
types.AddRange(AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).Where(type =>type.IsClass && !type.IsAbstract && type.IsSubclassOf(typeof(EditorWindow))));
var window = GetWindow<YOURWINDOW>(types.ToArray());
 

因为它实际上从头到尾遍历该数组并使用第一个匹配的打开的窗口类型。

关于c# - 如何从脚本在 Unity 中创建窗口并将其附加到现有选项卡?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71322699/

相关文章:

C#.NET : Descending comparison of a SortedDictionary?

c# - 为什么我们必须在 C# 中同时定义 == 和 !=?

c# - 当没有要求和的内容时,Linq .Sum() 函数失败

java - 在云中集成 Unity 和 Java

c# - 如何减少 Windows CE 设备上的 ActiveSync 功能

unity-game-engine - 在 Awake 或 Start 中调用 switch 语句

c# - OnPointerEnter 和 OnPointerExit 没有被触发 Unity

java - 如何在 Java 中使用原语避免 NoSuchMethodException

java - 我可以使用反射或任何其他方法在运行时加载外部项目的 java 类吗

c# - 如何使用反射将新项目添加到集合中