I gather this is a problem to a few and not-a-problem to many, based on what I find on the web (general web for either XNA or MonoGame) that addresses the problem satisfactorily. I have a solution that works for me, but, given my general ignorance regarding MonoGame (I’m a newb), I need to know whether I’m on the right track or out in left field somewhere.
My interest is in 3D viewing. Here, I’m trying to use the resources of XNA through MonoGame. (Most of my experience is with OpenGL, and I’ve got 48 years with 3D transformations.) I’m using MonoGame 3.4 with Windows 10.
My initial approach was based on an MSDN article on Resizing a Game and a Stack Overflow response to a forum query “How to resize window using XNA”. It involved delegating an event handler to handle the ClientSizeChange event of Game.Window. The event-handling requirements were:
- Set the buffer width and height.
- Call ApplyChanges() to commit the new viewport.
- Call CreatePerspectiveFieldOfView() to define the new viewing frustum.
I tried to handle these few requirements entirely in my OnResize() event handler. But I very quickly found out that my approach caused the stack to overflow. (After all, it was Stack Overflow advice!)
Watching the behavior in the window while I was resizing it (without trying to do everything in OnResize()), I hypothesized that neither draws nor updates were being done so long as my mouse button stayed down; the same buffer was being re-painted. I concluded that what I needed was a resize-complete event. But nothing like that is available, so far as I know.
I thunk about it for a while and then tried an experiment. I did the bare minimum in OnResize(): I set a flag that signals that a resize operation is pending, and I query the window height and width. I store these three things in a simple structure named resizing.
When the user terminates his window resize, there are two places where I could commit a window size change and set the frustum – Draw() or Update(). Both worked. I figured I’d seek someone else’s opinion. I looked at Open Rails source code and saw that they do it in Update(). That’s what I did.
Here’s a quick summary of what I did.
Key class variables in Game1:
GraphicsDeviceManager graphics; SpriteBatch spriteBatch; ResizeStatus resizing; // Records status and (width, height) while resizing
Game1’s constructor instantiates resizing (the ResizeStatus structure), allows window resizing, and delegates ClientSizeChange event handling to OnResize():
graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; resizing = new ResizeStatus(graphics);
Window.AllowUserResizing = true; Window.ClientSizeChanged += new EventHandler<EventArgs>(OnResize);
Update() tests the resizing.Pending flag. If set, the back buffer size is committed and the frustum is adjusted. On completion, the resizing.Pending flag is set false:
if (resizing.Pending) { graphics.PreferredBackBufferWidth = resizing.Width; graphics.PreferredBackBufferHeight = resizing.Height; graphics.ApplyChanges(); camera.UpdateProjection(resizing.Width, resizing.Height); resizing.Pending = false; // Resize is complete (no longer pending) }
The Resize() event handler merely records window size changes as they occur and sets the resizing.pending flag:
resizing.Pending = true; // Resize is pending resizing.Width = Window.ClientBounds.Width; resizing.Height = Window.ClientBounds.Height;
Finally, my question: Am I on the right track?