Кнопка, чувствительная к движению мыши

Нужно реализовать кнопку, чувствительную к движению мыши, которая при наведении на нее должна двигаться в любую из сторон от курсора. Реализовать смог только так:

 Random rnd = new Random();
    private void button1_MouseMove(object sender, MouseEventArgs e)
    {
        button1.Location = new Point(rnd.Next(this.Width - button1.Width), rnd.Next(this.Height - button1.Height));
    }

Но по итогу кнопка не двигается, а перемещается мгновенно на другую точку. Как мне реализовать ее передвижение ?


Ответы (1 шт):

Автор решения: aepot

Здесь нужно немного математики и совсем капелька асинхронного программирования.

К примеру, нужна (самодельная) анимация передвижения с частотой отрисовки 30 кадров в секунду, тогда задержка между кадрами будет 1 / 30 = 33мс. Следовательно нужен цикл, тело которого будет выполняться примерно раз в 33 миллисекунды.

Теперь нужно определиться с шагом, здесь нужно выяснить, а сколько времени кнопка будет "бежать" из одной точки в другую. Давайте допустим, что это 1 секунда, тогда шаг - это будет расстояние поделенное на количество "кадров" в 1 секунде, то есть 30. Тогда шаг - это будет 1/30 расстояния от старого положения кнопки до нового.

Ну и реализовать теперь это интуитивно просто.

private bool isRunning; // защита от повторного запуска новой анимации до окончания предыдущей
// async метод
private async void button1_MouseMove(object sender, MouseEventArgs e)
{
    if (isRunning) return;
    isRunning = true;
    int x = button1.Location.X;
    int y = button1.Location.Y;
    int duration = 1000; // длительность в миллисекундах
    int fps = 30 * duration / 1000; // 30 кадров/сек, но длительность может отличаться от 1000, поэтому пересчёт
    int delay = duration / fps;

    int newX = rnd.Next(this.Width - button1.Width);
    int newY = rnd.Next(this.Height - button1.Height);
    int stepX = (newX - x) / fps;
    int stepY = (newY - y) / fps;
    for (int i = 0; i < fps; i++)
    {
        button1.Location = new Point(x + stepX * i, y + stepY * i);
        await Task.Delay(delay); // асинхронное ожидание
    }
    // конечные координаты могут быть не точными из-за округления, поэтому я добавил вот это, чтобы исправить
    button1.Location = new Point(newX, newY); 
    isRunning = false;
}
→ Ссылка