2

我正在为我的 C# 学校项目编写俄罗斯方块克隆。我正在使用 Microsoft Visual Studio 2012。游戏本身实现为块的二维数组(块列表列表),每个块都有自己的纹理(bmp 图像)。我将整个数组绘制到 PictureBox 控件上,这就是问题的开始。更新 PictureBox 上的图像(移动/旋转活动形状)时,游戏会稍微滞后。我尝试在 Panel 控件上绘图,但结果是一样的。我有一个粗略的想法可能导致滞后,但我不知道如何摆脱它。

这是游戏“网格”的绘制方法:

public void Draw(Graphics g)
{
   Brush brush;
   Font font = new System.Drawing.Font( "Arial", 5);
   for (int i = 0; i < Width; i++)
     for (int j = 0; j < Height; j++)
     {
          brush = new TextureBrush(Blocks[i][j].Texture);
          if (Blocks[i][j].Occupied==true)
             g.FillRectangle(brush, i * 20, j * 20, i * 20 + Blocks[i][j].Texture.Width, j * 20 + Blocks[i][j].Texture.Height); 
     }
}

这是活动四联牌的绘制方法:

public void Draw(Graphics g)
{
    Brush brush = new TextureBrush(Blocks[0].Texture);
    foreach (FullBlock b in Blocks)
       g.FillRectangle(brush, b.x * 20, b.y * 20,b.Texture.Width, b.Texture.Height);
}

然后游戏本身同时使用它们(双缓冲尝试):

public void GameDraw(PictureBox p)
{
    Graphics g = Graphics.FromImage(gb);
    gameGrid.Draw(g);
    PlayingShape.Draw(g);
    p.Image = gb;
    p.Refresh();
}

"gb"我在类构造函数中只创建一次的私有变量在哪里Bitmap(以减少(不成功)滞后)。

GameDraw每当游戏状态发生变化时,都会调用该方法(例如,移动/旋转活动的 tetromino 和每个“重力”滴答声)

4

3 回答 3

4

您需要没有设置的双缓冲。引用MSDN

双缓冲使用内存缓冲区来解决与多次绘制操作相关的闪烁问题。启用双缓冲时,所有绘制操作首先渲染到内存缓冲区而不是屏幕上的绘图表面

您可以使用Control.DoubleBuffered属性启用它

于 2013-05-14T11:32:02.997 回答
0

另外,跳出框框思考...而不是进行完整的网格扫描,您可以将每个形状作为链接列表的一部分并根据它们在网格中的位置重新绘制它们...直到您的网格完全填满,你会做更少的扫描。

或者,只考虑重绘你需要重绘的东西,即一个块落在顶部附近,不需要完全重绘整个网格。

优化是我们与动物的区别。除了鸭嘴兽,谁是最理想的生物。

于 2013-05-14T11:41:30.060 回答
0

不需要图片框,添加自己的控件:

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

namespace TetrisGame
{
    public sealed class TetrisControl : Control
    {
        private TheBlockType[][] blocks = ...;

        protected override void OnPaint(PaintEventArgs e)
        {
            //draw your stuff here direct to the control, no buffers in the middle
            //if that causes flickering, turn on double buffering, but don't bother doing it yourself
            //this is your existing draw method:
            Draw(e.Graphics);
        }
    }
}

然后在每次滴答或移动时,不要调用paint,只是使控件无效:

tetris.Invalidate();
于 2013-05-14T12:47:19.510 回答