Update 2/20: The issue was closed as “by design” with no explanation. I’ve reached out to Unity for more information and will update if I hear anything.
Update 2/19: The Unity QA team was able to reproduce the bud, and the issue is now listed on the Unity Issue Tracker – go vote for it!
I just sent in a bug report to Unity on a rather nasty physics bug affecting 2D games – notably tile based games, though any game using 2D physics could be affected. The problem is how Unity maps pixels to units (it’s still a 3D world no matter what you do to your camera!), and how those units are passed into the 2D physics engine (Unity’s 2D physics engine is the open source project Box2D, helpful to know when searching about issues).
It’s my guess that there is a rounding call or float to int cast causing the trouble. This is based on the test project I did (and sent to Unity with the bug report).
To create a test, I simulated a 32×32 tile based game world. I added 3 objects to the world, each representing a 32×32 sprite. The first sprite is named “player” and has a 2D Box Collider and 2D Rigid Body attached. The other two sprites are “walls” and were given 2D Box Colliders and placed under the player 32 pixels apart. When run, gravity should cause the player to fall and rest on the corners of the wall exactly.
In the first scene I used a pixel to unit ration of 1:1 – that is 1 3D unity equals 1 sprite pixel. You can see from the screenshot below the test passed:
In the second scene I used the Unity default pixel to units mapping of 100:1 – that is 1 3D unit equals 100 sprite pixels. In the test scene, the player “floats” on top of the walls:
So why not just use 1:1 pixels per unit and call it a day? Honestly, I would love to use 1:1 mapping, but as I found out while working on UTiled (shameless plug for my Unity Tiled map importer) there is a limitation of Box2D that comes into play. Box2D has a max velocity of 100 m/s – of course what a “meter” is can be defined by the game. In Unity however, 1 3D unit is always 1 meter. This means the 2D physics system is not scaled according to the pixels per unit mapping, and the result is at a 1:1 mapping everything move very slowly.
Hopefully this gets fix in the next update of Unity. In the mean time its something you’ll have to be aware of if you’re using Unity’s physics engine for movement of objects.