Isometric view

Good day!

Tell me how to create an isometry in Monogame? Are there any tutorials where this is described step by step? How to write a camera? How to prepare and display sprites? I would not like a theory, but code examples.

Thanks more for the answers!

internal sealed class Game2D : Game
    {
        private ICamera _camera;
        private SpriteBatch _spriteBatch;
        private SolidTexture[] _textures;

        public Game2D(MonoSettings settings)
        {
            // ReSharper disable once UnusedVariable
            var deviceManager = new GraphicsDeviceManager(this)
            {
                GraphicsProfile = GraphicsProfile.HiDef,
                PreferMultiSampling = true,
                PreferredBackBufferHeight = settings.Height,
                PreferredBackBufferWidth = settings.Width
            };

            _camera = null!;
            Content.RootDirectory = settings.GfxPath;

            IsMouseVisible = true;

            Window.IsBorderless = !settings.Bordered;
            Window.Position = Point.Zero;

            _spriteBatch = null!;
            _textures = null!;
        }

        protected override void LoadContent()
        {
            _camera = new Camera2D();

            _spriteBatch = new SpriteBatch(GraphicsDevice);
            _textures = new[]
            {
                new SolidTexture(GraphicsDevice, Color.Black),
                new SolidTexture(GraphicsDevice, Color.White),
            };
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            _spriteBatch.Begin(transformMatrix: _camera.Transform);

            const int size = 100;
            for (var x = 0; x < 10; x++)
            {
                for (var y = 0; y < 10; y++)
                {
                    var rectangle = new Rectangle(x * size, y * size, size, size);
                    var odd = x % 2 == 0;
                    var texture = odd
                        ? y % 2 == 0 ? _textures[0] : _textures[1]
                        : y % 2 == 0
                            ? _textures[1]
                            : _textures[0];

                    _spriteBatch.Draw(texture, rectangle, Color.White);
                }
            }

            _spriteBatch.End();

            base.Draw(gameTime);
        }

        protected override void Update(GameTime gameTime)
        {
            _camera.Update(gameTime);
            base.Update(gameTime);
        }
    }
    public sealed class Camera2D : ICamera
    {
        // ReSharper disable once ConvertToAutoPropertyWithPrivateSetter
        public Matrix Transform => _transform;

        private const float MaxZoom = 1f;
        private const float MinZoom = 0.1f;

        private readonly Vector2 _origin;
        private Vector2 _position;
        private Matrix _transform;
        private float _zoom;

        private float _currentMouseWheelValue, _previousMouseWheelValue;

        internal Camera2D(Vector2? position = null)
        {
            _origin = Vector2.Zero;
            _zoom = 0.5f;
            _position = position ?? Vector2.Zero;
        }

        public void Update(GameTime gameTime)
        {
            _transform = Matrix.CreateTranslation(_position.X, _position.Y, 0f) *
                         Matrix.CreateScale(_zoom) *
                         // TODO: what to write here???
                         Matrix.CreateTranslation(new Vector3(_origin, 0f));

            int moveSpeed;
            if (_zoom > .8f) moveSpeed = 15;
            else if (_zoom < .8f && _zoom >= .6f) moveSpeed = 20;
            else if (_zoom < .6f && _zoom > MinZoom) moveSpeed = 25;
            else if (_zoom <= MinZoom) moveSpeed = 30;
            else moveSpeed = 10;

            var keyboard = Keyboard.GetState();

            var cameraMovement = Vector2.Zero;
            if (keyboard.IsKeyDown(Keys.W)) cameraMovement.Y = moveSpeed;
            if (keyboard.IsKeyDown(Keys.S)) cameraMovement.Y = -moveSpeed;
            if (keyboard.IsKeyDown(Keys.D)) cameraMovement.X = -moveSpeed;
            if (keyboard.IsKeyDown(Keys.A)) cameraMovement.X = moveSpeed;

            var newPosition = _position + cameraMovement;
            _position = newPosition;

            _previousMouseWheelValue = _currentMouseWheelValue;
            _currentMouseWheelValue = Mouse.GetState().ScrollWheelValue;

            if (_currentMouseWheelValue > _previousMouseWheelValue || keyboard.IsKeyDown(Keys.Q))
            {
                AdjustZoom(.05f);
            }
            else if (_currentMouseWheelValue < _previousMouseWheelValue || keyboard.IsKeyDown(Keys.Z))
            {
                AdjustZoom(-.05f);
            }
        }

        private void AdjustZoom(float zoomAmount)
        {
            _zoom += zoomAmount;
            if (_zoom < MinZoom) _zoom = MinZoom;
            else if (_zoom > MaxZoom) _zoom = MaxZoom;
        }
    }

P.S.: MonoGame.Framework.DesktopGL, Version 3.8.0.1375-develop, .NET Core 3.1, macOS.

1 Like

Ok, I took texture 132 by 99 and converted the coordinates of the beginning of the rectangle to isometric. I did not use matrix transformation. This is not the best solution, but it works.

const int width = 132;
const int height = 99;
const int halfWidth = width / 2;
var bounds = new Point(width, height);
for (var x = 0; x < 10; x++)
{
     for (var y = 0; y < 10; y++)
     {
          var odd = x % 2 == 0;
          var texture = odd
               ? y % 2 == 0 ? _textures[2] : _textures[3]
               : y % 2 == 0
                    ? _textures[3]
                    : _textures[2];

          var position = new Point(x * halfWidth, y * halfWidth).ToIsometric();
          var rectangle = new Rectangle(position, bounds);

          _spriteBatch.Draw(texture, rectangle, Color.White);
   }
}
public static Point ToIsometric(this Point cartesian)
{
     var x = cartesian.X - cartesian.Y;
     var y = (cartesian.X + cartesian.Y) / 2;
     return new Point(x, y);
}