【问题标题】:How to render tiles efficiently using Graphics.Draw?如何使用 Graphics.Draw 有效地渲染图块?
【发布时间】:2016-03-29 08:44:09
【问题描述】:

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

 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 的图块,全屏时它消耗了大约 50% 的 CPU。

【问题讨论】:

  • 您发布的代码看起来不错,我不知道如何加快速度。尝试智能失效和智能绘图(即仅绘制失效部分)
  • 如何检查零件是否失效?
  • e.ClipRectangle.IntersectsWith(part.Rectangle)
  • 抱歉,我不明白智能失效是如何工作的……我尝试过裁剪,我可以渲染地图的智能部分。你能举个例子说明ClipRectangle.IntersectsWith(part.Rectangle)是如何工作的吗?
  • 当然。你会在屏幕上移动那些瓷砖吗?或者上面的东西?还是换头像?

标签: c# tile


【解决方案1】:

正如我在 cmets 中提到的,方向应该是减少绘画。一种方法是仅当与该部分相关的内容发生更改时才使绘图画布的某些部分无效并绘制。 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);
        }
    }
}

【讨论】:

  • 非常感谢!这正是我想要的!非常感谢!
【解决方案2】:

不确定您的调整器类是如何工作的。我认为每次重新调整每张图片的大小时都会出现问题。

 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-12
    • 1970-01-01
    相关资源
    最近更新 更多