Определение направления столкновения

Квадратная плитка сталкивается с другой квадратной плиткой. Бармен говорит ...

У меня есть:

  • Высота, ширина, x и y обеих плиток.
  • 2D-вектор движения, вызвавшего столкновение.

Мне нужно знать, с какой СТОРОНЫ произошло столкновение (например, сверху, снизу, слева, справа), чтобы соответствующим образом сбросить местоположение.

Я дам мысленное печенье тому, кто сможет ответить на этот вопрос, потому что я пытался слишком много часов, и это кажется фундаментальным.


person slifty    schedule 21.02.2011    source источник
comment
вы ищете решение для кодирования на каком-то конкретном языке или просто алгоритмические подсказки?   -  person Joe    schedule 21.02.2011
comment
Я кодирую это в javascript node.js, но на самом деле это просто вопрос алгоритма на данный момент. У меня нет доступа ни к чему особенно интересному, например, к математическим библиотекам.   -  person slifty    schedule 21.02.2011
comment
на самом деле, подумав об этом некоторое время, с данной информацией невозможно определить сторону удара, потому что, скажем, r1 движется вниз по r2, затем зажимается, перекрывается с двух сторон, затем перекрывается с одной стороны, затем Затем уходит 2 стороны на противоположной стороне. как мне узнать, рассчитываю ли я перекрытие контактов или выходное перекрытие ...   -  person Joe    schedule 21.02.2011
comment
Что ж, вы знаете вектор, который его направил, так что вы знаете, какова была исходная позиция. Это должно позволить определить, какой из них правильный.   -  person slifty    schedule 21.02.2011
comment
в основном, все, что вы можете здесь сделать, это использовать координаты r1 и r2 и скорость движущегося прямоугольника для прогнозирования (используя y = mx + b), где он столкнется, а не использовать фактическое обнаружение столкновения   -  person Joe    schedule 21.02.2011
comment
ах да, теперь мы кое-что уходим, дай мне подумать ... давно я не занимался математикой, но это будет полезно и для моей игры, хе-хе   -  person Joe    schedule 21.02.2011
comment
Я обновил свой ответ, надеюсь, это поможет! Хороший вопрос   -  person Joe    schedule 21.02.2011
comment
Большое спасибо, Джо. Выглядит многообещающе, и я дам вам знать, как дела. Я обязательно поставлю вам зеленую отметку;)   -  person slifty    schedule 21.02.2011
comment
если делать прямоугольники слишком сложно, почему бы не рассмотреть круги? в большинстве случаев он лучше отображает реальную форму, и вам совсем не нужно беспокоиться о сторонах!   -  person Joe    schedule 21.02.2011
comment
Я заметил, что вы сегодня поставили мне зеленую галочку. Просто любопытно, как у тебя это получилось в итоге. В итоге я просто использовал сторонний физический движок для своей игры. pymunk.   -  person Joe    schedule 04.03.2011
comment
Я надеялся, что вы не заметите;) Это была превентивная зеленая галочка. Сейчас мы просто проверяем столкновения по вертикали, а затем по горизонтали. Это ошибочный алгоритм, но мой мозг отключился в ту ночь, у меня не было времени вернуться, и он работает достаточно часто. Я дал вам зеленый, потому что ваш ответ, я уверен, правильный. Надеюсь, в конце концов я его реализовываю.   -  person slifty    schedule 04.03.2011


Ответы (5)


float player_bottom = player.get_y() + player.get_height();
float tiles_bottom = tiles.get_y() + tiles.get_height();
float player_right = player.get_x() + player.get_width();
float tiles_right = tiles.get_x() + tiles.get_width();

float b_collision = tiles_bottom - player.get_y();
float t_collision = player_bottom - tiles.get_y();
float l_collision = player_right - tiles.get_x();
float r_collision = tiles_right - player.get_x();

if (t_collision < b_collision && t_collision < l_collision && t_collision < r_collision )
{                           
//Top collision
}
if (b_collision < t_collision && b_collision < l_collision && b_collision < r_collision)                        
{
//bottom collision
}
if (l_collision < r_collision && l_collision < t_collision && l_collision < b_collision)
{
//Left collision
}
if (r_collision < l_collision && r_collision < t_collision && r_collision < b_collision )
{
//Right collision
}

Это не решает проблему, когда объект находится внутри одного из другого. Но он работает с перекрытием

person Photonic    schedule 12.11.2012
comment
Просто хотел расширить это, потому что не сразу было ясно, что здесь происходит: нижний и правый край игрока / плитки представляют нижнюю и правую стороны игрока и плитки соответственно. b_collision представляет собой расстояние между нижней частью плитки и верхней частью игрока. Это расстояние между сторонами, которое будет наименьшим, если игрок сталкивается с плиткой снизу, именно это и проверяется, чтобы увидеть, действительно ли произошло столкновение снизу. Остальные столкновения проверяются таким же образом с другими сторонами. - person Benjamin Kovach; 15.08.2013

