Страницы

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

среда, 5 февраля 2020 г.

Траектория полета объекта

#c_sharp #unity3d


Задача: Отрисовать будущую траекторию полета выпущенной пули с учетом отскока пули
от препятствий. Т.е. есть персонаж. Персонаж собирается выстрелить. И когда персонаж
берет в руки оружие и начинает целится - от оружия выходит луч который показывает будущую
траекторию полета пули, при этом, если пуля рикошетит от препятствий - то и луч отражается
от них, показывая траекторию пули и после рикошета.
    


Ответы

Ответ 1



Вся суть вопроса заключается в отражении вектора, а именно, в получении нормали. Что это уже реализовано, спасибо встроенному физическому движку. Первое, что нужно получить - работающий рейкаст и нормаль: void DrawCurrentTrajectory() { Vector2 position = transform.position; Vector2 direction = firePosition.position - transform.position; RaycastHit2D hit = Physics2D.Raycast(position, direction, maximumRayCastDistance); Debug.DrawLine(position, position + direction * maximumRayCastDistance, Color.red); if (hit) { Debug.DrawLine(position, hit.point, Color.green); Debug.DrawLine(hit.point, hit.point + hit.normal * 0.25f, Color.magenta); position = hit.point + hit.normal * 0.00001f; } } Получаем все необходимые нам компоненты: Зеленый - траектория полета Фиолетовый - нормаль Красный - путь луча без препятствия Далее, отражаем луч от нормали через Vector2.Reflect и помещаем все это дело в цикл: void DrawCurrentTrajectory() { Vector2 position = transform.position; Vector2 direction = firePosition.position - transform.position; for(int i = 0; i <= maximumReflectionCount; ++i) { RaycastHit2D hit = Physics2D.Raycast(position, direction, maximumRayCastDistance); if (hit) { Debug.DrawLine(position, hit.point, Color.green); Debug.DrawLine(hit.point, hit.point + hit.normal * 0.25f, Color.magenta); position = hit.point + hit.normal * 0.00001f; direction = Vector2.Reflect(direction, hit.normal); } } } И получаем уже похожий на правду результат: Код выше рисует траекторию только в редакторе и только в Scene View. Способов отрисовать траекторию в игре, я подозреваю, масса, но остановимся на LineRenderer: public class RicochetTrajectory : MonoBehaviour { public Transform firePosition; public int maximumReflectionCount = 5; public float maximumRayCastDistance = 50f; LineRenderer lineRenderer; List reflectionPositions = new List(); private void Awake() { lineRenderer = GetComponent(); lineRenderer.startWidth = 0.1f; lineRenderer.endWidth = 0.1f; } void Update() { DrawCurrentTrajectory(); } void DrawCurrentTrajectory() { reflectionPositions.Clear(); Vector2 position = transform.position; Vector2 direction = firePosition.position - transform.position; reflectionPositions.Add(position); for(int i = 0; i <= maximumReflectionCount; ++i) { RaycastHit2D hit = Physics2D.Raycast(position, direction, maximumRayCastDistance); if (hit) { position = hit.point + hit.normal * 0.00001f; direction = Vector2.Reflect(direction, hit.normal); reflectionPositions.Add(position); } } lineRenderer.positionCount = reflectionPositions.Count; lineRenderer.SetPositions(reflectionPositions.ToArray()); } } Получаем результат: Количество отражений можно изменять хоть до бесконечности, но все упирается в производительность машины: P.S. Зачем нужно сдвигать точку отражения по нормали к поверхности? position = hit.point + hit.normal * 0.00001f; Если ее не сдвинуть, рейкаст может задеть этот же коллайдер: P.P.S Непосредственно формула отражения вектора относительно нормали: Vector2 ReflectVector(Vector2 vec, Vector2 normal) { return vec - 2 * Vector2.Dot(vec, normal) * normal; } Данная формула подходит для вектора любой размерности.

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

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