Рассчитать угол движения шарика после столкновения с угловой или наклонной стенкой, которая является двухмерным отрезком - PullRequest
1 голос
/ 24 декабря 2010

Если у вас есть «шар» внутри 2D-многоугольника, состоящий, скажем, из четырех отрезков, которые действуют как ограничивающие стены, как рассчитать угол мяча после столкновения с неравномерно наклонной стеной?

Я знаю, как заставить мяч отскочить, если стена горизонтальная, вертикальная или под углом 45 градусов. У меня также есть мой код для обнаружения столкновения со стеной.

Я читал о точечных продуктах и ​​нормалях, но не могу понять, как реализовать их в Java / Android. Я совершенно в замешательстве и чувствую, что 10 раз заглянул в Google на 10 страниц. Я сгорел, пытаясь понять это, я надеюсь, что кто-то может помочь.

Ответы [ 2 ]

8 голосов
/ 24 декабря 2010

Заранее извиняюсь: я не знаю правильных типов Android. Я предполагаю, что у вас есть векторный тип со свойствами 'x' и 'y'.

Если бы стена была горизонтальной и текущая скорость была «векторной», то это было бы так просто:

vector.y = -vector.y;

И вы бы оставили компонент x в покое. Поэтому вам нужно сделать что-то аналогичное, но более общее.

Вы делаете это, подставляя идею нормали линии (вектор, перпендикулярный линии) для жесткого кодирования для оси y (которая перпендикулярна горизонтали).

Так как нормаль ортогональна линии, ее можно найти, повернув линию на 90 градусов. В 2d вектор (a, b) можно повернуть на 90 градусов, преобразовав его в (-b, a). Следовательно, если у вас есть строка от (x1, y1) до (x2, y2), вы можете получить нормаль с помощью:

vectorAlongLine.x = x2 - x1;
vectorAlongLine.y = y2 - y1;

normal.x = -vectorAlongLine.y;
normal.y = vectorAlongLine.x;

На самом деле вам все равно, какой длины была исходная строка (и это повлияет на вычисления позже, когда вы этого не захотите), поэтому вы хотите, чтобы нормаль была длиной 1 независимо от ее текущей длины. Вы можете сделать это, разделив его на его текущую длину. Так, например

lengthOfNormal = Math.sqrt(normal.x*normal.x + normal.y*normal.y);
normal.x /= lengthOfNormal;
normal.y /= lengthOfNormal;

Используя теорему Пифагора, чтобы получить длину.

С горизонтальной линией, переворот на оси y был таким же, как (i) определение длины вектора вдоль оси y; и (ii) вычитать эту сумму дважды - один раз, чтобы получить скорость, равную 0 в этом направлении, и снова сделать ее отрицательной версией оригинала. То есть это так же, как:

distanceAlongNormal = vector.y;
vector.y -= 2.0 * distanceAlongNormal;

Точечное произведение, используемое в общем случае, заключается в том, чтобы определить, как далеко вектор простирается вдоль нормали. Таким образом, он делает то же самое, что и vector.y для горизонтальной линии. Вот где вам, возможно, придется сделать небольшой скачок веры. Это свойство точечного произведения, и вы можете убедить себя, осмотрев прямоугольный треугольник. Но сейчас, если бы у вас была горизонтальная линия, вы бы получили нормальную (0, 1). Поскольку точечное произведение будет:

vector.x * normal.x + vector.y * normal.y

Вы бы вычислили:

distanceAlongNormal = vector.x * 0.0 + vector.y * 1.0;

Очевидно, это то же самое, что просто взять компонент y.

Вычислив расстояние по нормали, вы на самом деле хотите затем вычесть это количество в два раза больше нормального. Единственным дополнительным шагом здесь является умножение на нормаль, чтобы вычесть 2-мерную величину. Это потому, что вы хотите вычесть в порядке нормального. Таким образом, полный код, основанный на нормальном вычисленном ранее, выглядит так:

distanceAlongNormal = vector.x * normal.x + vector.y * normal.y;
vector.x -= 2.0 * distanceAlongNormal * normal.x;
vector.y -= 2.0 * distanceAlongNormal * normal.y;

Если бы вы не делали нормаль длины 1, то вам нужно было бы разделить на длину здесь, так как скалярное произведение масштабировало бы значение distanceAlongNormal на эту величину.

0 голосов
/ 24 декабря 2010

Это может пригодиться для вас http://www.tonypa.pri.ee/vectors/tut07.html

...