There's going to be some variation in how you approach this, depending on whether you're going for "pixel-perfect retro re-creation" or "playable prototype to learn about making platformers." You don't need perfect precision to make something fun, so there's nothing wrong with taking a simpler route, especially in your early work. As I go through the steps below I'll call out extra things you'll want to think about if you want to push toward pixel-perfection, but you can also safely skip these and still get something that feels good to play.
Step 1: Decide on your unit scale
Mega Man 3 used 16x16 tiles, so you'll probably find it convenient to consider this "one unit" for the purposes of laying out your levels. You could also halve this value if you want both tile corners and tile centers to sit on integer coordinates - this is really a matter of taste.
(I'd recommend against using 1 pixel = 1 unit though - generally you want your unit to be in the ballpark of the size of the player avatar, since a lot of engine tools & systems assume you're working in this kind of scale range)
If you want your game to render pixel-perfect across multiple resolutions, you may want to use two or more unit scales for your graphics, selecting the best fit for the current resolution as described in this article on pixel-perfect rendering in Unity. To keep gameplay consistent, you'll still want to pick one canonical unit scale for calculating your metrics & movement in Step 4.
Step 2: Configure your Pixels Per Unit import settings
This is found in the Inspector when selecting any image you've imported into your project with
TextureType: Sprite (2D and UI)
Set this to your unit scale value (eg. 16 if using 16-pixel tiles, or the appropriate variant for each asset if you're using multiple sizes as touched on above)
Once you do this for each Sprite asset you're using, each tile will automatically size itself to 1 unit when you add it to your scene (and other shapes/sizes of sprites like characters will size themselves proportionately)
Step 3: Configure your camera size
Using the formula:
Orthographic camera size = (screen height in source pixels) / (pixels per unit * 2)
So, if you want to emulate a standard NES resolution of 240 pixels vertically (including overscan), with 16 pixels per unit, you'd set your camera size to
If you want to crop in further to mimic the fact that old CRTs only displayed part of the image, you could use
224/(16*2) = 7
To get a pixel perfect look you need to be careful how this is scaled to the player's screen, which typically has way more pixels than a retro-style game. If you notice rippling artifacts in your sprites it's because your viewport size isn't an integer multiple of your "retro" resolution. Again, the pixel-perfect rendering article linked above has tips on how to crop or pad your display to get this lined up neatly, if you want to go all the way with it.
Step 4: Tune your gameplay metrics & speeds
Now we can use this value to translate our measurements into gameplay units:
Jump speed in pixels per frame = 4.875 p/f
...times 60 frames per second = 292.5 p/s
...divided by 16 pixels per unit = 18.28125 u/s
Acceleration in pixels per frame² = 0.25 p/f²
...times (60 frames per second)² = 900.0 p/s²
...divided by 16 pixels per unit = 56.25 u/s²
Step 5: Using Unity Physics
Unity's Box2D physics system is a lot more complex than the logic used in classic platformers, so as others have pointed out above, if you want to truly duplicate older mechanics then the way to do it is to write your own custom physics handling - that's beyond the scope of this answer.
But if purity of reproduction isn't your goal and you just want to get something playable and fun, using Unity's built-in physics may help you get up and running faster, and can be tuned to give a similar feel, so that's what I'll describe here.
You'll find there's a lot of negativity out there about these physics engines, but most of it comes from the fact that they're very easy to use wrong. With a little care we can tame them to get the kind of results we want.
There are three main parts to this:
If your reference game's physics update at 60 fps, then you'll want to go into
Project Settings -> Time and set
Fixed Timestep to 1/60 = 0.01666...
This will ensure that things like gravity and collisions are integrated at the expected time resolution. Note that if your rendering framerate is very close to 60, this can cause a beat frequency between the physics rate and the display rate, but for a 2D game you'll typically be running well above 60 fps anyway. There are ways to address this if you find noticeable artifacts.
Get in the habit of putting any movement logic in
FixedUpdate() methods. This will ensure they run as often as the physics step, no matter what happens to the rendering framerate, helping you get consistent gameplay across different devices and levels of load.
B) Applying your forces and velocities
Applying the gravity acceleration is straightforward. If everything is using the same gravity, you can go to
Project Settings -> Physics 2D and put the value we calculated above into Y, negated. (ie.
X: 0 Y: -56.25). Then you can leave the
gravityScale on each object at its default value of 1.
Some old games used different gravity values per character/object, or for different phases of the jump. In a case like that you'd probably want to zero-out the gravity globally or by setting
rigidbody2D.gravityScale = 0 on the objects that need custom gravity, then apply it yourself at the end of every
rigidbody2D.velocity += Vector2.down * gravity * Time.deltaTime;
To kick your character into the air with a given initial velocity, you'd use something like this:
Vector2 velocity = rigidbody2D.velocity;
// You can also add to the current vertical velocity instead of replacing it,
// if you want the jump to adapt to running up/downhill or jumping off a moving platform.
velocity.y = jumpVelocity;
ridigbody2D.velocity = velocity;
That should give you a good starting point. Test it out and see how it works.You may find the jump arc in Unity deviates slightly from your target, due to differences in when gravity is applied (eg. between steps or continuously over the course of each step) - if you find that's the case, comment below with the metrics you're seeing and we can work out the appropriate compensating factors.
C) Disable unwanted physics effects
Create a new
Physics2D Material from the Assets menu and set its Friction to 0. Use this on any player colliders so contact with the ground doesn't sap a portion of the velocity value you want.
On the player Rigidbody2D, check FreezeRotation Z under Constraints so your character doesn't roll around. Keep Linear Drag at its default of zero for the same reason as the friction - it'll be up to your control script to stop the player when you want them stopped. ;)