Centering a stupid box in Unity

If you have a 2D game with a board and you want to center it on the screen, here’s the best way I came up with to do it.

Suppose you have a variable-size board (could longer or shorter in either dimension) on a variable-sized screen (could be a phone, tablet, web browser, console, etc.). Given you want to center the board on the screen, leaving a small margin on each edge, you need to scale and position it correctly.

First we’re just going to find the width and height of the screen. ViewportToWorldPoint gets the coordinates at the upper-right corner of the screen and the camera is centered at (0, 0), so we actually need to double the URH coordinates to get the full width and height.

Vector3 world = Camera.main.ViewportToWorldPoint(
    new Vector3(1f, 1f, 0f));
world *= 2;

Then we need to scale the board to fit within this screen. Thus, if the board is longer than the screen is tall, we have to make it shorter. If the board is wider than the screen, we have to squeeze it thinner. In either case, we want to keep the board at the same aspect ratio after shrinking, so we choose the axis that requires the most compression and scale both axes by that. This code assumes that transform is your board GameObject‘s Transform and board is a Vector2 of board width & height (e.g., for chess it would be new Vector2(8, 8)).

float margin = .5f;
float scaleX = (world.x - 2 * margin) / board.x;
float scaleY = (world.y - 2 * margin) / board.y;
float scale = Mathf.Min(scaleX, scaleY);
transform.localScale = new Vector3(scale, scale, 1f);

Finally, we need to center the scaled-down board on the screen. Since (0, 0) is the center of the screen, we want to position the board at (-width/2, –height/2). However, this isn’t quite correct: if we put a 1-unit sprite at (0, 0), Unity centers the sprite at (0, 0) so its left edge is at -.5. Thus, if we position the sprite at –width/2, its right edge ends up at 0. To adjust for this we need to offset by 1/2 of tile’s width, i.e., the 1/2 of the scaling factor.

float offset = scale / 2;
transform.position = new Vector3(
    -(scale * board.x) / 2 + offset,
    -(scale * board.y) / 2 + offset,

I’m kind of shocked that there isn’t an easier way to do this, so please chime in if you know of one!

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: