Найти тему
Степан Гончаров

Коллизия

Для начала:

Коллизия — это упрощённая геометрия объекта, которая позволяет взаимодействовать с другими объектами: столкновения и выстрелы.

Когда-то давно я реализовывал коллизию считая столкновение точек на прямоугольнике игрока с точками прямоугольника стены.

Это был достаточно элементарный алгоритм, который занимал не более 20 строк и он позволял абсолютно точно определять, что фигуры пересеклись, после чего игрока объект переставлялся на предыдущую позицию, но он не позволял реализовать игру таким образом, чтобы в нее можно было играть нормально, так как игрок фактически прилипал к стене и не мог скользить в доль нее, имея огромный уклон в необходимую для движения сторону.

Реализовать задачу я решил при помощи векторов

Красный вектор - направление игрока, синий - направление движения

Но, у прямоугольника 4 стороны, 2 из которых через y = kx+b выразить попусту нельзя, тогда пришлось прибегать к следующей идее

-2

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

для начла я реализовал функцию, которая проверяла, что прямоугольники пересеклись бы, если бы игрок продолжал идти в заданном направлении еще одну итерацию


void func_collizion(int xp1, int pl, int x, int yp1, int y, int w, int h, int& o) {
if (xp1 - pl >= x and xp1 - pl <= x + w and yp1 - pl >= y and yp1 - pl <= y + h) { o = 1; }
if (xp1 + pl >= x and xp1 + pl <= x + w and yp1 - pl >= y and yp1 - pl <= y + h) { o = 1; }
if (xp1 + pl >= x and xp1 + pl <= x + w and yp1 + pl >= y and yp1 + pl <= y + h) { o = 1; }
if (xp1 - pl >= x and xp1 - pl <= x + w and yp1 + pl >= y and yp1 + pl <= y + h) { o = 1; }
if (x >= xp1 - pl and x <= xp1 + pl and y >= yp1 - pl and y <= yp1 + pl) { o = 1; }
if (x + w >= xp1 - pl and x + w <= xp1 + pl and y >= yp1 - pl and y <= yp1 + pl) { o = 1; }
if (x + w >= xp1 - pl and x + w <= xp1 + pl and y + h >= yp1 - pl and y + h <= yp1 + pl) { o = 1; }
if (x >= xp1 - pl and x <= xp1 + pl and y + h >= yp1 - pl and y + h <= yp1 + pl) { o = 1; }
}

Если происходило пересечение, то мы по точкам столкновения определяли направление движения после столкновения, после чего возвращали 2 аргумента, отталкиваясь от которых игрок производил бы движение по формулам


x = x+speed*cos(a)
y = y+speed*sin(a)

итогом являлась следующая функция

void go(int xp, int yp, float angle, int stop[512][4], int& yy, int& xx, int map_x, int map_y, float speed, int wp) {
for (int i = 0; i < 512; i++) {
int xx3 = xx, yy3 = yy, x = stop[i][0] + map_x, y = stop[i][1] + map_y, w = stop[i][2], h = stop[i][3], xp1 = xp + cos(angle) * speed, yp1 = yp + sin(angle) * speed, p1 = 0, p2 = 0, p3 = 0, p4 = 0, p12 = 0, p22 = 0, p32 = 0, p42 = 0, pl = wp / 2;
if (xp1 - pl >= x and xp1 - pl <= x + w and yp1 - pl >= y and yp1 - pl <= y + h) {p1 = 1;}
if (xp1 + pl >= x and xp1 + pl <= x + w and yp1 - pl >= y and yp1 - pl <= y + h) {p2 = 1;}
if (xp1 + pl >= x and xp1 + pl <= x + w and yp1 + pl >= y and yp1 + pl <= y + h) {p3 = 1;}
if (xp1 - pl >= x and xp1 - pl <= x + w and yp1 + pl >= y and yp1 + pl <= y + h) {p4 = 1;}
if (x >= xp1 - pl and x <= xp1 + pl and y >= yp1 - pl and y <= yp1 + pl) {p12 = 1;}
if (x + w >= xp1 - pl and x + w <= xp1 + pl and y >= yp1 - pl and y <= yp1 + pl) {p22 = 1;}
if (x + w >= xp1 - pl and x + w <= xp1 + pl and y + h >= yp1 - pl and y + h <= yp1 + pl) {p32 = 1;}
if (x >= xp1 - pl and x <= xp1 + pl and y + h >= yp1 - pl and y + h <= yp1 + pl) {p42 = 1;}
if ((p1 == 1 and p2 == 1) or (p3 == 1 and p4 == 1) or (p12 == 1 and p22 == 1) or (p32 == 1 and p42 == 1) or (p12 == 1 and p3 == 1) or (p4 == 1 and p22 == 1) or (p1 == 1 and p32 == 1) or (p42 == 1 and p2 == 1)) {xx = 1;}
if ((p2 == 1 and p3 == 1) or (p1 == 1 and p4 == 1) or (p22 == 1 and p32 == 1) or (p12 == 1 and p42 == 1) or (p12 == 1 and p3 == 1) or (p4 == 1 and p22 == 1) or (p1 == 1 and p32 == 1) or (p42 == 1 and p2 == 1)) {yy = 1;}
int xx2 = xx;
if (xx == 1) {
int o = 0;
xp1 = xp;
if (angle < 90 or angle > 270) {xp1 += 1;}
else {xp1 -= 1;}
yp1 = yp + speed;
func_collizion(xp1, pl, x, yp1, y, w, h, o);
xp1 = xp;
if (angle < 90 or angle > 270) {xp1 += 1;}
else {xp1 -= 1;}
yp1 = yp - speed;
func_collizion(xp1, pl, x, yp1, y, w, h, o);
if (o == 1) {xx = xx2;}
else {xx = xx3;}
}
int yy2 = yy;
if (yy == 1) {
int o = 0;
xp1 = xp + speed;
yp1 = yp;
if (angle < 0 or angle > 180) {yp1 += 1;}
else {yp1 -= 1;}
func_collizion(xp1, pl, x, yp1, y, w, h, o);
xp1 = xp - speed;
yp1 = yp;
if (angle < 0 or angle > 180) {yp1 += 1;}
else {yp1 -= 1;}
func_collizion(xp1, pl, x, yp1, y, w, h, o);
if (o == 1) {yy = yy2;}
else {yy = yy3;}
}
}
}