Johny P.
Johny P.

Reputation: 698

Scale all sprites on screen based on resolution

I decided to move my game from windowed to fullscreen mode and that's the first problem I face. I'm looking for a way of resizing all of my sprites based on screen resolution. My background is now in the (0, 0) coordinates, but I need to have it and all sprites to scale with some kind of fixed aspect ratio (16:9 preferred). And resize them to that portion that the background is stretched to fill the screen. And not more, not less.

I've looked into some online tutorials but I really couldn't understand the concept they used. Can you explain how you would to that? I read using a RenderTarget2D and passing it to a spriteBatch.Begin() call, has some kind of effect, but there's got to be more code.

I'm not looking to supporting resolution change option, but adapting the sprites to the current resolution.

Upvotes: 4

Views: 5355

Answers (2)

craftworkgames
craftworkgames

Reputation: 9957

It sounds like you're talking about resolution independence.

The general idea is to make your game using a virtual resolution and scale it up or down to fit the actual resolution of the screen.

var scaleX = (float)ActualWidth / VirtualWidth;
var scaleY = (float)ActualHeight / VirtualHeight;
var matrix = Matrix.CreateScale(scaleX, scaleY, 1.0f);

_spriteBatch.Begin(transformMatrix: matrix);

For example, if your virtual resolution was 800x480 you would simply render all your sprites relative to that. Then before rendering the sprite batch, create a transformation matrix to pass into the Begin call.

The other thing you should know is that you'll need to scale the mouse / touch input coordinates in reverse to deal with them in the virtual resolution. In the Update method you can scale the mouse position in reverse like this:

var mouseState = Mouse.GetState(); // you're probably already doing this
var mousePosition = new Vector2(mouseState.X, mouseState.Y);
var scaledMousePosition = Vector2.Transform(mousePosition, Matrix.Invert(matrix));

Then you can use the scaled value in all the places you're currently using mouseState.X and mouseState.Y.

It gets more complicated if want to implement letterboxing or pillarboxing. Take a look at the Viewport Adapters in MonoGame.Extended if you want to know how that works.

Upvotes: 10

Mephy
Mephy

Reputation: 2986

You have a texture with size (W, H), to be put in the position (X, Y), according to a scale (sW, sH). Initially, the scale was (1, 1), so the sprite would be positioned in the rectangle (X, Y, W, H).

Now, let's say the initial resolution was 800x600, but you now want a resolution of 1440x900. If 800 -> sW = 1, 1440 -> sW = 1440/800 = 1.8. Similar, our new sH is 1.5.

What this is saying is: if something was supposed to be on the X-coordinate 500 on the initial resolution, it is now on 500*1.8 = 900 X position on the new resolution. This is clear for the edge: if something was on X=800 previously, it is now on 800*1.8 = 1440, still on the edge of the screen!

All said and done, we simply have to multiply. Going back to the first paragraph, we can say that a rectangle (X, Y, W, H) can be rescaled by a scale (sW, sH) to (X * sW, Y * sH, W * sW, H * sH).

This is of course calculated by assuming the original resolution is scaled by (1, 1), don't forget this!

Upvotes: 1

Related Questions