如何在C#windows窗体应用程序中创建形状的平滑动画运动?

如何在C#windows窗体应用程序中创建形状的平滑动画运动?,c#,winforms,animation,graphics,C#,Winforms,Animation,Graphics,我正在制作C#windows窗体应用程序,其中我希望在白色背景上制作黑色条的平滑动画运动。我尝试了以下代码,但运动是闪烁的,即使在1毫秒的时间间隔内,也无法实现平稳快速的运动 我尝试了以下代码: public Form1() { InitializeComponent(); DoubleBuffered = true; System.Windows.Forms.Timer timer1 = new System.Windows.Fo

我正在制作C#windows窗体应用程序,其中我希望在白色背景上制作黑色条的平滑动画运动。我尝试了以下代码,但运动是闪烁的,即使在1毫秒的时间间隔内,也无法实现平稳快速的运动

我尝试了以下代码:

    public Form1()
    {
        InitializeComponent();
        DoubleBuffered = true;
        System.Windows.Forms.Timer timer1 = new System.Windows.Forms.Timer();
        timer1.Interval = 30;
        timer1.Tick += Timer1_Tick;
        timer1.Enabled = true;
    }
    int x_position = 0;
    int bar_width = 40;
    int speed = 1;
    private void Timer1_Tick(object sender, EventArgs e)
    {
        x_position += speed;
        if (x_position + bar_width > this.Width) x_position = 0;
        Invalidate();
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.FillRectangle(Brushes.Black, x_position, 0, bar_width, 500);
    }
结果根本就不是平稳的运动。我在另一个问题上发现了类似于
Invalidate(true)
DoubleBuffered=true

等待帮助。谢谢

Winforms API和构建它的本机Win32窗口消息传递API根本不是为“平滑动画”而设计的。即使不是不可能,也很难实现完美平滑的动画

也就是说,可以做很多事情来改进您的上述尝试:

  • 不要使用
    CreateGraphics()
    。相反,始终绘制以响应
    Paint
    事件
  • 不要使用任何.NET计时器实现来计划渲染。取而代之的是,尽可能快地绘制,同时考虑帧间时间来更新对象位置
应用这些想法,下面是一个更好的代码版本:

const float speedXPerSecond=1000f/30;
常数整型条宽度=40;
公共表格1()
{
初始化组件();
双缓冲=真;
}
浮动x_位置=0;
TimeSpan\u lastFrameTime=TimeSpan.Zero;
秒表_frameTimer=Stopwatch.StartNew();
受保护的覆盖无效OnPaint(PaintEventArgs e)
{
基础漆(e);
TimeSpan currentFrameTime=\u frameTimer.appeased;
浮动距离=(浮动)(currentFrameTime-_lastFrameTime).TotalSeconds*speedXPerSecond;
x_位置+=距离;
而(x_位置>此.Width)x_位置-=此.Width;
e、 图形。填充矩形(画笔。黑色,x_位置,0,条形宽度,500);
_lastFrameTime=currentFrameTime;
使无效();
}
您可以将此通用技术应用于任何交互式场景。一个真实的游戏将有其他元素加入这个一般的“渲染循环”,包括用户输入和更新游戏状态(例如,基于物理模型)。这将增加渲染循环的开销,并必然降低帧速率。但对于任何基于合理的最新硬件(例如,在过去几十年中构建的)的基本游戏,净帧速率仍将远高于可接受的流畅游戏所需的帧速率

请注意,在托管的.NET/Winforms上下文中,与使用较低级别的API相比,这种方法的成功总是有限的。特别是,在没有额外工作的情况下,垃圾收集会定期中断,导致帧速率略微停顿,以及线程调度和线程消息队列的不均匀性


但根据我的经验,人们提出这类问题并不需要事情绝对完美。他们需要“足够好”,这样才能继续学习游戏开发中涉及的其他主题。

winforms中不可能实现真正的smoth动画,因为它不允许您将代码与监视器刷新同步。需要对表单进行双缓冲,以避免闪烁,并且可以正常工作。使用这个.CreateGraphics();然后gF.Clear将保证闪烁返回。用e.图形代替绘制另外:定时器的分辨率仅为25-30毫秒,不允许可靠的帧速率!使用CreateGraphics永远不会成功。您需要使用绘制事件。从绘制
事件内部移除
while(true)
Thread.Sleep(3)
Application.DoEvents()
(后者是真正的杀手)。这破坏了任何让任何事情都起作用的尝试。是
计时器。勾选
事件修改位置值并调用
无效()
(引发
绘制
事件)。计时器间隔不能小于30毫秒(您必须同时绘制内容)。此外,您不需要
.Clear(Color.White))。您正在绘制单个形状,前一个形状将不会持续。您正在控件的表面上绘制,而不是在位图中绘制(图形将保留在位图中)。不。你没有照我说的做。在
Timer.Tick
事件中,您需要重新定义对象的位置,然后调用
Invalidate()
。这将引发窗体的绘制事件。在“绘制事件处理程序”中,使用当前值来定位图形,绘制图形。不要使用
Control.CreateGraphics()
在控件的曲面上绘制。该方法不用于此类操作。计时器间隔不能设置为小于30。这是我真正需要的完美答案。非常感谢。