Search code examples
c#monogame

Position reset when minimizing


When I start my application, the object spawns at the given position (given vector). But when I minimize the monogame window and reopen it, then the object is in the upper-left corner.

Why is this happening?

NOTE: this is my Draw method:

public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
{
    // Position is the object position 
    spriteBatch.Draw(textureImage, position, new Rectangle(
    (currentFrame.X * frameSize.X),
    (currentFrame.Y * frameSize.Y),
    frameSize.X, frameSize.Y),
    Color.White, 0, Vector2.Zero, 2, SpriteEffects.None, 0);
}

How the starting position is calculated:

// Vector2 position is the starting position for the object

public PlayerMovement(Texture2D textureImage, Vector2 position, Point frameSize, int collisionOffSet, Point currentFrame, Point startFrame, Point sheetSize, float speed, float speedMultiplier, float millisecondsPerFrame)
        : base(textureImage, position, frameSize, collisionOffSet, currentFrame, startFrame, sheetSize, speed, speedMultiplier, millisecondsPerFrame)
{
        children = new List<Sprite>();
}

I use Vector2 direction to know which direction the sprite is facing:

public abstract Vector2 direction
    {
        get;
    }

I use the get in my PlayerMovement class and return inputDirection * speed

(inputDirection is a Vector2)

Finally in my Update method, I do position += direction and I also check if the player isn't touching the borders of the screen(he can't move out the screen.).


Solution

  • From my own experience, using Game.Window.ClientBounds in an Update call has caused problems when the window is minimized. Here is some sample code from my project:

    Rectangle gdm = Game.Window.ClientBounds;
    if (DrawLocation.X < 0) DrawLocation = new Vector2(0, DrawLocation.Y);
    if (DrawLocation.Y < 0) DrawLocation = new Vector2(DrawLocation.X, 0);
    if (DrawLocation.X > gdm.Width - DrawAreaWithOffset.Width) DrawLocation = new Vector2(gdm.Width - DrawAreaWithOffset.Width, DrawLocation.Y);
    if (DrawLocation.Y > gdm.Height - DrawAreaWithOffset.Height) DrawLocation = new Vector2(DrawLocation.X, gdm.Height - DrawAreaWithOffset.Height);
    

    The problem I had when minimizing was that Game.Window.ClientBounds was returning some width/height around -32000. This would always reset my game objects to some default location when restoring the window. I fixed it by first checking that the ClientBounds Width and Height were both greater than zero:

    Rectangle gdm = Game.Window.ClientBounds;
    if (gdm.Width > 0 && gdm.Height > 0) //protect when window is minimized
    {
        if (DrawLocation.X < 0)
            DrawLocation = new Vector2(0, DrawLocation.Y);
        if (DrawLocation.Y < 0)
            DrawLocation = new Vector2(DrawLocation.X, 0);
        if (DrawLocation.X > gdm.Width - DrawAreaWithOffset.Width)
            DrawLocation = new Vector2(gdm.Width - DrawAreaWithOffset.Width, DrawLocation.Y);
        if (DrawLocation.Y > gdm.Height - DrawAreaWithOffset.Height)
            DrawLocation = new Vector2(DrawLocation.X, gdm.Height - DrawAreaWithOffset.Height);
    }
    

    For reference, here is a diff of changes that fixed the minimize problem for my own project.

    A separate bug I was having involved interaction with the game still happening when the game was not the primary, active window. You can also add a check for Game.IsActive at the beginning of your Update and Draw calls:

    public override void Update(GameTime gt)
    {
        if(!IsActive) return;
        //etc...
    }
    

    Or if using Game Components, your component update/draw would look like:

    public override void Update(GameTime gt)
    {
        if(!Game.IsActive) return;
        //etc...
    }