我正在制作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
事件做出反应。应用这些想法,这里是你的代码的一个版本,作品多好:
const float speedXPerSecond = 1000f / 30;
const int bar_width = 40;
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
}
float x_position = 0;
TimeSpan _lastFrameTime = TimeSpan.Zero;
Stopwatch _frameTimer = Stopwatch.StartNew();
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
TimeSpan currentFrameTime = _frameTimer.Elapsed;
float distance = (float)(currentFrameTime - _lastFrameTime).TotalSeconds * speedXPerSecond;
x_position += distance;
while (x_position > this.Width) x_position -= this.Width;
e.Graphics.FillRectangle(Brushes.Black, x_position, 0, bar_width, 500);
_lastFrameTime = currentFrameTime;
Invalidate();
}
您可以将此通用技术应用于任何交互式方案。真实游戏将具有此一般“渲染循环”的其他元素,包括用户输入和更新游戏状态(例如,基于物理模型)。这些将增加渲染循环的开销,并且必然会降低帧速率。但是,对于使用任何合理最新硬件(例如,在过去的几十年中构建)的任何基本游戏,其净帧速率仍将远远高于可接受的流畅游戏所需的帧速率。
请注意,在托管.NET / Winforms上下文中,与使用较低级别的API相比,此方法的成功始终受到限制。特别是,如果您没有进行任何额外的工作,则垃圾收集将定期中断,从而导致帧速率稍微停滞不前,以及线程调度和线程的消息队列中的不均匀性。
但是根据我的经验,人们提出这样的问题并不需要绝对完美。他们需要“足够好”,这样他们才能继续学习游戏开发中涉及的其他主题。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句