Мне нужно реализовать простую анимацию шара, движущегося в равномерном круговом движении. Я пробовал несколько формул, и следующая версия кажется лучшей до сих пор. Однако есть еще две проблемы, и я действительно не могу понять, что не так. Сначала, через пару секунд сразу после запуска программы, шар перемещается беспорядочно. Я думаю, что значения для theta (угол в радианах) вычисляются неправильно, но я не знаю почему. Во-вторых, через некоторое время движение становится более равномерным, но со временем оно со временем уменьшается. Значение «скорость» указывает количество секунд, необходимое для полного оборота. То, что я хочу, - это равномерное, правильное круговое движение (в соответствии со значением скорости) и без дряхлости в начале.C# Равномерное круговое движение
Мой код до сих пор:
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 просто класс держит координаты & текущую скорость. Являются ли единицы измерения для времени & угловой скоростью (и преобразованиями использования милисекунд) правильно?
UPDATE: изменил BackgroundWorker на Timer, но я все еще получаю это неустойчивое движение, и движение замедляется через некоторое время.
Это может сгладить вещи, чтобы использовать анимацию, основанную на времени, а не анимацию на основе кадра. Время, сколько времени прошло с момента создания кадра и использования его для анимаций, зависящих от времени. Это будет намного более точной, чем предполагать, что это было такое же количество времени каждый раз (даже если вы указываете ожидание в свой 'Thread.Sleep()'). –
Вам нужно избавиться от своей «кисти», которую вы создаете в своей функции «OnPaint». (а не источник вашей проблемы, но это может привести к другим проблемам, связанным с GDI +). –
Я сбросил BackgroundWorker и использовал таймер (интервал 100 мс), но он по-прежнему ведет себя одинаково. Тета достигает значений> 100, разве это не должно быть в [0, 2 * PI], если я рассматриваю радианы? – joanna