[Solved]Texture not stretching properly

Hello, everyone

I’m relatively new to Monogame and I really have no idea how to solve this issue.
I have a small tileset (3 tiles, 32x32 - green, brown and blue) made with Tiled, for testing. I loaded it into my program and I want to stretch the tiles (from 32x32 to, let’s say, 64x64) to learn how to adapt window size to resolution.

This is the original code, to place the tiles:


Tile[,] tiles = new Tile[mapWidth, mapHeight];
            for (int i = 0; i < mapWidth; i++)
            {
                for (int j = 0; j < mapHeight; j++)
                {
                    tiles[i, j] = new Tile(new Vector2(i * 32, j * 32), new Rectangle((int)sourcePos[intIDs[i, j] - 1].X, (int)sourcePos[intIDs[i, j] - 1].Y, 32, 32), tex);
                }
            }

To stretch it, I did this:


Tile[,] tiles = new Tile[mapWidth, mapHeight];
            for (int i = 0; i < mapWidth; i++)
            {
                for (int j = 0; j < mapHeight; j++)
                {
                    tiles[i, j] = new Tile(new Vector2(i * 64, j * 64), new Rectangle((int)sourcePos[intIDs[i, j] - 1].X, (int)sourcePos[intIDs[i, j] - 1].Y, 64, 64), tex);
                }
            }

Basically, I put the position of every tile at 64px instead of 32px, and stretched the rectangle to 64px instead of 32px. Vertically, this works perfectly. Horizontally, not so much, getting all messed up.

Original:

Stretched vertically:

Only modifying the position of the tiles on the X axis:


Stretching the width of the rectangle from 32px to 64px:

(Sorry for badly cropped images)

Can someone more experienced offer me some insight? I can’t understand what’s going wrong.
Thank you :grin:

What is “sourcePos”? And how are you drawing the tiles?
(and btw this is not a good way of supporting multiple resolutions. An easier way is to draw everything as usual to a RenderTarged2D and then stretch that according to resolution.)

1 Like

sourcePos is the position of the tile in the tileset.

I understand now what I have to do. It was a wrong way to do it.
I’ll try with RenderTarget2D, since I can’t really stretch it this way without going over the next texture in the tileset.

Thanks a lot!

You can take a look at how I do it, or just use it if you want to :slight_smile:

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;

namespace Fhax.Graphics
{
    /// <summary>
    /// The methods for resizing the screen
    /// </summary>
    public enum ResizeMethod
    {
        /// <summary>
        /// Just stretch/shrink the image in x/y to fit
        /// </summary>
        Stretch,
        /// <summary>
        /// Stretch/shrink the image by the smaller scale-difference in x/.
        /// Keeps aspect-ratio.
        /// This results in black bars around the image.
        /// </summary>
        Pillow,
        /// <summary>
        /// Stretch/shrink the image by the bigger scale-difference.
        /// Keeps aspect-ratio.
        /// Image will most likeley be bigger than the window
        /// </summary>
        Fill
    }

    /// <summary>
    /// Used to render independent from the screen's size
    /// </summary>
    public class ResolutionRenderer
    {
        /// <summary>
        /// The resolution that will be rendered on
        /// </summary>
        public Point VirtualResolution { get { return _virtualResolution; } set { _virtualResolution = value; _needsUpdate = true; } }
        private Point _virtualResolution;

        /// <summary>
        /// The actual screen-size
        /// </summary>
        public Point ScreenResolution { get { return _screenResolution; } set { _screenResolution = value; _needsUpdate = true; } }
        private Point _screenResolution;

        /// <summary>
        /// Method to be used when resizing the image
        /// Default: Stretch
        /// </summary>
        public ResizeMethod Method { get { return _method; } set { _method = value; _needsUpdate = true; } }
        private ResizeMethod _method;

        private Vector2 _scale;
        private Vector2 _methodScale;

        private GraphicsDevice _device;
        private RenderTarget2D _target;
        private SpriteBatch _batch;

        private RenderTargetBinding[] _prevTargets;

        private bool _needsUpdate;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="virtualResolution"></param>
        public ResolutionRenderer(Point virtualResolution, GraphicsDevice device)
        {
            _device = device;

            _virtualResolution = virtualResolution;
            _screenResolution.X = _device.Viewport.Width;
            _screenResolution.Y = _device.Viewport.Height;

            _method = ResizeMethod.Stretch;
            
            _batch = new SpriteBatch(_device);

            _needsUpdate = false;
        }

        private void Update()
        {
            _needsUpdate = false;

            _scale = ScreenResolution.ToVector2() / VirtualResolution.ToVector2();
            _target = new RenderTarget2D(_device, _virtualResolution.X, _virtualResolution.Y);

            switch(_method)
            {
                case ResizeMethod.Stretch:
                    _methodScale = _scale;
                    break;
                case ResizeMethod.Pillow:
                    var smaller = Math.Min(_scale.X, _scale.Y);
                    _methodScale = new Vector2(smaller, smaller);
                    break;
                case ResizeMethod.Fill:
                    var bigger = Math.Max(_scale.X, _scale.Y);
                    _methodScale = new Vector2(bigger, bigger);
                    break;
                default:
                    _methodScale = _scale;
                    break;
            }
        }

        /// <summary>
        /// Call before drawing anything
        /// </summary>
        public void Begin()
        {
            if (_needsUpdate)
                Update();

            _prevTargets = _device.GetRenderTargets();
            _device.SetRenderTarget(_target);
            _device.Clear(Core.Settings.Screen.ClearColor);  
        }

        /// <summary>
        /// Call after drawing is finished
        /// </summary>
        public void End()
        {
            var pos = ScreenResolution.ToVector2() / 2f;
            var origin = VirtualResolution.ToVector2() / 2f;

            _device.SetRenderTargets(_prevTargets);
            _device.Clear(Core.Settings.Screen.ClearColor);

            _batch.Begin();
            _batch.Draw(_target, pos, null, Color.White, 0, origin, _methodScale, SpriteEffects.None, 0);
            _batch.End();
        }
    }
}


And in your game-class:

public class Game1 : Game
{
    ResolutionRenderer res;

    protected override void Initialize()
    {
        //...
        res = new ResolutionRenderer(/*Render-Resolution*/, GraphicsDevice);
        res.ScreenResolution = /*Window-Size*/;
        //...
    }

    public static void Draw(GameTime gameTime)
    {
        res.Begin();

        spriteBatch.Begin();
        //Draw stuff...
        spriteBatch.End();

        res.End();
    }
}