C# Unity-将编辑器窗口停靠在游戏视图上方
我试图实现的是通过脚本在Unity的编辑器中将一个编辑器窗口停靠在游戏视图的下方、顶部或左侧或右侧(为简单起见,让我们只关注停靠在游戏视图上方)。请看视频,了解我想要实现的目标 编辑 由于这个问题被标记为离题,下面是一个代码示例。我遇到的问题是C# Unity-将编辑器窗口停靠在游戏视图上方,c#,unity3d,unity-editor,C#,Unity3d,Unity Editor,我试图实现的是通过脚本在Unity的编辑器中将一个编辑器窗口停靠在游戏视图的下方、顶部或左侧或右侧(为简单起见,让我们只关注停靠在游戏视图上方)。请看视频,了解我想要实现的目标 编辑 由于这个问题被标记为离题,下面是一个代码示例。我遇到的问题是Dock方法中的dropInfo为null,因此SplitView的PerformDrop方法会导致null ref错误 public static class Docker { private class _EditorWindow {
Dock
方法中的dropInfo
为null,因此SplitView
的PerformDrop
方法会导致null ref错误
public static class Docker
{
private class _EditorWindow
{
private EditorWindow instance;
private Type type;
public _EditorWindow( EditorWindow instance )
{
this.instance = instance;
type = instance.GetType();
}
public object m_Parent
{
get
{
var field = type.GetField( "m_Parent", BindingFlags.Instance | BindingFlags.NonPublic );
return field.GetValue( instance );
}
}
}
private class _DockArea
{
private object instance;
private Type type;
public _DockArea( object instance )
{
this.instance = instance;
type = instance.GetType();
}
public object window
{
get
{
var property = type.GetProperty( "window", BindingFlags.Instance | BindingFlags.Public );
return property.GetValue( instance, null );
}
}
public object s_OriginalDragSource
{
set
{
var field = type.GetField( "s_OriginalDragSource", BindingFlags.Static | BindingFlags.NonPublic );
field.SetValue( null, value );
}
}
}
private class _ContainerWindow
{
private object instance;
private Type type;
public _ContainerWindow( object instance )
{
this.instance = instance;
type = instance.GetType();
}
public object rootSplitView
{
get
{
var property = type.GetProperty( "rootSplitView", BindingFlags.Instance | BindingFlags.Public );
return property.GetValue( instance, null );
}
}
}
private class _SplitView
{
private object instance;
private Type type;
public _SplitView( object instance )
{
this.instance = instance;
type = instance.GetType();
}
public object DragOver( EditorWindow child, Vector2 screenPoint )
{
var method = type.GetMethod( "DragOver", BindingFlags.Instance | BindingFlags.Public );
return method.Invoke( instance, new object[] { child, screenPoint } );
}
public void PerformDrop( EditorWindow child, object dropInfo, Vector2 screenPoint )
{
var method = type.GetMethod( "PerformDrop", BindingFlags.Instance | BindingFlags.Public );
method.Invoke( instance, new object[] { child, dropInfo, screenPoint } );
}
}
public enum DockPosition
{
Left,
Top,
Right,
Bottom
}
/// <summary>
/// Docks the second window to the first window at the given position
/// </summary>
public static void Dock( this EditorWindow wnd, EditorWindow other, DockPosition position )
{
var mousePosition = GetFakeMousePosition( wnd, position );
var parent = new _EditorWindow( wnd );
var child = new _EditorWindow( other );
var dockArea = new _DockArea( parent.m_Parent );
var containerWindow = new _ContainerWindow( dockArea.window );
var splitView = new _SplitView( containerWindow.rootSplitView );
var dropInfo = splitView.DragOver( other, mousePosition );
dockArea.s_OriginalDragSource = child.m_Parent;
splitView.PerformDrop( other, dropInfo, mousePosition );
}
private static Vector2 GetFakeMousePosition( EditorWindow wnd, DockPosition position )
{
Vector2 mousePosition = Vector2.zero;
// The 20 is required to make the docking work.
// Smaller values might not work when faking the mouse position.
switch ( position )
{
case DockPosition.Left:
mousePosition = new Vector2( 20, wnd.position.size.y / 2 );
break;
case DockPosition.Top:
mousePosition = new Vector2( wnd.position.size.x / 2, 20 );
break;
case DockPosition.Right:
mousePosition = new Vector2( wnd.position.size.x - 20, wnd.position.size.y / 2 );
break;
case DockPosition.Bottom:
mousePosition = new Vector2( wnd.position.size.x / 2, wnd.position.size.y - 20 );
break;
}
return new Vector2(wnd.position.x + mousePosition.x, wnd.position.y + mousePosition.y);
}
}
public static class SomeStaticClass
{
[MenuItem("DOCK TESTING/Dock Above")]
public static void DockAbove()
{
SysType gameViewType = Assembly.GetAssembly(typeof(Editor)).GetType("UnityEditor.GameView");
EditorWindow baseWindow = EditorWindow.GetWindow(gameViewType);
EditorWindow newWindow = (EditorWindow)ScriptableObject.CreateInstance(gameViewType);
baseWindow.Dock(newWindow, Docker.DockPosition.Top);
}
}
公共静态类Docker
{
私有类编辑器窗口
{
私有编辑器窗口实例;
私有类型;
public\u EditorWindow(EditorWindow实例)
{
this.instance=instance;
type=instance.GetType();
}
公共对象m_父对象
{
得到
{
var field=type.GetField(“m_Parent”,BindingFlags.Instance | BindingFlags.NonPublic);
返回字段.GetValue(实例);
}
}
}
私有类
{
私有对象实例;
私有类型;
public_DockArea(对象实例)
{
this.instance=instance;
type=instance.GetType();
}
公共对象窗口
{
得到
{
var property=type.GetProperty(“窗口”,BindingFlags.Instance | BindingFlags.Public);
return property.GetValue(实例,null);
}
}
公共对象s_OriginalDragSource
{
设置
{
var field=type.GetField(“s_OriginalDragSource”,BindingFlags.Static | BindingFlags.NonPublic);
field.SetValue(null,value);
}
}
}
私有类ContainerWindow
{
私有对象实例;
私有类型;
公共容器窗口(对象实例)
{
this.instance=instance;
type=instance.GetType();
}
公共对象rootSplitView
{
得到
{
var property=type.GetProperty(“rootSplitView”,BindingFlags.Instance | BindingFlags.Public);
return property.GetValue(实例,null);
}
}
}
私有类_SplitView
{
私有对象实例;
私有类型;
public\u SplitView(对象实例)
{
this.instance=instance;
type=instance.GetType();
}
公共对象DragOver(编辑器窗口子对象,矢量2屏幕点)
{
var method=type.GetMethod(“DragOver”,BindingFlags.Instance | BindingFlags.Public);
Invoke(实例,新对象[]{child,screenPoint});
}
public void PerformDrop(编辑器窗口子对象、对象dropInfo、矢量2屏幕点)
{
var method=type.GetMethod(“PerformDrop”,BindingFlags.Instance | BindingFlags.Public);
调用(实例,新对象[]{child,dropInfo,screenPoint});
}
}
公共枚举DockPosition
{
左边
顶部
正确的,
底部
}
///
///将第二个窗口停靠到给定位置的第一个窗口
///
公共静态无效驳接(此EditorWindow wnd、EditorWindow其他、驳接位置)
{
var mousePosition=GetFakeMousePosition(wnd,位置);
var parent=新的编辑器窗口(wnd);
var child=新编辑器窗口(其他);
var dockArea=新的_dockArea(parent.m_parent);
var containerWindow=新的_containerWindow(dockArea.window);
var splitView=new_splitView(containerWindow.rootSplitView);
var dropInfo=splitView.DragOver(其他,鼠标位置);
dockArea.s_OriginalDragSource=child.m_父项;
splitView.PerformDrop(其他、dropInfo、鼠标位置);
}
专用静态向量2 GetFakeMousePosition(编辑器窗口wnd,DockPosition位置)
{
Vector2鼠标位置=Vector2.0;
//对接工作需要使用20。
//伪造鼠标位置时,较小的值可能不起作用。
开关(位置)
{
案例文档位置。左:
鼠标位置=新矢量2(20,wnd.position.size.y/2);
打破
案例文档位置。顶部:
鼠标位置=新矢量2(wnd.position.size.x/2,20);
打破
案例文档位置。右侧:
mousePosition=newvector2(wnd.position.size.x-20,wnd.position.size.y/2);
打破
案例文档位置。底部:
mousePosition=newvector2(wnd.position.size.x/2,wnd.position.size.y-20);
打破
}
返回新矢量2(wnd.position.x+mousePosition.x,wnd.position.y+mousePosition.y);
}
}
公共静态类SomeStaticClass
{
[MenuItem(“上述码头测试/码头”)]
公共静态无效停靠区()
{
SysType gameViewType=Assembly.GetAssembly(typeof(Editor)).GetType(“UnityEditor.GameView”);
EditorWindow baseWindow=EditorWindow.GetWindow(gameViewType);
EditorWindow newWindow=(EditorWindow)ScriptableObject.CreateInstance(gameViewType);
baseWindow.Dock(newWindow、Docker.DockPosition.Top);
}
}
因此,为了将来的参考,对于其他任何尝试此代码(找到)的人来说,这就是我为使其为我工作所做的
dropInfo
对象始终为空的原因有两个:
首先使用20的固定值来计算假鼠标位置,生成的位置是游戏视图的下降选项卡区域,然后
private static Vector2 GetFakeMousePosition(_SplitView view, DockPosition position, float offset)
{
Vector2 mousePosition = Vector2.zero;
switch ( position )
{
case DockPosition.Left:
mousePosition = new Vector2(offset, view.position.height / 2);
break;
case DockPosition.Top:
mousePosition = new Vector2(view.position.width / 2, offset);
break;
case DockPosition.Right:
mousePosition = new Vector2(view.position.width - offset, wnd.position.size.y / 2 );
break;
case DockPosition.Bottom:
mousePosition = new Vector2(view.position.width / 2, view.position.height - offset);
break;
}
return new Vector2(view.position.x + mousePosition.x, view.position.y + mousePosition.y);
}
private class _SplitView
{
private object instance;
private Type type;
public _SplitView( object instance )
{
this.instance = instance;
type = instance.GetType();
}
public object DragOver( EditorWindow child, Vector2 screenPoint )
{
var method = type.GetMethod( "DragOver", BindingFlags.Instance | BindingFlags.Public );
return method.Invoke( instance, new object[] { child, screenPoint } );
}
public void PerformDrop( EditorWindow child, object dropInfo, Vector2 screenPoint )
{
var method = type.GetMethod( "PerformDrop", BindingFlags.Instance | BindingFlags.Public );
method.Invoke( instance, new object[] { child, dropInfo, screenPoint } );
}
public Rect position
{
get
{
var property = type.GetProperty("screenPosition", BindingFlags.Instance | BindingFlags.Public);
return property.GetValue(instance, null);
}
}
}