如何使用Graphics.Draw有效地渲染切片?

时间:2016-03-29 08:44:09

标签: c# tile

我目前正在c#中制作基于图块的游戏,但每次我绘制瓷砖时都会使用大量的CPU,并且随着瓷砖变大(如果我让游戏全屏),它会消耗更多。 这是我的瓷砖类:

 public class Tiles
{
    //PRIVATE :

    //variabiles
    private int XPosition, YPosition;
    private Image Texture;
    private bool Colidable;
    private int SizeW = 32;
    private int SizeH = 32;
    private Resizer resizer = new Resizer();
    //methods




    //PUBLIC :

    //variabiles


    //methods

    //CONSTRUCTOR
    public Tiles(int _x,int _y,Image _i, int _sW = 32, int _sH = 32, bool _c = false)
    {
        XPosition = _x;//set position X
        YPosition = _y;//set position Y
        SizeW = _sW;
        SizeH = _sH;
        Texture = resizer.ResizeImage(_i, SizeW, SizeH) ;// set texture

        Colidable = _c;//set if the tile is colidable,default : false
        resizer = null;
    }

    //DRAW METHOD
    //gets graphics object to draw on, adn draws at the position of the tile
    public void Draw(Graphics _g)
    {
        _g.DrawImage(this.Texture, this.XPosition, this.YPosition);
    }

    //GET PRIVATE MEBERS
    //returns if the tile is colidable
    public bool getColidable()
    {

        return this.Colidable;

    }
}

这就是我绘制瓷砖的方式:

private void DrawMap(Graphics _g)
    {
        //CALLS THE DRAW METHOD OF EACH TILE
       for (int i = 0; i < MAP_WIDTH; i++)
        {
            for (int j = 0; j < MAP_HEIGHT; j++)
            {
                Tile[i, j].Draw(_g);
            }

        }

    }
    bool TilesUpdate = false;


    private void _Window_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.Clear(Color.Black);

        if (isGameRunning)
        {

            DrawMap(e.Graphics);
        }
        else
        {
            FullRezolutionBtn.Draw(e.Graphics);
            BigRezolutionBtn.Draw(e.Graphics);
            NormalRezolutionBtn.Draw(e.Graphics);
        }

    }


    private void Update_Tick(object sender, EventArgs e)
    {
        Invalidate();

    }

我想提一下,地图是20 x 20个图块,当全屏显示时,它占据了cpu的50%左右。

2 个答案:

答案 0 :(得分:1)

正如我在评论中所提到的,方向应该是减少绘画。一种方法是仅在与该部分相关的内容发生变化时使绘图画布的部分无效并绘制。 Windows本身对控件/窗口进行了这样的优化。

这是一个例子。看看Gadget类在某些属性发生变化时如何使其矩形无效。然后在绘画期间,仅绘制与e.ClipRectange相交的矩形。这大大减少了绘图操作的次数。

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Samples
{
    class Gadget
    {
        public readonly Control Canvas;

        public Gadget(Control canvas) { Canvas = canvas; }

        private Rectangle bounds;
        public Rectangle Bounds
        {
            get { return bounds; }
            set
            {
                if (bounds == value) return;
                // NOTE: Invalidate both old and new rectangle
                Invalidate();
                bounds = value;
                Invalidate();
            }
        }

        private Color color;
        public Color Color
        {
            get { return color; }
            set
            {
                if (color == value) return;
                color = value;
                Invalidate();
            }
        }

        public void Invalidate()
        {
            Canvas.Invalidate(bounds);
        }

        public void Draw(Graphics g)
        {
            using (var brush = new SolidBrush(color))
                g.FillRectangle(brush, bounds);
        }
    }


    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            var form = new Form { WindowState = FormWindowState.Maximized };
            int rows = 9, cols = 9;
            var gadgets = new Gadget[rows, cols];
            var rg = new Random();
            Color[] colors = { Color.Yellow, Color.Blue, Color.Red, Color.Green, Color.Magenta };
            int size = 64;
            var canvas = form;
            for (int r = 0, y = 8; r < rows; r++, y += size)
                for (int c = 0, x = 8; c < cols; c++, x += size)
                    gadgets[r, c] = new Gadget(canvas) { Color = colors[rg.Next(colors.Length)], Bounds = new Rectangle(x, y, size, size) };
            int paintCount = 0, drawCount = 0;
            canvas.Paint += (sender, e) =>
            {
                paintCount++;
                for (int r = 0; r < rows; r++)
                {
                    for (int c = 0; c < cols; c++)
                    {
                        if (e.ClipRectangle.IntersectsWith(gadgets[r, c].Bounds))
                        {
                            gadgets[r, c].Draw(e.Graphics);
                            drawCount++;
                        }
                    }
                }
                form.Text = $"Paint:{paintCount} Draw:{drawCount} of {(long)paintCount * rows * cols}";
            };
            var timer = new Timer { Interval = 100 };
            timer.Tick += (sender, e) =>
            {
                gadgets[rg.Next(rows), rg.Next(cols)].Color = colors[rg.Next(colors.Length)];
            };
            timer.Start();


            Application.Run(form);
        }
    }
}

答案 1 :(得分:0)

不确定您的缩放器类是如何工作的。我认为每次重新调整每个图像的尺寸时都会出现问题。

 Texture = resizer.ResizeImage(_i, SizeW, SizeH) ;// set texture

我会像这样替换上面的行

 Texture = _i;// set texture but do not resize image now

同时更新Tile的Draw Function,如下所示。

public void Draw(Graphics _g)
{
    //now specify the location and size of the image.
   _g.DrawImage(Texture , new Rectangle(this.XPosition, this.YPosition, SizeW, SizeH));

}

希望它应该改善性能。 如果它闪烁,那么你可以使用Double Buffer