防止移动物体闪烁

本文关键字:闪烁 移动 | 更新日期: 2023-09-27 18:22:38

我正在尝试为windows窗体中的分配制作一个突破游戏,我以前也制作过游戏,但我以前从未使用过winforms。我发现了一些有用的东西,比如OnPaint()(您应该覆盖它)、DoubleBuffered and Invalidate`。但我只是在努力将它应用于我的代码

这是我的:

 int xSpeed, ySpeed;
    Graphics display;
    Brush brush;
    Rectangle ballRect;
    public Form1()
    {
        InitializeComponent();

        timer1.Enabled = true;
        timer1.Interval = 1;
        xSpeed = 5;
        ySpeed = 5;
        ballRect = new Rectangle(10, 10, 20, 20);
        display = this.CreateGraphics();
        brush = new SolidBrush(Color.Red);

    }
    private void timer1_Tick(object sender, EventArgs e)
    {
        DoubleBuffered = true;
        ballRect.X += xSpeed;
        ballRect.Y += ySpeed;
        if (ballRect.X >= 469)
            xSpeed = -xSpeed;
        if (ballRect.Y >= 457)
            ySpeed = -ySpeed;
        if (ballRect.X <= 0)
            xSpeed = -xSpeed;
        if (ballRect.Y <= 0)
            ySpeed = -ySpeed;
        display.Clear(Color.White);
        display.FillEllipse(brush, ballRect);
    }

我在Update方法(timer1_tick)中绘制球,但我觉得我不应该这样做。感谢:)

防止移动物体闪烁

您可以创建自定义ControlForm和:

  • 在构造函数中设置无闪烁绘画的样式OptimizedDoubleBufferUserPaintAllPaintingInWmPaint
  • 在构造函数中,如果大小更改ResizeRedraw,则设置重画的样式
  • Tick事件中,只更新球的位置,然后Invalidate控制
  • 覆盖控件的OnPaint方法,并将绘制逻辑放在那里
  • 此外,您应该使用速度或球大小的属性,以便在这些值更改时使控件无效。(我没有在下面的代码中实现属性。)此外,您可以稍微增加间隔

例如:

public partial class CustomControl1 : Control
{
    public CustomControl1()
    {
        InitializeComponent();
        this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
        this.SetStyle(ControlStyles.UserPaint, true);
        this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        this.SetStyle(ControlStyles.ResizeRedraw, true);
        timer1.Enabled = true;
        timer1.Interval = 1;
        xSpeed = 5;
        ySpeed = 5;
        ballRect = new Rectangle(10, 10, 20, 20);
        brush = new SolidBrush(Color.Red);
    }
    protected override void OnPaint(PaintEventArgs pe)
    {
        pe.Graphics.FillEllipse(brush, ballRect);
    }
    int xSpeed, ySpeed;
    Brush brush;
    Rectangle ballRect;
    private void timer1_Tick(object sender, EventArgs e)
    {
        ballRect.X += xSpeed;
        ballRect.Y += ySpeed;
        if (ballRect.X + ballRect.Width >= this.Width)
            xSpeed = -xSpeed;
        if (ballRect.Y + ballRect.Height >= this.Height)
            ySpeed = -ySpeed;
        if (ballRect.X <= 0)
            xSpeed = -xSpeed;
        if (ballRect.Y <= 0)
            ySpeed = -ySpeed;
        this.Invalidate();
    }
}

闪烁是因为您直接绘制到显示器上。首先清除显示,用户会在一瞬间看到,然后在上面画一个圆圈,在重复过程之前只显示很短的时间。这种"透支"就是闪烁的来源。

消除它的一种方法是对内存位图进行所有绘制,完成后将整个位图移动到显示器上。

我在代码中看到的另一个问题是,在构造函数中创建一个Graphics实例,并在程序的整个生命周期中保留它。这是你应该避免的模式。相反,您应该为每个"帧"创建一个新的Graphics对象,最好是在using语句中。这将确保一切都得到妥善清理。