等距瓦片引擎优化以获得更好的FPS

时间:2014-01-14 22:21:39

标签: c# xna tile monogame isometric

我有一个用XNA(Monogame)编写的等距瓷砖引擎。它只能绘制瓷砖地图表面。但是当我有更大的地图(例如50x50瓷砖)时,则非常慢(大约15 FPS)。当我有小地图(例如10x10瓷砖)时,framrate是完美的(60 FPS)。

我正试图找到如何优化我的代码的方法,但我不知道该怎么做。

这是我的代码:

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;
        }
    }
}

3 个答案:

答案 0 :(得分:1)

我建议你看看我刚才写的一个答案,它确实只绘制了一个级别中唯一可见的部分,无论级别有多大:

我没有在我写这篇文章的时候复制和粘贴答案,所以去看看吧:

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

答案 1 :(得分:0)

通常,要提高性能,请避免创建unessesary对象,也不要做任何你不需要的事情。例如,你在DrawMap()中创建一个无用的局部纹理,也可以为方法PlaceTile单个调用创建3个新向量,同时需要one.etc。另请注意,这些只是次要改进 加速的另一种方法可能是使用缓冲区(不确定XNA的默认值)
但最重要的是,尽可能并行化。

答案 2 :(得分:0)

在执行任何其他操作之前,请对您的代码进行分析,并查看花费最多时间的位置。只有这样才能开始优化