如何在C#windows窗体应用程序中创建形状的平滑动画运动?
我正在制作C#windows窗体应用程序,其中我希望在白色背景上制作黑色条的平滑动画运动。我尝试了以下代码,但运动是闪烁的,即使在1毫秒的时间间隔内,也无法实现平稳快速的运动 我尝试了以下代码:如何在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
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。这是我真正需要的完美答案。非常感谢。