5
\$\begingroup\$

I've converted my XNA project into a MonoGame one.

Whenever I start the application and resize the game manually (ie - dragging the window)...

this.Window.AllowUserResizing = true;

...the game scales in a weird manner.

Namely instead of scaling as it should do, it scales to the point where it looks fuzzy and the mouse clicks aren't working correctly.

The main game map has a hard coded "component size" which means that when the screen gets larger, its supposed to show more of the game - but instead I'm getting poorly scaled components.

Part of my code looks as follows:

const int TILEWIDTH = 50;
const int TILEHEIGHT = 50;
//......
Rectangle rec = new Rectangle(0, 0, TILEWIDTH, TILEHEIGHT);
spriteBatch.Draw(this.game.Content.Load<Texture2D>(tileGraphic.path), rec, Color.White);

So theoretically the pixels are becoming larger. This was working correctly in XNA.

I am in no way handling or overriding the resize command, it was 'just working'.

I found some threads with similar problems, but no solution. Anything I could do ?

\$\endgroup\$

4 Answers 4

6
\$\begingroup\$

I found that in order to get window resizing to work properly, you need to handle resetting the Graphics Device parameters manually, when the window is resized:

this.Window.AllowUserResizing = true;
this.Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);

void Window_ClientSizeChanged(object sender, EventArgs e)
{
    graphics.PreferredBackBufferWidth = Window.ClientBounds.Width;
    graphics.PreferredBackBufferHeight = Window.ClientBounds.Height;
    graphics.ApplyChanges();
}

So basically, whenever your window is resized, you reset the Graphics Device with the new width/height.

\$\endgroup\$
7
  • \$\begingroup\$ GraphicsDevice.Reset() does not exist in Monogame - monogame.codeplex.com/discussions/432200 \$\endgroup\$
    – Haedrian
    Jan 16, 2014 at 20:30
  • \$\begingroup\$ You are right. I modified the code. Might help. \$\endgroup\$
    – jgallant
    Jan 16, 2014 at 20:45
  • 1
    \$\begingroup\$ I get a stack overflow whenever I run the program with that code. The pertinant part of the stack suggests that MonoGame.Framework.dll!MonoGame.Framework.WinFormsGameWindow.OnClientSizeChanged(object sender, System.EventArgs eventArgs) - calls "OnClientSizeChanged()" which starts the loop over again. \$\endgroup\$
    – Haedrian
    Jan 16, 2014 at 21:17
  • \$\begingroup\$ I moved "graphics.ApplyChanges()" to the Update function instead and it seems to be working. I'm not sure how its effecting my framerate though - apparently nothing at all - but I need to be sure... \$\endgroup\$
    – Haedrian
    Jan 16, 2014 at 21:30
  • \$\begingroup\$ yeah, sorry, I haven't tested this :) \$\endgroup\$
    – jgallant
    Jan 16, 2014 at 21:37
2
\$\begingroup\$

The answer by jgallant here creates a stack overflow. To fix this I did the following:

//add this in your initialisation

this.Window.AllowUserResizing = true;
this.Window.ClientSizeChanged += new EventHandler<EventArgs>(Window_ClientSizeChanged);

private bool WindowSizeIsBeingChanged = false;
void Window_ClientSizeChanged(object sender, EventArgs e)
{
    WindowSizeIsBeingChanged = !WindowSizeIsBeingChanged
    if(WindowSizeIsBeingChanged){
        graphics.PreferredBackBufferWidth = Window.ClientBounds.Width;
        graphics.PreferredBackBufferHeight = Window.ClientBounds.Height;
        graphics.ApplyChanges();
    }
}

The problem was that graphics.ApplyChanges() calls the ClientSizeChanged to be activated. With this fix, you essentially skip the code from the second call, which makes sure you don't end up with a stack overflow, without having to put any additional calls to graphics.ApplyChanges() in your main game loop.

\$\endgroup\$
1
\$\begingroup\$

Fixing the issue was easier than expected

public override void Update(GameTime gameTime)
{
graphics.ApplyChanges();
}

It doesn't seem to impact framerate in any way (still getting 120)

\$\endgroup\$
3
  • \$\begingroup\$ I went from 0.06 to 0.16 render iteration time by doing this each update call, so at least for me there is a performance cost. \$\endgroup\$
    – ItzWarty
    Jan 25, 2017 at 23:16
  • \$\begingroup\$ @ItzWarty - A solution, when need to be sure work is done at next Update, but not on every Update, is to set a flag on the event that causes the change. In Update, test the flag; if set, do the work and clear the flag. \$\endgroup\$ Oct 26, 2017 at 23:07
  • \$\begingroup\$ Calling Applychanges() on every update is not a good solution. \$\endgroup\$
    – user122973
    Nov 19, 2022 at 20:09
0
\$\begingroup\$

I found that I needed to cache the resolution I had been on, and compare and if they changed, then do apply changes. This made it happen only once. Putting it in game update gave me lots of artifacts and crazy stuff.

void Window_ClientSizeChanged(object sender, EventArgs e)
{
    if (Resolution.currentResolution().X != Window.ClientBounds.Width || Resolution.currentResolution().Y != Window.ClientBounds.Height)
    {
         graphics.PreferredBackBufferWidth = screen.Bounds.Width;
         graphics.PreferredBackBufferHeight = screen.Bounds.Height;
         graphics.ApplyChanges();
    }
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .