简体   繁体   English

Unity-将编辑器窗口停靠在游戏视图上方

[英]Unity - Dock an editor window above the game view

What I am trying to achieve is to dock an editor window below, on top or to the left or right of the game view in Unity's editor via script (for simplicity, lets just focus on docking above the game view). 我要实现的目标是通过脚本将编辑器窗口停靠在Unity编辑器中游戏视图的下方,顶部或左侧或右侧(为简单起见,我们只专注于停靠在游戏视图上方)。 Look at this video for an example of what I want to achieve. 观看视频,了解我想要实现的示例。

EDIT 编辑

As the question was mark as off topic, here is a code sample. 由于该问题被标记为主题之外,因此这里是一个代码示例。 The problem that I have is that dropInfo inside the Dock method is null, and therefore the PerformDrop method of the SplitView causes a null ref error. 我的问题是Dock方法中的dropInfo为null,因此SplitViewPerformDrop方法导致null引用错误。

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);
    }
}

So for future reference, for anyone else out there that tries this code (found here ) this is what I did for it to work for me. 因此,为以后的参考,对于尝试此代码的其他任何人(在此处找到),这就是我所做的工作。

The reason why the dropInfo object was always null is because of two things: dropInfo对象始终为null的原因有两点:

First using a fix value of 20 to calculate the fake mouse position, was generating position that was falling tab area of the game view, and therefore it was not possible to anchor the other window to the game view (this was only happening when trying to tab on Top of the game view). 首先使用固定值20计算假鼠标位置,生成的位置落在游戏视图的标签区域,因此无法将另一个窗口锚定到游戏视图(这仅在尝试标签)。 In order to fix this I just used a different value, passed to the GetFakeMousePosition as the offset parameter. 为了解决这个问题,我只使用了一个不同的值,将GetFakeMousePosition作为offset参数传递给GetFakeMousePosition

Second, using the editor window position to calculate the fake mouse position, was always giving strange results, that is when I notices that the window position property returns the local position of the window relative to it's parent, rather than the window's screen position, so I change from using the window position to using it's top parent position (Window->DockArea->SplitView) position to calculate the fake mouse position. 其次,使用编辑器的窗口位置来计算假鼠标的位置,总是会产生奇怪的结果,也就是说,当我注意到window position属性返回的是窗口相对于其父窗口的本地位置,而不是窗口的屏幕位置时,我从使用窗口位置更改为使用其顶部父位置(Window-> DockArea-> SplitView)位置来计算假鼠标位置。

After all this changes, the GetFakeMousePosition looks like this: 完成所有这些更改后, GetFakeMousePosition如下所示:

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);
}

And the _SplitView class looks like this: _SplitView类如下所示:

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);
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM