Не могу понять что представляет собой скалярное произведение в детекте игрока
нашла код детекта игрока и не могу понять некоторые вещи.
Вот сам код:
Vector3 toPlayer = player.transform.position - enemy.transform.position;
if (toPlayer.magnitude < detectRadius)
{
if (Vector3.Dot(toPlayer.normalized, enemy.transform.forward) >
Mathf.Cos(90 * 0.5f * Mathf.Deg2Rad))
{
Debug.Log("Player has been found");
}
Вопросов по коду несколько:
Правильно ли я поняла что нет разницы между
player.transform.position - enemy.transform.positionиenemy.transform.position - player.transform.positionв плане детекта игрока? Проверяла вроде и так и так игрок детектится одинаково.Vector3.Dot(toPlayer.normalized, enemy.transform.forward: Тут считается скалярное произведение, так сказать в представлении единичной окружности врага, то есть после того, как игрок вошёл в зону дистанции (Выполнено верхнее условие), выполняется проверка того попал ли игрок в радиус детекта который рассчитывается косинусом от положения врага или нет. Это я правильно понимаю? И ещё мне не понятно почему тут рассчитывается именноtoPlayer.normalized, enemy.transform.forwardкак они вообще относятся к косинусу? Ну например получается значение, а почему именно из нихПочему не используется нормализация
enemy.transform.forward?
Сложновато представить это действо в представлении единичной окружности
Ответы (2 шт):
1 Обращение направления вектора не влияет на его длину, т.е. радиус обнаружения, но важно для расчёта скалярного произведения
2,3 Можно предположить, что forward всегда нормализованный. Тогда скалярное произведение нормализованного вектора направления на игрока и forward говорит о том, находится ли игрок в конусе с углом 45 градусов перед врагом -в этом можно убедиться на двумерном примере - вектор u с углом от forward менее 45 градусов, скалярное произведение (косинус угла между ними) больше косинуса 45, а для векторов v, w (и -u) это не выполняется
Скалярное произведение это просто сумма перемножения осей x1*x2+y1*y2. В программировании эту функцию называют Dot, у Vector2 и Vector3 она есть.
Но если использовать нормали векторов (длинной 1), то мы получим косинус разницы их угла, от 1 направлены в одну сторону, до -1 направлены в противоположные стороны! Это ось х на круге.
float[] d = new float[5];
d[0] = Vector2.Dot(new Vector2(1, 0), new Vector2(1, 0));
d[1] = Vector2.Dot(new Vector2(1, 0), new Vector2(1, 1).normalized);
d[2] = Vector2.Dot(new Vector2(1, 0), new Vector2(0, 1));
d[3] = Vector2.Dot(new Vector2(1, 0), new Vector2(-1, 1).normalized);
d[4] = Vector2.Dot(new Vector2(1, 0), new Vector2(-1, 0));
for (int i = 0; i < 5; i++)
Debug.Log(i + " " + d[i].ToString("N3") + " -> " + (Mathf.Acos(d[i]) * Mathf.Rad2Deg) + "°");
// 0 1,000 -> 0°
// 1 0,707 -> 45°
// 2 0,000 -> 90°
// 3 -0,707 -> 135°
// 4 -1,000 -> 180°
Таким образом сравнив направление поворота персонажа с вектором до цели, мы можем понять попадет ли его центр в угол обзора персонажа, просто по косинусу угла этого обзора и скалярному произведению этих векторов. Работает как для плоскости Vector2, так и в объёме Vector3, например для шутеров.
Если угол обзора 90° (0.5π), то есть разница векторов должна быть менее, чем 45° (0.25π). Косинус должен быть в промежутке от Mathf.Cos(90 * 0.5f * Mathf.Deg2Rad) = 0.7071068 до 1, меньшие значения от -1 до 0.7071068 не попадут в угол обзора. Математику легко понять по иллюстрации выше.

