#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; ListreflectionPositions = 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; } Данная формула подходит для вектора любой размерности.
Комментариев нет:
Отправить комментарий