Определение направления 2D вектора с 8 дискретными направлениями (горизонтальное, вертикальное и диагонали) - PullRequest
0 голосов
/ 20 ноября 2011

У меня есть ввод джойстика геймпада, это вектор.Диапазон значений вектора определяет окружность в прямоугольнике, который охватывает -1, -1 до +1, + 1.

Я хочу знать, к какому из 8 возможных направлений вектор подходит.Не беспокойтесь о случае, когда вектор равен (0, 0), я буду разбираться с этим отдельно. Как я могу это сделать?

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

Ответы [ 3 ]

2 голосов
/ 20 ноября 2011

Представьте квадрат внутри квадрата -1..1, где позиция палки (X) находится на одной из сторон:

+-----------------+  +-----------------+
|                 |  |                 |
|                 |  |                 |
|          X      |  |    +-----X-+    |
|                 |  |    |       |    |
|        O        |  |    |   O   |    |
|                 |  |    |       |    |
|                 |  |    +-------+    |
|                 |  |                 |
|                 |  |                 |
+-----------------+  +-----------------+

Вам просто нужно выяснить, на какой стороне находятся координатыи проверьте, находится ли он ближе к центру стороны или в углу.Если внутренний квадрат слишком мал, вы можете считать палку центрированной.

Что-то вроде:

Public enum Direction {
  None,
  LeftUp, Up, RightUp, Right, RightDown, Down, LeftDown, Left
}

public Direction GetDirection(double x, double y) {
  double absX = Math.Abs(x);
  double absY = Math.Abs(y);
  if (absX < 0.1 && absY < 0.1) {
    // close to center
    return Direction.None;
  }
  if (absX > absY) {
    // vertical side
    double half = absX * 0.4142;
    if (x > 0) {
      // left side
      if (y > half) return Direction.LeftDown;
      if (y < -half) return Diretion.LeftUp;
      return Direction.Left;
    } else {
      // right side
      if (y > half) return Direction.RightDown;
      if (y < -half) return Direction.RightUp;
      return Direction.Right;
    }
  } else {
    // horisontal side
    double half = absY * 0.4142;
    if (y > 0) {
      // bottom
      if (x > half) return Direction.RightDown;
      if (x < -half) return Direction.LeftDown;
      return Direction.Down;
    } else {
      // top
      if (x > half) return Direction.RightUp;
      if (x < -half) return Direction.LeftUp;
      return Direction.Up;
    }
  }
}

Нет тригонометрии, только простые сравнения, поэтому он должен быть довольно быстрым.:)

(Хотя я использовал тригонометрию для вычисления точки 0,4142, которая является загаром (22,5), или положения на стороне, где угол равен 45/2.)

1 голос
/ 20 ноября 2011

sin a / cos a = tan a,

и у вас есть

Y = sin a

X = cos a

Итак, применитеобратная касательная к Y / X, и вы получите угол.

РЕДАКТИРОВАТЬ: В полном круге, есть два угла с одинаковым значением касательной (a и a + pi).Используйте знаки X и Y, чтобы определить, какой из них является действительным.

0 голосов
/ 20 ноября 2011

Вы можете использовать предварительно построенную таблицу приближений tan ^ -1. Должно быть очень быстро вычислять угол на основе размера вашего входного вектора, и вам, вероятно, не понадобится очень большое разрешение в таблице (на самом деле, если вам нужно только 8 дискретных направлений, 8 записей в вашей таблице будет достаточно ).

...