Учитывая r1 и r2 (r2 неподвижен), сначала найдите угол r2, ближайший к r1. Это точка (c1.x, c1.y), и представьте, что теперь вы расширяете ее на две плоскости, одну параллельную оси x, а другую - оси y.

Теперь найдите ближайший угол от r1 к r2 (назовите его c2) и используйте его в следующей формуле y = mx + b, где b - c2.x, а m - ваш вектор. а x - это c1.x

Итак, если y больше, чем c1.y, это означает, что в точке контакта x (ширина) вы уже достигли вершины. Если меньше, значит, вы еще не попали. Инвертировать для низа / верха.

person Joe    schedule 21.02.2011
comment
Помните, я не перемещаю пиксель за пикселем, я двигаюсь вектором. Что произойдет, если перекрытие более чем одной стороны? - person slifty; 21.02.2011
comment
Я обновил свой ответ, он не точен, но я думаю, что с помощью векторной математики вы можете кое-что получить ... - person Joe; 21.02.2011

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

Квадрат1: (x1, y1)
Квадрат2: (x2, y2)

Я буду работать, исходя из предположения, что верхний левый угол вашей рабочей области равен (0,0) и что x значения увеличиваются при движении вправо, а значения y увеличиваются при движении вниз.

Имея это в виду:

Если (x1 ‹x2), правая сторона квадрата 1 столкнулась с левой стороной квадрата 2
Если (x1> x2), левая сторона квадрата 1 столкнулась с правой стороной квадрата 2
if ( y1 ‹y2), нижняя сторона квадрата 1 столкнулась с верхней стороной квадрата 2
если (y1> y2), верхняя сторона квадрата 1 столкнулась с нижней стороной квадрата 2

Предлагаю вам нарисовать себе несколько картинок, и вам это должно стать понятно.

person Nathanael    schedule 21.02.2011
comment
Я знаю, как определить верхнее и нижнее, левое и правое, но что происходит, когда верхнее и левое перекрываются? Моя проблема заключается в том, чтобы выяснить, что совпадает в первую очередь. - person slifty; 21.02.2011
comment
Возьмите разницу между x1 и x2 и y1 и y2. Большая (абсолютная) разница будет у той стороны, которая столкнулась первой. - person Nathanael; 21.02.2011
comment
это не обязательно правда. если у вас есть широкий прямоугольник, который в дюймах вверх, тогда столкновение должно происходить сверху / снизу, но разница x2-x1 будет намного больше с учетом ширины - person Joe; 21.02.2011
comment
То, что сказал Джо, было сродни моей первой попытке, а потом я осознал тот крайний случай. - person slifty; 21.02.2011
comment
Вы правы - моя беда - я извиняюсь, что уже поздно ночью, где я нахожусь: P - person Nathanael; 21.02.2011
comment
Я собирался предположить, что вы можете использовать большее из двух чисел в векторе (x, y), но понял, что если вы скажете (0,5,1), то вы подумаете, что столкновение произошло снизу, однако прямоугольник может быть намного ближе сбоку, так что это тоже не очень хороший индикатор ... сложно - person Joe; 21.02.2011

  if(player.y <= wall.y + wall.height && player.y > wall.y || player.y + player.height  <= wall.y+wall.height && player.y + player.height > wall.y){
            if(player.x -2< wall.x + wall.width && player.x > wall.x){
                leftspeed = 0
            }else if(player.x + player.width +2 > wall.x && player.x + player.width < wall.x + wall.width){
                rightspeed = 0
            }
        }

        if(player.x <= wall.x + wall.width && player.x > wall.x || player.x + player.width  <= wall.x+wall.width && player.x + player.width > wall.x){
            if(player.y -2 < wall.y + wall.height && player.y > wall.y){
                upspeed = 0
            }else  if(player.y + player.height +2> wall.y && player.y + player.height < wall.y + wall.height){
                downspeed = 0
            }
        }

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

person cubefox    schedule 02.11.2018

вам нужно смоделировать свой квадрат, чтобы зафиксировать ориентацию, только с (x, y, высота) квадрата, ориентация, я имею в виду, может ли он находиться в первом, втором, третьем или четвертом квадранте путем моделирования всех четырех угловых вершин квадрата .

затем вам нужно определить, все четыре вектора, которые составляют этот квадрат

найдите косинус между 2D-вектором, который у вас есть с каждой стороной квадрата, например, если косинус данной стороны и 2D-вектор равен 1, тогда оба ортогональны или 0 они перпендикулярны, любое другое значение будет находиться между

или любые другие уловки с векторной алгеброй о том, как вы хотите определять / определять свое столкновение!

person Community    schedule 21.02.2011