RectTransform With a Top-Left Origin

In this post, I talk about setting the anchorMin and anchorMax of a RectTransform to the same value and directly assigning the anchoredPosition and sizeDelta. This is going to expand on that to mimic using GUIs APIs that have an origin on the top left.

A lot of traditional GUI APIs have a coordinate system where the top left is the origin. [1][2] Even Unity’s legacy IMGUI (the GUI system that Unity’s Inspector and Editor scripts still use) has a top-left origin convention. Unity’s current main GUI system (UGUI) goes the other way and makes the bottom left the viewport origin to match the coordinate convention of its 3D content. This also means moving content in +Y moves GUI content up instead of down. But, what if you really want to have the top-left as your origin and work like a traditional UI?

To do that:

  • For every RectTransform in the hierarchy, set the anchorMin and anchorMax to Vector(0.0f, 1.0f)
  • For every RectTransform in the hierarchy, set the pivot to Vector(0.0f, 1.0f).
  • Set the sizeDelta to the pixel dimensions you want the UI’s rectangle to be.
  • Set the anchoredPosition's position, except with a negated Y.
Setting a RectTransform’s placement similar to traditional dialogs by assigning the sizeDelta with the size, and anchoredPosition to the position using a negated Y component.

The first two items set up the coordinate frame of the RectTransform to be anchored to the top left or itself, and its parent. Then you can place stuff from from the top as your origin as long as you remember to negate the Y component of the position.

Example

So if I was writing something in PlatformSDK (or wxWidgets or MFC, or X11/Motif, or whatever IOS, Mac or Andro… you know – etc) to create a UI element:

// Windows Platform SDK (with C) to create a button and assign it a position and size

// Allocate the button
HWND hwndBtn = CreateWindow(
    L"BUTTON",                     
    L"Example",
    BS_DEFPUSHBUTTON|WS_CHILD|WS_VISIBLE,
    0,0,0,0 // Leave empty so we can change it with a call
    parentHwnd,
    NULL,
    hInstance,
    NULL);
    
// Set the button 30 pixels from the left, and 50 pixels from the top
// With a size of 200px x 20x
SetWindowPos(hwndBtn, HWND_NOTOPMOST, 30, 50, 200, 20, SWP_NOZORDER);

I can translate it into Unity with something like

// Unity C#, creating a button and assining its position and size similar to tradtional
// dialog programming.
// Create 
GameObject go = new GameObject("Button", typeof(UnityEngine.UI.Button), typeof(UnityEngine.UI.Image));
go.transform.SetParent(parentGO.transform, false);
RectTransform rt = go.GetComponent<RectTransform>(); //Adding an Image forced it to already have a RectTransform
// Setting pivot and anchors to top left (<0.0, 1.0>)
rt.anchorMin = new Vector2(0.0f, 1.0f);
rt.anchorMax = new Vector2(0.0f, 1.0f);
rt.pivot = new Vector2(0.0f, 1.0f);
// Setting the button's position to 30 pixels from the left, and 50 pixels from the top
rt.anchoredPosition = new Vector2(30.0f, -50.0f);
// Set the button's pixel dimensions
rt.sizeDelta = new Vector2(200.0f, 20.0f);

This helps take old GUI coding knowledge and algorithms for dialogs and translate them into Unity without spending too much cognitive effort on going back-and-fourth between conventions. Very often when (re)implementing/porting dialog and UI libraries into Unity that I’ve made in the past, I’ll set up all the data structures and calculations to be based off the top left (how I’m used to for traditionally coding dialogs) and simply set the position to an inverted Y at the very end.

– Stay strong, code on. William Leu

Explore more articles here.
Explore more articles about Unity here.