Страницы

Поиск по вопросам

четверг, 2 мая 2019 г.

Unity 5 движение по кругу через поворот

Тело двигается по следующему алгоритму. Сначала выбирается случайный угол, на который происходит поворот тела, затем задается Vector2.up и тело летит в направлении поворота. Как сделать чтобы тело двигалось по кругу? Знаю, что необходимо использовать тригонометрические функции, но как конкретно - не знаю.


Ответ

Вспоминаем геометрию. Уравнение окружности имеет вид:
(x - a)² + (x - b)² = R²
где
a, b - координаты центра окружности
R - радиус окружности
Уравнение окружности радиуса R с центром в начале координат:
x² + y² = R²
Это поможет нам узнать переменные в другом представлении окружности: в параметрическом уравнении:
x = R * cos(alpha) + a y = R * sin(alpha) + b
в центре координат:
x = R * cos(alpha) y = R * sin(alpha)
Видим знакомые данные и еще дополнительную: alpha. Думаю понятно, что это угол. Меняем угол альфа и получаем движение по окружности.
Все это переносим в Unity.
Итак:
public float angle = 0; // угол public float radius = 0.5f; // радиус public bool isCircle = false; // условие движения по кругу
Допустим в какой-то момент времени нужно, чтоб объект начал движение по кругу, а значит нужно изменять постепенно угол и передавать значение в координаты. Угол можно менять например в Update, который будет каждый фрейм вызываться. Тогда получится простая формула:
void Update () { if (isCircle) { angle += Time.deltaTime; // меняется плавно значение угла
var x = Mathf.Cos (angle * speed) * radius; var y = Mathf.Sin (angle * speed) * radius; transform.position = new Vector2(x, y); } }
Когда нужно прекратить движение по кругу, выставляем isCircle в false и обнуляем угол angle = 0;
Всё.
Для движения вокруг какого-то центра не забываем добавить это условие в координаты. Например центр с координатами 1, 1.5; Формула будет например такая:
var x = Mathf.Cos (angle * speed) * radius; var y = Mathf.Sin (angle * speed) * radius; transform.position = new Vector2(x, y) + new Vector2(1, 1.5);

По часовой или против часовой?
Тут всё банально просто. Нужно одну из координат умножить дополнительно на -1. Если умножить X, то движение пойдет так, как будто находитесь на отметке 180°

Если умножить Y, то с отметки 0°:

Если я ничего не путаю))
Вот банальное и в очень сыром виде движение тела вперед, а при изменении параметра isCircle в true летит против часовой стрелки ровно с того места, где находится (для этого в формуле еще один параметр new Vector2(radius, 0) для компенсации направления движения).
using UnityEngine; public class Testy: MonoBehaviour { public float angle = 0; public float speed = 1; public float radius = 0.5f; public bool isCircle = false; // запоминать свое нахождение и делать его центром окружности public Vector2 cachedCenter; void Update() { if (isCircle) { angle += Time.deltaTime; var x = Mathf.Cos(angle * speed) * radius; var y = Mathf.Sin(angle * speed) * radius; transform.position = new Vector2(x, y) + cachedCenter - new Vector2(radius, 0); } else { angle = 0; cachedCenter = transform.position; var x = transform.position.x; var y = transform.position.y; x += 0.5f * Time.deltaTime; transform.position = new Vector2(x, y); } } }

Ну и по поводу движения по синусоиде. Тут немного по-другому. По одной оси мы просто движемся, а по другой, так сказать "вихляем".
Я попробую просто написать две формулы, попробуйте разобраться с ними сами)))
1) Движение вперед, "вихляет" вниз-вверх:
using UnityEngine; public class Testy2: MonoBehaviour { public float MoveSpeed = 0.5f; public float frequency = 3.0f; // Скорость виляния по синусоиде public float magnitude = 0.5f; // Размер синусоиды (радиус, по сути..можно заменить на "R") private Vector3 axis; private Vector3 pos; void Start() { pos = transform.position; axis = transform.up; } void Update() { pos += transform.right * Time.deltaTime * MoveSpeed; transform.position = pos + axis * Mathf.Sin(Time.time * frequency) * magnitude; } }
2) Движение вверх, "вихляет" влево-вправо:
using UnityEngine; public class Testy2: MonoBehaviour { public float MoveSpeed = 0.5f; public float frequency = 3.0f; // Скорость виляния по синусоиде public float magnitude = 0.5f; // Размер синусоиды (радиус, по сути..можно заменить на "R") private Vector3 axis; private Vector3 pos; void Start() { pos = transform.position; axis = transform.right; } void Update() { pos += transform.up * Time.deltaTime * MoveSpeed; transform.position = pos + axis * Mathf.Sin(Time.time * frequency) * magnitude; } }

Комментариев нет:

Отправить комментарий