Приветствую! Хочу вам показать один из способов, как реализовать свободное перемещение частиц в указанном диапазоне. Для выполнения этой задачи я буду использовать ReactJS. Но сам алгоритм все равно будет общим, и вы можете его использовать где угодно.
В конце статьи, мы создадим с вами такую штуку.
Первое, что приходит в голову для решения этой задачи, это просто рандомить X и Y. Давайте посмотрим, что из этого получится.
Здесь мы просто рандомим сдвиг каждую секунду в промежутке от -50 до 50 по X и по Y:
А плавность перехода осуществляется при помощи css свойства transition:
Как видите – получилось не совсем то, что мы хотели. Конечно можно настроить так, чтобы сдвиг добавлялся к уже существующей позиции, тогда будет больше похоже на правду. Но все равно нам нужно зайти немного с другой стороны.
Предыдущий метод кажется таким кривым по нескольким причинам:
И это наводит на мысль, что рандомить нужно именно направление, в котором будет двигаться частица, причем в определенном интервале градусов, чтобы не было резких поворотов. Так мы решим первую проблему.
А для решения второй проблемы, мы будем заранее указывать шаг, на который нужно сдвигать частицу за интервал времени.
Теперь придется вспомнить базовый курс тригонометрии. Нам известна длина
У нас получатся следующие формулы для вычисления:
Но есть одно но. В javaScript
Напишем функцию, которая на вход будет получать угол, и расстояние на которое нужно сдвинуть частицу. А возвращать функция будет объект
Потестим, что будет выводить наша функция. Допустим, мы будем каждый раз сдвигать частицу на
Ну что же, похоже на правду, согласны?
Теперь попробуем исправить наше первое написанное приложение.
Уже неплохо! Осталось реализовать рамки, за которые частица не сможет вылетать. Так как сейчас скорее всего через какое-то время синий круг улетит за пределы экрана.
Для того, чтобы сделать рамки, нужно будет добавить новую константу. А также добавить одно условие. Здесь нам подойдет цикл while. Если на пути встретится ограничение, то мы будем поворачивать угол до тех пор, пока на вывернем от рамки.
Для наглядности добавим желтый квадрат, за пределы которого круг не сможет вылетать. Вот что получилось:
Наш алгоритм полностью готов к использованию. Следующий шаг – это реализация данного алгоритма на ReactJS c использованием его возможностей.
При переносе нашего приложения на ReactJS поставим перед собой следующие задачи:
В результате получим следующий пример:
Исходные данные будем брать из массива
После этого описываем компонент
После этого с помощью цикла
Спасибо за внимание! Это была моя первая статья на хабре, надеюсь она будет полезна. Пробуйте, экспериментируйте.
В конце статьи, мы создадим с вами такую штуку.
Неправильный способ
Первое, что приходит в голову для решения этой задачи, это просто рандомить X и Y. Давайте посмотрим, что из этого получится.
Здесь мы просто рандомим сдвиг каждую секунду в промежутке от -50 до 50 по X и по Y:
Math.random() * 100 - 50
А плавность перехода осуществляется при помощи css свойства transition:
transition: transform 1s linear;
Как видите – получилось не совсем то, что мы хотели. Конечно можно настроить так, чтобы сдвиг добавлялся к уже существующей позиции, тогда будет больше похоже на правду. Но все равно нам нужно зайти немного с другой стороны.
Правильный способ
Предыдущий метод кажется таким кривым по нескольким причинам:
- В реальности частица не может так резко менять направление.
- Частица за каждый отрезок времени должна проходить определенное расстояние
И это наводит на мысль, что рандомить нужно именно направление, в котором будет двигаться частица, причем в определенном интервале градусов, чтобы не было резких поворотов. Так мы решим первую проблему.
А для решения второй проблемы, мы будем заранее указывать шаг, на который нужно сдвигать частицу за интервал времени.
Теперь придется вспомнить базовый курс тригонометрии. Нам известна длина
l
и угол deg
. Нужно найти X
и Y
.sin — отношение противолежащей стороны к гипотенузе.
cos — отношение прилежащей стороны к гипотенузе.
У нас получатся следующие формулы для вычисления:
x = cos(deg) * l
y = sin(deg) * l
Но есть одно но. В javaScript
Math.sin
принимает угол в радианах (значение от -1 до 1). Поэтому прежде чем пробрасывать угол, нужно его предварительно перевести в радианы.deg(рад) = deg(гр) * Pi / 180
Напишем функцию, которая на вход будет получать угол, и расстояние на которое нужно сдвинуть частицу. А возвращать функция будет объект
{ x, y }
c нашими значениями для сдвига.
function getShift(deg, step) {
return {
x: +(Math.cos(deg * Math.PI / 180) * step).toFixed(),
y: +(Math.sin(deg * Math.PI / 180) * step).toFixed(),
};
};
Потестим, что будет выводить наша функция. Допустим, мы будем каждый раз сдвигать частицу на
10px
. Посмотрим, что вернет getShift
при разных значениях углов.
getShift(30, 10); // {x: 9, y: 5}
getShift(90, 10); // {x: 0, y: 10}
getShift(135, 10); // {x: -7, y: 7}
getShift(210, 10); // {x: -9, y: -5}
getShift(-30, 10); // {x: 9, y: -5}
Ну что же, похоже на правду, согласны?
Теперь попробуем исправить наше первое написанное приложение.
Уже неплохо! Осталось реализовать рамки, за которые частица не сможет вылетать. Так как сейчас скорее всего через какое-то время синий круг улетит за пределы экрана.
Для того, чтобы сделать рамки, нужно будет добавить новую константу. А также добавить одно условие. Здесь нам подойдет цикл while. Если на пути встретится ограничение, то мы будем поворачивать угол до тех пор, пока на вывернем от рамки.
Для наглядности добавим желтый квадрат, за пределы которого круг не сможет вылетать. Вот что получилось:
Наш алгоритм полностью готов к использованию. Следующий шаг – это реализация данного алгоритма на ReactJS c использованием его возможностей.
Переносим алгоритм на ReactJS
При переносе нашего приложения на ReactJS поставим перед собой следующие задачи:
- Создадим компонент-обертку
MovingPart
в которую можно будет прокинуть что угодно. - В состоянии будем хранить значения X и Y, так как только они нужны для перерисовки компонента.
- Снаружи в компонент будем прокидывать интервал, границу, за которую нельзя выходить и шаг, на который будет сдвигаться элемент за один интервал времени.
- Отрисуем небольшую красивость с несколькими компонентами
MovingPart
, для того, чтобы примерно представить, где это может применяться в реальной жизни
В результате получим следующий пример:
Исходные данные будем брать из массива
data
.После этого описываем компонент
MovingPart
:- Интервал (interval), расстояние (distance) и сдвиг за один шаг (step) получаем снаружи из props;
- Максимальный поворот при движении (maxRotate) и текущий угол сдвига (deg) определяем внутри элемента;
- Значения x и y выносим в состояние компонента;
- Метод getShift определяем как внутренний метод компонента.
После этого с помощью цикла
map
рендерим все элементы, оборачивая их нашим созданным компонентом MovingPart
.Спасибо за внимание! Это была моя первая статья на хабре, надеюсь она будет полезна. Пробуйте, экспериментируйте.
inoyakaigor
В Firefox что-то пошло не так:
vladikin
вроде как
backface-visibility: hidden
должен помочь:vital_pavlenko Автор
Признаюсь, первый раз слышу про это свойство. Но это действительно помогло! Спасибо