【发布时间】:2014-01-09 21:27:16
【问题描述】:
我需要实现一个球以匀速圆周运动移动的简单动画。我已经尝试了几个公式,到目前为止,以下版本似乎是最好的。但是,仍然存在 2 个问题,我真的不知道出了什么问题。
首先,在程序开始后的几秒钟内,球的移动不规律。我认为 theta 的值(以弧度为单位的角度)计算不正确,但我不知道为什么。
其次,一段时间后运动变得更加均匀,但似乎随着时间的推移而减少。
The value for 'speed' indicates the number of seconds it takes to do a full revolution.
我想要的是一个均匀、正确的圆周运动(根据速度的值),并且在开始时没有急动。
到目前为止我的代码:
public partial class ServerForm : Form
{
Stopwatch watch;
//Angular velocity
float angularVelocity;
//Angle
float theta = 20;
//Speed - time to complete a full revolution, in seconds
private float speed = 3;
//Circle center
private int centerX = 250;
private int centerY = 200;
//Circle radius
private float R = 120;
//Current position
private LocationData currentLocation;
public ServerForm()
{
InitializeComponent();
}
public void UpdateUI()
{
currentLocation.CoordX = (float)(centerX + Math.Cos(theta) * R);
currentLocation.CoordY = (float)(centerY + Math.Sin(theta) * R);
currentLocation.Speed = speed;
try
{
this.Invoke(new Action(() => { this.Invalidate(); }));
}
catch (Exception ex)
{
watch.Stop();
Application.Exit();
}
theta += (float)((angularVelocity * 1000 / watch.ElapsedMilliseconds));
//Console.Out.WriteLine("elapsed miliseconds: " + watch.ElapsedMilliseconds + " theta = " + theta);
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Brush color = new SolidBrush(Color.BlueViolet);
g.FillEllipse(color, currentLocation.CoordX, currentLocation.CoordY, 30, 30);
//Draw circle & center
g.DrawEllipse(new Pen(color), centerX, centerY, 5, 5);
float x = centerX - R;
float y = centerY - R;
float width = 2 * R;
float height = 2 * R;
g.DrawEllipse(new Pen(color), x, y, width, height);
base.OnPaint(e);
}
private void button1_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(textSpeed.Text))
{
ResetValues(float.Parse(textSpeed.Text));
}
}
private void ResetValues(float newSpeed)
{
speed = newSpeed;
angularVelocity = (float)(2 * Math.PI / speed); // radians / sec
//Start at the top
currentLocation.CoordX = centerX;
currentLocation.CoordY = centerY - R;
theta = 90;
watch.Restart();
}
private void ServerForm_Load(object sender, EventArgs e)
{
watch = new Stopwatch();
timer1.Enabled = true;
timer1.Interval = 100;
timer1.Tick += timer1_Tick;
currentLocation = new LocationData();
ResetValues(speed);
}
void timer1_Tick(object sender, EventArgs e)
{
UpdateUI();
}
}
LocationData 只是一个保存坐标和当前速度的类。 时间和角速度的单位(以及使用毫秒的转换)是否正确?
我将 BackgroundWorker 更改为 Timer,但我仍然会出现这种不稳定的运动,并且一段时间后运动会变慢。
【问题讨论】:
-
使用基于时间的动画而不是基于帧的动画可能会使事情变得平滑。时间 自上次生成帧并将其用于与时间相关的动画以来已经过去了多长时间。这将比假设每次都是相同的时间要准确得多(即使您在
Thread.Sleep()中指定了等待时间)。 -
您需要处理您在
OnPaint函数中创建的Brush。 (不是问题的根源,但可能导致其他 GDI+ 相关问题) -
我删除了 BackgroundWorker 并使用了 Timer(100 毫秒间隔),但它的行为仍然相同。 Theta 达到 > 100 的值,如果我考虑弧度,它不应该在 [0, 2*PI] 中吗?