在C#WinForms程序中闪烁屏幕清除

本文关键字:屏幕 清除 闪烁 C#WinForms 程序 | 更新日期: 2023-09-27 18:26:43

好吧,所以我对这个主题做了一些研究,我找到的大多数解决方案都声称可以解决这个问题,但我发现它们并不完全正确。我正处于实现一个简单的小粒子引擎的早期阶段,没什么疯狂的,我只是出于无聊才这么做。我以前没有用WinForms做过这样的事情,我当然用过C/C++,但这对我来说是一件新鲜事。以下是我用来将粒子绘制到屏幕上的代码,粒子的锅炉板代码并不相关,因为它工作得很好,我更好奇我的实际游戏循环。

以下是更新和重绘的主要代码

public MainWindow()
    {
        this.DoubleBuffered = true;
        InitializeComponent();
        Application.Idle += HandleApplicationIdle;
    }
    void HandleApplicationIdle(object sender, EventArgs e)
    {
        Graphics g = CreateGraphics();
        while (IsApplicationIdle())
        {
            UpdateParticles();
            RenderParticles(g);
            g.Dispose();
        }
    }
    //Variables for drawing the particle
    Pen pen = new Pen(Color.Black, 5);
    Brush brush = new SolidBrush(Color.Blue);
    public bool emmiter = false;
    private void EmitterBtn_Click(object sender, EventArgs e)
    {
        //Determine which emitter to use
        if (emmiter == true)
        {
            //Creates a new particle
            Particle particle = new Particle(EmitterOne.Left, EmitterOne.Top, .5f, .5f, 20, 20);
            emmiter = false;
        }
        else if(emmiter == false)
        {
            Particle particle = new Particle(EmitterTwo.Left, EmitterTwo.Top, -.5f, .5f, 20, 20);
            emmiter = true;
        }
    }
    public void RenderParticles(Graphics renderer)
    {

        Invalidate();
        Thread.Sleep(0);
        //Iterate though the static list of particles
        for (int i = 0; i < Particle.activeParticles.Count; i++)
        {

            //Draw Particles
            renderer.DrawRectangle(pen, Particle.activeParticles[i].x,
                                 Particle.activeParticles[i].y,
                                 Particle.activeParticles[i].w,
                                 Particle.activeParticles[i].h);
        }
    }
    public void UpdateParticles()
    {
        for (int i = 0; i < Particle.activeParticles.Count; i++)
        {
            //Move particles
            Particle.activeParticles[i].MoveParticle();
        }
    }

我遇到的问题是,每当屏幕被清除和更新时,它都会出现可怕的闪烁,不仅如此,有时我发射粒子时也不会。

这种形式基本上只是使用标签作为屏幕上的不可见位置,来说明在哪里渲染每个粒子。

无论如何,我以前见过这个主题,但没有任何东西能解决任何问题,当前的实现是最不闪烁/滞后的,但并不能解决问题。

感谢您的帮助!

EDIT*我意识到我从未在每个循环中取消分配图形对象,所以我这样做了,每当我单击发射器按钮时都不会有更多延迟,但闪烁仍然存在,我相应地更新了代码。

在C#WinForms程序中闪烁屏幕清除

要去除可见的绘画工件需要双重缓冲。换言之,将场景渲染到后台缓冲区中,当后台缓冲区准备就绪时,可以在一步中快速闪电传输到屏幕表面。这是Winforms中的一个内置功能,只需在表单构造函数中将DoubleBuffered属性设置为true即可。必须使用"绘制"事件才能利用这一点。覆盖OnPaint()并调用RenderParticles(e.Graphics).

你需要注意时间,现在你的UI线程正在燃烧100%的核心,动画速度完全取决于粒子的数量和机器的速度。将Timer从工具箱中放到表单上,而不是Application.Iidle。在Tick事件处理程序中,调用UpdateParticles()和this。Invalidate()可使"绘制"事件再次启动。计时器的"间隔"属性值至关重要,您可以通过选择15或31毫秒(64或32 FPS)来获得最可复制的更新速率。

您并不总是能获得所需的FPS速率,如果机器繁忙或速度太慢,或者UI线程上的其他代码需要运行,计时器只会延迟或跳过Tick事件。为了确保这不会影响动画,必须测量实际经过的时间,而不是按固定的量移动粒子。Environment.TickCount、DateTime.UtcNow或Stopwatch都是测量真实运行时间的合适方法。