I've been trying to reach a good solution on different resolutions, but none have been working very well, either the sprites get distorted, everythings gets offset, or a variety of different shenanigans.
The best solution I got was this, where it uses a RenderTarget and Transformation Matrix to scale everything down according to the resolution, however when the aspect ration is not the same as the virtual resolution, things get offset on the Y axis gif of it happening, here's the Draw code:
GraphicsDevice.SetRenderTarget(RenderTarget);
var scaleX = (float)ScreenWidths[CurrentResolution] / 1920;
var scaleY = (float)ScreenHeights[CurrentResolution] / 1080;
var matrix = Matrix.CreateScale(scaleX, scaleX, 1.0f);
spriteBatch.Begin(transformMatrix: matrix);
GraphicsDevice.Clear(BackgroundColor);
foreach (var uiElement in UIElements)
{
uiElement.Draw(gameTime, spriteBatch);
}
spriteBatch.End();
GraphicsDevice.SetRenderTarget(null);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend,
SamplerState.LinearClamp, DepthStencilState.Default,
RasterizerState.CullNone);
var offsetX = ScreenWidths[CurrentResolution] / 2 - 1920 / 2 * scaleX;
var offsetY = ScreenHeights[CurrentResolution] / 2 - 1080 / 2 * scaleY;
spriteBatch.Draw(RenderTarget, new Rectangle((int)offsetX, (int)offsetY, (int)(1920), (int)(1080)), Color.White);
spriteBatch.End();
var mouseState = Mouse.GetState();
MousePosition = Vector2.Transform(new Vector2(mouseState.X, mouseState.Y), Matrix.Invert(matrix));
base.Draw(gameTime);
This is on the Initialise:
ScreenWidths = new int\[\] { 1920, 960, 1366, 1280, 1280, 1366 };
ScreenHeights = new int\[\] { 1080, 540, 768, 1024, 720, 680 };
RenderTarget = new RenderTarget2D(
GraphicsDevice,
GraphicsDevice.PresentationParameters.BackBufferWidth,
GraphicsDevice.PresentationParameters.BackBufferHeight,
false,
GraphicsDevice.PresentationParameters.BackBufferFormat,
DepthFormat.Depth24);
And this is the code for the button:
if (Main.CurrentResolution >= 0 && Main.CurrentResolution < Main.ScreenWidths.Length - 1) {
Main.CurrentResolution++;
Main.graphics.PreferredBackBufferWidth = Main.ScreenWidths[Main.CurrentResolution];
Main.graphics.PreferredBackBufferHeight = Main.ScreenHeights[Main.CurrentResolution];
Main.graphics.ApplyChanges();
}
How would I fix this offset on the Y axis? Or even what would be a better way to go about different resolutions?
In this example, you can see how to:
Things are then correctly positioned in a relative manner no matter the aspect ratio difference.
Next thing you want is an uniform scale, here it's min of X/Y but you can also force it to be on a specific axis.
Also, the matrix you want will likely be: scale, rotate, translate.
You may want to adjust all of this to what you're really looking for.
Result:
resolution: <960, 540>, pointRelative: <480.000, 270.000>, pointAbsolute: <50.000, 50.000>, scaleAbsolute: <0.500, 0.500>, scaleUniform: 0.500
resolution: <960, 680>, pointRelative: <480.000, 340.000>, pointAbsolute: <50.000, 62.963>, scaleAbsolute: <0.500, 0.630>, scaleUniform: 0.500
resolution: <960, 720>, pointRelative: <480.000, 360.000>, pointAbsolute: <50.000, 66.667>, scaleAbsolute: <0.500, 0.667>, scaleUniform: 0.500
resolution: <960, 768>, pointRelative: <480.000, 384.000>, pointAbsolute: <50.000, 71.111>, scaleAbsolute: <0.500, 0.711>, scaleUniform: 0.500
resolution: <960, 1024>, pointRelative: <480.000, 512.000>, pointAbsolute: <50.000, 94.815>, scaleAbsolute: <0.500, 0.948>, scaleUniform: 0.500
resolution: <960, 1080>, pointRelative: <480.000, 540.000>, pointAbsolute: <50.000, 100.000>, scaleAbsolute: <0.500, 1.000>, scaleUniform: 0.500
resolution: <1280, 540>, pointRelative: <640.000, 270.000>, pointAbsolute: <66.667, 50.000>, scaleAbsolute: <0.667, 0.500>, scaleUniform: 0.500
resolution: <1280, 680>, pointRelative: <640.000, 340.000>, pointAbsolute: <66.667, 62.963>, scaleAbsolute: <0.667, 0.630>, scaleUniform: 0.630
resolution: <1280, 720>, pointRelative: <640.000, 360.000>, pointAbsolute: <66.667, 66.667>, scaleAbsolute: <0.667, 0.667>, scaleUniform: 0.667
resolution: <1280, 768>, pointRelative: <640.000, 384.000>, pointAbsolute: <66.667, 71.111>, scaleAbsolute: <0.667, 0.711>, scaleUniform: 0.667
resolution: <1280, 1024>, pointRelative: <640.000, 512.000>, pointAbsolute: <66.667, 94.815>, scaleAbsolute: <0.667, 0.948>, scaleUniform: 0.667
resolution: <1280, 1080>, pointRelative: <640.000, 540.000>, pointAbsolute: <66.667, 100.000>, scaleAbsolute: <0.667, 1.000>, scaleUniform: 0.667
resolution: <1366, 540>, pointRelative: <683.000, 270.000>, pointAbsolute: <71.146, 50.000>, scaleAbsolute: <0.711, 0.500>, scaleUniform: 0.500
resolution: <1366, 680>, pointRelative: <683.000, 340.000>, pointAbsolute: <71.146, 62.963>, scaleAbsolute: <0.711, 0.630>, scaleUniform: 0.630
resolution: <1366, 720>, pointRelative: <683.000, 360.000>, pointAbsolute: <71.146, 66.667>, scaleAbsolute: <0.711, 0.667>, scaleUniform: 0.667
resolution: <1366, 768>, pointRelative: <683.000, 384.000>, pointAbsolute: <71.146, 71.111>, scaleAbsolute: <0.711, 0.711>, scaleUniform: 0.711
resolution: <1366, 1024>, pointRelative: <683.000, 512.000>, pointAbsolute: <71.146, 94.815>, scaleAbsolute: <0.711, 0.948>, scaleUniform: 0.711
resolution: <1366, 1080>, pointRelative: <683.000, 540.000>, pointAbsolute: <71.146, 100.000>, scaleAbsolute: <0.711, 1.000>, scaleUniform: 0.711
resolution: <1920, 540>, pointRelative: <960.000, 270.000>, pointAbsolute: <100.000, 50.000>, scaleAbsolute: <1.000, 0.500>, scaleUniform: 0.500
resolution: <1920, 680>, pointRelative: <960.000, 340.000>, pointAbsolute: <100.000, 62.963>, scaleAbsolute: <1.000, 0.630>, scaleUniform: 0.630
resolution: <1920, 720>, pointRelative: <960.000, 360.000>, pointAbsolute: <100.000, 66.667>, scaleAbsolute: <1.000, 0.667>, scaleUniform: 0.667
resolution: <1920, 768>, pointRelative: <960.000, 384.000>, pointAbsolute: <100.000, 71.111>, scaleAbsolute: <1.000, 0.711>, scaleUniform: 0.711
resolution: <1920, 1024>, pointRelative: <960.000, 512.000>, pointAbsolute: <100.000, 94.815>, scaleAbsolute: <1.000, 0.948>, scaleUniform: 0.948
resolution: <1920, 1080>, pointRelative: <960.000, 540.000>, pointAbsolute: <100.000, 100.000>, scaleAbsolute: <1.000, 1.000>, scaleUniform: 1.000
Code:
public void Test()
{
var sx = new[] { 1920, 1366, 1280, 960 };
var sy = new[] { 1080, 1024, 768, 720, 680, 540 };
var pt1 = new Vector2(0.5f, 0.5f);
var pt2 = new Vector2(100, 100);
foreach (var w in sx.Reverse())
{
foreach (var h in sy.Reverse())
{
var scaleX = w / 1920.0f;
var scaleY = h / 1080.0f;
var resolution = new Vector2(w, h);
var scaleUniform = Math.Min(scaleX, scaleY);
var scaleAbsolute = new Vector2(scaleX, scaleY);
var pointRelative = pt1 * resolution;
var pointAbsolute = pt2 * scaleAbsolute;
Console.WriteLine(
$"{nameof(resolution)}: {resolution,12}, " +
$"{nameof(pointRelative)}: {pointRelative,20:F3}, " +
$"{nameof(pointAbsolute)}: {pointAbsolute,20:F3}, " +
$"{nameof(scaleAbsolute)}: {scaleAbsolute:F3}, " +
$"{nameof(scaleUniform)}: {scaleUniform:F3}"
);
}
}
}