My game has a virtual resolution of 640x480 and an actual resolution of 1280x720.
I’m drawing to a RenderTarget
that is being scaled to fit the game window while maintaining its aspect ratio and uses letterboxing/pillarboxing where needed.
My problem is, while I’m using my virtual resolution for drawing, when I try to draw my text on the center of my virtual window, it gets drawn at a weird position:
Below is my code:
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace MGPlayground
{
public class Game1 : Game
{
private const int VIRTUAL_WIDTH = 640;
private const int VIRTUAL_HEIGHT = 480;
private const int WINDOW_WIDTH = 1280;
private const int WINDOW_HEIGHT = 720;
private int renderXOffset;
private int renderYOffset;
private RenderSize renderSize;
private GraphicsDeviceManager graphics;
private SpriteBatch spriteBatch;
private RenderTarget2D renderTarget;
private SpriteFont arialFont;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
// TODO: Once 3.8.1 comes out, use this and remove the version in `Initialize`.
// graphics.PreferredBackBufferWidth = WINDOW_WIDTH;
// graphics.PreferredBackBufferHeight = WINDOW_HEIGHT;
// _graphics.SynchronizeWithVerticalRetrace = true; // Enable VSync.
}
protected override void Initialize()
{
// TODO: Once 3.8.1 comes out, use the version in `Game1()` and remove this.
graphics.PreferredBackBufferWidth = WINDOW_WIDTH;
graphics.PreferredBackBufferHeight = WINDOW_HEIGHT;
graphics.SynchronizeWithVerticalRetrace = true; // Enable VSync.
graphics.ApplyChanges();
renderTarget = new RenderTarget2D(
GraphicsDevice,
GraphicsDevice.PresentationParameters.BackBufferWidth,
GraphicsDevice.PresentationParameters.BackBufferHeight,
false,
GraphicsDevice.PresentationParameters.BackBufferFormat,
DepthFormat.Depth24);
renderSize = ScaleToFitAspectRatio(VIRTUAL_WIDTH, VIRTUAL_HEIGHT, WINDOW_WIDTH, WINDOW_HEIGHT);
renderXOffset = WINDOW_WIDTH / 2 - renderSize.Width() / 2;
renderYOffset = WINDOW_HEIGHT / 2 - renderSize.Height() / 2;
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
arialFont = Content.Load<SpriteFont>("ArialFont");
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
DrawToRenderTarget(renderTarget);
DrawRenderTargetToScreen();
base.Draw(gameTime);
}
private void DrawToRenderTarget(RenderTarget2D renderTarget)
{
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };
GraphicsDevice.Clear(Color.CornflowerBlue);
// Draw with Nearest Neighbor filtering:
spriteBatch.Begin(blendState: BlendState.AlphaBlend, samplerState: SamplerState.PointClamp);
spriteBatch.DrawString(arialFont, "Hello, World!", new Vector2(VIRTUAL_WIDTH / 2, VIRTUAL_HEIGHT / 2), Color.White);
spriteBatch.End();
GraphicsDevice.SetRenderTarget(null);
}
private void DrawRenderTargetToScreen()
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend,
SamplerState.LinearClamp, DepthStencilState.Default,
RasterizerState.CullNone);
spriteBatch.Draw(renderTarget, new Rectangle(renderXOffset, renderYOffset, renderSize.Width(), renderSize.Height()), Color.White);
spriteBatch.End();
}
private RenderSize ScaleToFitAspectRatio(int srcWidth, int srcHeight, int destWidth, int destHeight)
{
var ratio = Math.Min(Decimal.Divide(destWidth, srcWidth), Decimal.Divide(destHeight, srcHeight));
decimal width = srcWidth * ratio;
decimal height = srcHeight * ratio;
return new RenderSize(Decimal.ToInt32(Math.Round(width, 0)), Decimal.ToInt32(Math.Round(height, 0)));
}
}
public class RenderSize
{
private int _width;
private int _height;
public RenderSize(int width, int height)
{
_width = width;
_height = height;
}
public int Width()
{
return _width;
}
public int Height()
{
return _height;
}
}
}
What puzzles me even more is that when I use my actual resolution instead of my virtual one, the text is displayed on the center of the screen:
Below is the edited code:
spriteBatch.DrawString(arialFont, "Hello, World!", new Vector2(WINDOW_WIDTH / 2, WINDOW_HEIGHT / 2), Color.White);
Shouldn’t using my virtual resolution be the one to actually center my text on the window?
What am I doing wrong?