Earlgray
Earlgray

Reputation: 647

Isometric tile engine optimisation for better FPS

I have an isometric tile engine written in XNA (Monogame). It can only draw tile map surface. But when I have bigger map (for example 50x50 tiles) then is very slow (about 15 FPS). When I have small map (for example 10x10 tiles) than framrate is perfect (60 FPS).

I'm trying to find way how to optimise my code but I have no idea how to do it.

This is my code:

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

namespace IsoEngine
{
    public class Game1 : Game
    {
        GraphicsDeviceManager _graphics;
        SpriteBatch _spriteBatch;

        Texture2D Tile1;
        Texture2D Tile2;
        MouseState mouseState;
        bool isMousePressed = false;

        int[,] map = { {1, 1, 1, 1},
                       {1, 0, 0, 1},
                       {1, 0, 0, 1},
                       {1, 1, 1, 1} };

        int tileWidth = 64;
        int tileHeight = 32;
        Vector2 scrollSpan = new Vector2(0, 0);
        Vector2 mouseDragPos = new Vector2(0, 0);

        public Game1()
        {
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            base.IsMouseVisible = true;
            base.Initialize();
        }

        protected override void LoadContent()
        {
            _spriteBatch = new SpriteBatch(GraphicsDevice);

            Tile1 = Content.Load<Texture2D>("1");
            Tile2 = Content.Load<Texture2D>("2");
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            mouseState = Mouse.GetState();

            if (mouseState.LeftButton == ButtonState.Pressed && !isMousePressed)
            {
                isMousePressed = true;
                mouseDragPos.X = mouseState.X;
                mouseDragPos.Y = mouseState.Y;
            }

            if (mouseState.LeftButton == ButtonState.Pressed && isMousePressed)
            {
                if (mouseDragPos.X < mouseState.X)
                {
                    scrollSpan.X += mouseState.X - mouseDragPos.X;
                    mouseDragPos.X = mouseState.X; 
                }
                if (mouseDragPos.X > mouseState.X)
                {
                    scrollSpan.X -= mouseDragPos.X - mouseState.X;
                    mouseDragPos.X = mouseState.X;
                }
                if (mouseDragPos.Y < mouseState.Y)
                {
                    scrollSpan.Y += (mouseState.Y - mouseDragPos.Y) * 2;
                    mouseDragPos.Y = mouseState.Y;
                }
                if (mouseDragPos.Y > mouseState.Y)
                {
                    scrollSpan.Y -= (mouseDragPos.Y - mouseState.Y) * 2;
                    mouseDragPos.Y = mouseState.Y;
                }
            }

            if (mouseState.LeftButton == ButtonState.Released && isMousePressed)
                isMousePressed = false;

            base.Update(gameTime);
        }

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

            _spriteBatch.Begin();
            DrawMap();
            _spriteBatch.End();

            base.Draw(gameTime);
        }

        private void DrawMap()
        {
            for (int osaY = 0; osaY < map.GetLength(0); osaY++)
            {
                for (int osaX = 0; osaX < map.GetLength(1); osaX++)
                {
                    int x = osaX * 32;
                    int y = osaY * 32;

                    Texture2D thisTile = Tile1;

                    if (map[osaY, osaX] == 0)
                        thisTile = Tile1;

                    if (map[osaY, osaX] == 1)
                        thisTile = Tile2;

                    PlaceTile(thisTile, CartToIso(new Vector2(x, y)), new Vector2(osaX, osaY));
                }
            }
        }

        public void PlaceTile(Texture2D tileImage, Vector2 tilePos, Vector2 tileCoords)
        {
            _spriteBatch.Draw(tileImage, new Vector2(tilePos.X - (tileWidth / 2), tilePos.Y - tileHeight), Color.White);
        }

        public Vector2 CartToIso(Vector2 cartCoords)
        {
            Vector2 isoCoords = new Vector2(0, 0);

            isoCoords.X = (cartCoords.X + scrollSpan.X) - cartCoords.Y;
            isoCoords.Y = (cartCoords.X + scrollSpan.Y + cartCoords.Y) / 2;

            return isoCoords;
        }

        public Vector2 IsoToCart(Vector2 isoCoords)
        {
            Vector2 cartCoords = new Vector2(0, 0);

            cartCoords.X = (2 * isoCoords.Y + isoCoords.X - scrollSpan.X - scrollSpan.Y) / 2;
            cartCoords.Y = (2 * isoCoords.Y - isoCoords.X + scrollSpan.X - scrollSpan.Y) / 2;

            return cartCoords;
        }
    }
}

Upvotes: 1

Views: 1450

Answers (3)

aybe
aybe

Reputation: 16672

I'd suggest you to take a look at an answer I wrote a while ago, it does draw only the only the visible part of a level, no matter how big the level is :

I'm not copying and pasting the answer here as I wrote it already, so go and have a look at it here :

https://gamedev.stackexchange.com/a/29930/16262

Upvotes: 1

user2201501
user2201501

Reputation:

Before doing anything else, profile your code and see where the most time is being spent. Only then can you begin to optimize

Upvotes: 0

wondra
wondra

Reputation: 3583

Generally, to increase performace avoid creating unessesary objects and dont do anything you dont have to. For example you create one useless local texture in DrawMap(), also for single call of method PlaceTile you create 3 new vectors, while you need one.etc. also note, these are only minor improvements.
Another ways of speeding up might be using buffers(not sure what is default for XNA)
But most importantly, parallelize wherever you can.

Upvotes: 0

Related Questions