3
\$\begingroup\$

I want my game script to detect mouse clicks everywhere on my screen, except one corner where I have a pair of buttons to control the sound and will be handled separately. To help identify this corner, I've created a soundPanel object with the Rect Transform component (available in the Unity 4 Beta 17+) and have sized/positioned it appropriately in the editor in my UI layer.

In my game's script, I have passed in this corner object, and tried using it in the following way:

bool tap = (Input.GetMouseButtonDown(0) || Input.GetMouseButtonUp(0))
           && !soundPanel.rect.Contains(Input.mousePosition);

Clicking in the soundPanel still triggers a tap. I figured this is because the mouse position and soundPanel.Rect are not in the same coordinate space. Since the documentation on the new Unity Beta UI is a bit lacking / hard to find, I tried converting the mouse coordinates to everything I could:

if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonUp(0))
{
    if (soundPanel.rect.Contains(Input.mousePosition)) { print("Raw"); }
    if (soundPanel.rect.Contains(camera.ScreenToViewportPoint(Input.mousePosition))) { print("ScreenToViewportPoint"); }
    if (soundPanel.rect.Contains(camera.ScreenToWorldPoint(Input.mousePosition))) { print("ScreenToWorldPoint"); }
    if (soundPanel.rect.Contains(camera.ViewportToScreenPoint(Input.mousePosition))) { print("ViewportToScreenPoint"); }
    if (soundPanel.rect.Contains(camera.ViewportToWorldPoint(Input.mousePosition))) { print("ViewportToWorldPoint"); }
    if (soundPanel.rect.Contains(camera.WorldToScreenPoint(Input.mousePosition))) { print("WorldToScreenPoint"); }
    if (soundPanel.rect.Contains(camera.WorldToViewportPoint(Input.mousePosition))) { print("WorldToViewportPoint"); }
    print("-------------------");
}

When I click with the above code, "ScreenToViewportPoint" and "ScreenToWorldPoint" print no matter where I click, and no others trigger. I suspect I need to transform the soundPanel somehow.

Here is the Hierarchy, Scene, and Inspector. The selected rect is the soundPanel, and it is in the bottom-right of the UI Canvas:

Hierarchy, Scene, and Inspector

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

The easiest way I found to do this was as follows:

  1. Make sure to configure your canvas to use screen space based on the camera. Drag and drop your camera into the render camera property

    Canvas Inspector

  2. Detect if the rectangle contains the mouse coordinates using RectTransformUtility.RectangleContainsScreenPoint() method. Pass in your rectTransform object, the current mouse position (takes screen coordinates so raw Input.mousePosition works fine), and the main camera object.

  3. To keep the UI position in sync with the camera, update the canvas position with a line similar to the following somewhere where it will execute after the camera position has been updated:

    canvas.transform.position = new Vector3(camera.transform.position.x, camera.transform.position.y, canvas.transform.position.z);

\$\endgroup\$
4
  • \$\begingroup\$ Hmm, something weird happens when I change the UI Canvas to Screen Space - Camera: The UI bobs around when the camera moves \$\endgroup\$ Oct 2, 2014 at 5:40
  • \$\begingroup\$ Here's a gif: i.imgur.com/QUpYem1.gif The whole HUD moves in the opposite direction of the camera briefly, then slowly recovers. \$\endgroup\$ Oct 2, 2014 at 5:48
  • \$\begingroup\$ @John McDonald i think it's a unity bug , i have experienced the same thing. \$\endgroup\$
    – Raxvan
    Oct 2, 2014 at 10:13
  • \$\begingroup\$ @Raxvan I mostly agree except I will concede that it's possible we just don't know how to properly implement this at this point and we're missing something big. I wouldn't expect to have to update the canvas position but if we don't the screen bobs as John described so for now we use the code above to rectify the problem. \$\endgroup\$ Oct 2, 2014 at 13:58
1
\$\begingroup\$

I figured out how to detect pixel coordinates on a RectTransform by using the transform property to get the center of of the rect in pixel coordinates, then use sizeDelta to get the width and height, make a rect from that, then test it against the mouse coordinates.

Vector2 topLeft = (Vector2)soundPanel.transform.position - (soundPanel.sizeDelta / 2f);
Rect soundRect = new Rect(topLeft.x, topLeft.y, soundPanel.sizeDelta.x, soundPanel.sizeDelta.y);

bool tap = (Input.GetMouseButtonDown(0) || Input.GetMouseButtonUp(0))
           && !soundRect.Contains(Input.mousePosition);

I will say, it's not perfect. Something is still slightly off, but it's close enough for now.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .