Рассчитайте угол отскакивания для шара / точки - PullRequest
0 голосов
/ 17 апреля 2020

Я создаю свой собственный маленький игровой движок для обучения. Так в основном чисто Java. У меня есть Линии, которые определены начальной и конечной точкой (координаты x и y)

Теперь у меня есть шар с вектором скорости. Я хочу «отскочить» от стены, которую можно расположить под любым возможным углом. Как я могу узнать новый вектор скорости после столкновения? Я знаю точки S, P1 и P2 (см. Изображение)

enter image description here

Я думал о вычислении угла и изменении компонентов x и y. Но я не могу найти способ сделать это для всех возможных углов.

Я мог бы найти много решений для стен, которые параллельны границам холста, но нет общего решения. Как «большие» игровые движки справляются с этой распространенной проблемой?

edit :

Мои обновленные методы векторного класса:

public static Vector bounce(Vector normal, Vector velocity) {
    Vector tmp = Vector.multiplication(2*Vector.dot(normal,velocity), normal);
    return Vector.addition(tmp, velocity);
}

public static Vector multiplication(double multi, Vector n) {
    Vector new_vector = new Vector(n.x * multi, n.y * multi);
    return new_vector;
}

public static double dot(Vector a, Vector b) {
    return a.x*b.x + a.y*b.y; // + a.z*b.z if you're in 3D
}

Моя тестовая функция :

@Test
   public void testBounce() {
        Vector normal_vector_corrected = new Vector(0, 1);
        Vector start_velocity = new Vector(3, -3);
        Vector bounced_vector = Vector.bounce(normal_vector_corrected, start_velocity);
        System.out.println("normal vector: "+normal_vector_corrected);
        System.out.println("start_velocity: "+start_velocity);
        System.out.println("bounced_vector "+bounced_vector);
    }

Вывод такой:

normal vector: <Vector x=0,00, y=1,00>
start_velocity: <Vector x=3,00, y=-3,00>
bounced_vector <Vector x=3,00, y=-9,00>

Согласно моим расчетам, bounced_vector должно быть вместо x = 3, y = 3. Где моя ошибка? (Мой пример как изображение:) enter image description here

edit2: я обнаружил, что это должно быть return Vec.add(tmp, v);. Кроме того, мне пришлось инвертировать вектор скорости.

Ответы [ 2 ]

3 голосов
/ 17 апреля 2020

"Вектор отскоченной скорости" v' получается из исходной скорости v и вектора нормальной единицы поверхности n с 2(n . v)n + v, где . обозначает векторное произведение . Это обычно называется отражением; вектор скорости отражается по нормали поверхности.

Если вы не знакомы с терминологией, нормаль поверхности - это вектор, перпендикулярный (под углом 90 градусов) к поверхности. Единичный вектор - это вектор длиной 1.

enter image description here

Я предполагаю, что у вас уже есть класс для представления векторов, называемый Ve c, с методами умножить вектор на скаляр и сложить два вектора. Вы можете написать операцию отскока следующим образом:

static Vec bounce(Vec n, Vec v) {
    Vec tmp = Vec.scalarMultiply(-2*Vec.dot(n,v), n);
    return Vec.add(tmp, v);
}

static double dot(Vec a, Vec b) {
    return a.x*b.x + a.y*b.y; // + a.z*b.z if you're in 3D
}

Что касается нормального отображения поверхности, это будет зависеть от того, находитесь ли вы в 2D или 3D. Предполагая 2D, все просто: если (x,y) является вектором от P1 до P2, то (-y,x) перпендикулярен ему, и одна единица нормальная будет:

n = (-y/sqrt(x*x+y*y), x/sqrt(x*x+y*y))

. другая возможная единица нормальна -n. Вы можете использовать одну или другую в зависимости от того, с какой стороны поверхности вы находитесь.

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

0 голосов
/ 17 апреля 2020

Я не знаю, отвечает ли это на ваш вопрос, но я удалю его, если это не так.

Vector 1 is <x, y>
s = slope of the wall
theta = Math.acos(1/s) //or arcsin(1/s) //an angle formed between the wall and a line parallel to the x-axis
alpha = (90.0 - theta) + Math.asin(x/y) //the angle between the wall and vector 1
beta = 180.0 - 2 * alpha // the angle between the two vectors
mag is magnitude of both the vectors
vector2 = new Vector(mag * Math.sin(beta), mag * Math.cos(beta))

Каждая точка может быть частью отдельной нити, которая постоянно вычисляет, где она находится перейдя к go, и если он собирается ударить стену, рассчитывает, где он отскочит. Может быть установлено количество миллисекунд для каждого Runnable для обновления Примерно так:

if (this.goingToHitWall()) ...;
else this.setPosition(this.x + this.velX, this.y + this.velY);
Thread.sleep(10);

Игры с продвинутой графикой довольно ресурсоемки, хотя, поэтому я думаю, что это нормально, если для вас это занимает много памяти.

...