Monogame Screen Tearing Between Tiles

by Matt Clegg   Last Updated September 15, 2018 12:13 PM

I've noticed some 'tearing' or gaps appearing between tiles when the camera moves over a tile map, and I have no idea why.

I should mention, the game is being drawn to a render target (320x192), then the render target is drawn and scaled to fit the window size (960x576). I'm also using Monogame Extended's Camera2D class. Tiles have int positions, so x:10 y:14, but are rendered at float positions. I found that if they were rendered at int positions, the camera movement stuttered a lot and was quite noticeable.

The render target is setup like so:

_depthStencilState = new DepthStencilState { DepthBufferEnable = true };
_renderTarget = new RenderTarget2D(_graphics,
                                   RPG.VirtualWidth,
                                   RPG.VirtualHeight,
                                   false,
                                   SurfaceFormat.Color, 
                                   DepthFormat.None, 
                                    _graphics.PresentationParameters.MultiSampleCount,
                                   RenderTargetUsage.DiscardContents);

_renderDestination = new Rectangle(0, 0, _graphics.Viewport.Width, _graphics.Viewport.Height);

This is my rendering code:

private void DrawGame(SpriteBatch flatBatch, SpriteBatch sortedBatch)
{
    CalculateCameraBounds();
    flatBatch.Begin(samplerState: SamplerState.PointClamp, transformMatrix: _camera.GetViewMatrix());

    _mapRenderer.Draw(flatBatch, _cameraBounds);
    _entityRenderer.Draw(sortedBatch, _cameraBounds);

    flatBatch.End();
}

public override void Draw(SpriteBatch batch)
{
    DrawToRenderTarget(batch);
     _graphics.Clear(Color.Black);

    batch.Begin(samplerState: SamplerState.PointClamp);
    batch.Draw(_renderTarget, _renderDestination, Color.White);
    batch.End();
}

private void DrawToRenderTarget(SpriteBatch batch)
{
    _graphics.SetRenderTarget(_renderTarget);
    _graphics.DepthStencilState = _depthStencilState;

    _graphics.Clear(Color.HotPink);

    DrawGame(batch, _sortedBatch);

    _graphics.SetRenderTarget(null);
}

private void CalculateCameraBounds()
{
    RectangleF bounds = _camera.BoundingRectangle;
    _cameraBounds.X = (int)(bounds.X / Assets.TileWidth) - 1;
    _cameraBounds.Y = (int)(bounds.Y / Assets.TileHeight) - 1;
    _cameraBounds.Width = (int)(bounds.Width / Assets.TileWidth) + 3;
    _cameraBounds.Height = (int)(bounds.Height / Assets.TileHeight) + 3;
}

The _mapRenderer.Draw() method looks like this:

public void Draw(SpriteBatch batch, RectangleF cameraBounds)
{
    if (CurrentMap == null)
    {
        return;
    }

    for (int y = 0; y < cameraBounds.Height; y++)
    {
        float drawY = (y + cameraBounds.Y) * Assets.TileHeight;
        int worldY = (int)(y + cameraBounds.Y);
        for (int x = 0; x < cameraBounds.Width; x++)
        {
            float drawX = (x + cameraBounds.X) * Assets.TileWidth;
            int worldX = (int)(x + cameraBounds.X);

            DrawTile(batch, worldX, worldY, drawX, drawY);
            DrawShadow(batch, worldX, worldY, drawX, drawY);
        }
    }
}

The tiles are drawn like so:

private void DrawTile(SpriteBatch batch, int worldX, int worldY, float drawX, float drawY)
{
    Tile tile = CurrentMap.GetTile(worldX, worldY);
    if(tile != null)
    {
        Sprite sprite = _animationManager.GetSpriteForTile(tile.Id);
        batch.DrawSprite(sprite, drawX, drawY);
    }
}

Using a SpriteBatch extension method I wrote called DrawSprite:

private static Vector2 _destination = new Vector2();

public static void DrawSprite(this SpriteBatch batch, Sprite sprite, float x, float y)
{
    _destination.X = (int)x;
    _destination.Y = (int)y;
    batch.Draw(sprite.Texture, _destination, sprite.Bounds, Color.White);
}

The sprite.Bounds field is a Rectangle object where he x, y coords are the sprites location on a texture. The width, height fields are the size of the texture (16x16).

Here's a slowed down gif: enter image description here

And a still when the tearing occurs.

enter image description here

You can see at some points, the pink background bleeds through between gaps in the tiles. Any thoughts on what could be happening here? Could this be an issue with using ints or floats incorrectly?

Edit: Added code showing DrawTile method and DrawSprite extension method.



Related Questions




only one tile being drawn xna c#

Updated September 27, 2016 09:05 AM