8
\$\begingroup\$

I previously used SFML, XNA, Monogame, etc. to create 2d games, where if I display a 100px sprite on the screen, it will take up 100px. If I use 128px tiles to create a background, the first tile will be at (0, 0) while the second will be at (128, 0).

Unity on the other hand, has its own odd unit system, scaling on all transforms, pixel-to-units, othographic size, etc, etc. So my question is two-fold, namely:

  1. Why does Unity have this system by default for 2d? Is it for mobile dev? Is there a big benefit I'm not seeing?
  2. How can I setup my environment, so that if I have a 128x128 sprite in Photoshop, it displays as a 128x128 sprite in Unity when I run my game?

Note that I am targeting desktop exclusively.

\$\endgroup\$
  • 1
    \$\begingroup\$ Why this happens is because Unity was a 3D engine that recently had 2D graphics grafted in. How to handle everything however is something I'd be curious to see answers to, to see if someone else has a better approach than I do. \$\endgroup\$ – jhocking May 20 '14 at 20:00
  • \$\begingroup\$ Unity's GUI functions and GUITexture component let you draw textures to screen at native size, directly. docs.unity3d.com/Documentation/ScriptReference/GUI.html docs.unity3d.com/Documentation/Components/class-GuiTexture.html If you need more flexibility, your best bet is to define a consistent scale - like 1U = 128px - and apply it consistently to all your quads/sprites/cameras. \$\endgroup\$ – DMGregory May 21 '14 at 13:05
  • \$\begingroup\$ I would avoid Unity's GUI class; because the immediate mode GUI in Unity is pretty inefficient, they are building a new GUI system (about to release it actually, in version 4.6). \$\endgroup\$ – jhocking May 31 '14 at 19:45
4
\$\begingroup\$

Handling 2D coordinates and scaling in Unity is fairly simple, but non-obvious and as you've noticed it's unlike how other dev tools work. Why this happens is because Unity was a 3D engine that recently had 2D graphics grafted in.

In particular, 1 unit in Unity is not necessarily 1 pixel in the image. When you import images as 2D Sprites there's actually a Pixels-to-Units setting that could be made 1:1 but I recommend leaving it at the default 100:1 for a couple reasons (the physics engine doesn't work right at 1:1, and the default is better for compatibility with others' code).

This scaling setting means that all positions are divided by 100. It's pretty easy as long as you always remember the scaling; when you want to move a sprite 256 pixels (say) then you move it 2.56 You may also want to write a utility function to round numbers to 2 decimal places/the nearest pixel: Mathf.Round(float * 100) / 100f


As for setting up a pixel-perfect camera, first off set it as an orthographic camera. When you select the camera, in it's settings is a drop-down for Perspective or Orthographic projection; perspective means things will look 3D, while orthographic displays the scene flat. Right under this drop-down is Size; set the camera's orthographic size to half the pixel dimensions of the screen you want.

For example, let's say you want a pixel-perfect 1024x768 screen. Well that means the camera height should be 384 pixels. Divide that by 100 (because of the pixels-to-units scale) and you get 3.84 for the camera size. Again, that math is simply SCREEN_SIZE / 2 / 100f


(I was waiting to see what other answers come first, but it's been a couple days. I've been doing 2D in Unity for a while using 2D Toolkit, but am relatively new to the built-in 2D features)

\$\endgroup\$
2
\$\begingroup\$

As jhocking says, it's a result of shoehorning 2D into a 3D IDE. But, there is a solution, it's just a bit arcane.

First step is to open your sprite's Import Settings from the Project pane. Once Texture Type is set to Sprite or Advanced (Advanced gives you other handy options, but Sprite is default if you created a 2D project at the beginning), there's a Pixels To Units field with a default of 100.

I'm mucking around with a tile system, so I'm using 16x16 pixel tiles and set Pixels To Units to 16. The math works like so: Size in pixels (either X or Y) / Pixels To Units = Unity Units in Transform. 16 pixel cube with PTU 16 takes up 1 unit in Unity space.

I haven't tried yet, but I expect a PTU of 1 would make things pixel perfect.

The orthographic camera setting is a bit of a headache however. Once again, it's based of that Pixels to Units setting, but also a few other things. Basically it's half the screen height from Player Settings (ie 1080, 768, whatever the iPhone 5 is, can't be bothered to look it up) divided by Pixels To Units.

\$\endgroup\$
1
\$\begingroup\$

Pixel units is not a good way to represent large worlds due to the way that floating point numbers work. With floating point numbers, you lose precision with very large numbers. Numbers that are near 0 have the best precision. Thus, some game engines tend to prefer the MKS system of metrics (Meters/Kilograms/Seconds). Unity defaults to meters, so game characters can easily be represented as 1.0-2.0 meters tall with very good precision.

The average weight and height of a human male is about 50kg and 1.8meters tall. If you tried to make a character that is 1200 pixels tall, its weight would be about 33,000 pixels units. If you then wanted to add a a very heavy object like a bus to a game, you'd have a huge number of pixel units. You can easily see how this could lead to very imprecise calculations for collisions.

If you are very determined to use pixel units, you can easily calculate the pixels to meters ratio.

\$\endgroup\$
  • \$\begingroup\$ But all of this doesn't apply to most 2D games which hardly even need to use physics at all. The problem is that Unity suggests support for 2D but it's very rudimentary and requires a lot of study to simplify down to what you really need out of a 2D engine. \$\endgroup\$ – Kokodoko Aug 29 '15 at 12:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.