GUI.Button render order vs click order.

We have noticed something curious which we think is the core of several issues concerning 2D artifacts on our games. I wanted to attach a screenshot but apparently the attach image thing is not working right now. Anyway… the attached script draws three squares (GUI.Buttons) on the screen that are staggered and partially overlapping. Starting top left and rendered in the back is a white square, then a yellow square and in the front on the bottom right is a red square.

What we have noticed is that if you click on any button in an area that has a button behind it then the rear button gets the event. For instance if I click on the top/red button area where the others intersect behind it, the bottom/white button gets the click. If I click the middle/yellow button where the bottom/white button is underneath it, the bottom/white button gets the click.

If you click the middle/yellow (or any other) button where there is nothing behind it, it works as expected. Other wise it works completely counter intuitive to any other GUI system I have worked on. Basically it looks like the clicks get intercepted with the render order.

Is there a reason for this in design or is this a feature (or a bug) in the Unity GUI system? Is there a workaround or hack that may be employed to make this work somewhat is expected?

Here is a simple script demonstrating what I am talking about:

using UnityEngine;
using System.Collections;

public class GuiClickThroughTest : MonoBehaviour {

    void OnGUI()
    {
        
        GUI.color = Color.white;
        if (GUI.Button(new Rect(450, 100, 200, 200), "A WHITE button"))
        {
            Debug.Log("WHITE button pressed " + Event.current);
        }
        
        GUI.color = Color.yellow;
        if (GUI.Button(new Rect(500, 150, 200, 200), "A YELLOW button"))
        {
            Debug.Log("YELLOW button pressed " + Event.current);
        }
        
        GUI.color = Color.red;
        if (GUI.Button(new Rect(550, 200, 200, 200), "A RED button"))
        {
            Debug.Log("RED button pressed "  + Event.current);
        }
    }
}

Sure, that’s the normal behaviour of an immediate GUI system. It processes all your GUI elements in the order you create them. So if the first one catches an event noone else will be able to use the event. The drawing happens in the same order, that’s why the last object is drawn on top of everything else.

Because of this the event-handling first reacts to the bottom-most elements. The only GUI element that works different is a GUI.Window.

It isn’t drawn immediately. All windows are collected and get drawn in the current z-order after the OnGUI function is finished. The input handling is executed reverse. That works only for windows because they provide a delegate callback for their content. Windows change their z-order automatically when they got focused.

Normal GUI elements should not overlap to prevent such misbehaviour.

I’m not sure why the buttons should overlap? Is it because of the margin/padding? you can set them to 0 to put the buttons seemless together. Take a look at GUISkin (scripting ref)

Here’s a question that I asked (and answered) about drawing GUI controls on top of each other:

this same question: ask solution
http://answers.unity3d.com/questions/1173148/guilayouttextfield-do-not-work-on-guibutton-1.html