Я пытаюсь создать 2D-платформерную игру (типа Марио), и у меня есть некоторые проблемы с правильной обработкой столкновений. Я пишу эту игру на C ++, используя SDL для ввода, загрузки изображений, загрузки шрифтов и так далее. Я также использую OpenGL через библиотеку FreeGLUT в сочетании с SDL для отображения графики.
Мой метод обнаружения столкновений - AABB (Axis-Aligned Bounding Box), и это действительно все, с чего мне нужно начать. Что мне нужно, так это простой способ определить, на какой стороне произошло столкновение, и правильно обработать его. Таким образом, в основном, если игрок сталкивается с вершиной платформы, переместите его на вершину; если происходит столкновение по сторонам, переместите игрока обратно на сторону объекта; если столкновение снизу, переместите игрока под платформу.
Я пробовал много различных способов сделать это, например, пытаясь найти глубину проникновения и переместить игрока назад на глубину проникновения. К сожалению, ничего из того, что я пробовал, похоже, не работает правильно. Движение игрока заканчивается очень глючно и перемещает игрока, когда я этого не хочу. Частично причина, вероятно, в том, что я чувствую, что это что-то очень простое, но я слишком обдумываю это.
Если кто-то считает, что может помочь, ознакомьтесь с приведенным ниже кодом и, если возможно, помогите мне улучшить его. Я хотел бы воздержаться от использования библиотеки для обработки этого (как я хочу учиться самостоятельно) или чего-то подобного SAT (Теорема о разделяющей оси), если это вообще возможно. Заранее благодарю за помощь!
void world1Level1CollisionDetection()
{
for(int i; i < blocks; i++)
{
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==true)
{
de2dObj ballPrev;
ballPrev.coords[0] = ball.coords[0];
ballPrev.coords[1] = ball.coords[1];
ballPrev.coords[2] = ball.coords[2];
ballPrev.coords[3] = ball.coords[3];
ballPrev.coords[0] -= ball.xspeed;
ballPrev.coords[1] -= ball.yspeed;
ballPrev.coords[2] -= ball.xspeed;
ballPrev.coords[3] -= ball.yspeed;
int up = 0;
int left = 0;
int right = 0;
int down = 0;
if (ballPrev.coords[0] < block[i].coords[0] && ballPrev.coords[2] < block[i].coords[0] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || ball.coords[3] < block[i].coords[3])))
{
left = 1;
}
if (ballPrev.coords[0] > block[i].coords[2] && ballPrev.coords[2] > block[i].coords[2] && (((ball.coords[1] < block[i].coords[1]) || (ball.coords[3] < ball.coords[1])) || ((ball.coords[1] < block[i].coords[3]) || (ball.coords[3] < block[i].coords[3]))))
{
right = 1;
}
if(ballPrev.coords[1] < block[i].coords[1] && block[i].coords[1] < ballPrev.coords[3] && ballPrev.coords[3] < block[i].coords[3])
{
up = 1;
}
if(block[i].coords[1] < ballPrev.coords[1] && ballPrev.coords[1] < block[i].coords[3] && block[i].coords[3] < ballPrev.coords[3])
{
down = 1;
}
cout << left << ", " << right << ", " << up << ", " << down << ", " << endl;
if (left == 1)
{
ball.coords[0] = block[i].coords[0] - 18.0f;
ball.coords[2] = block[i].coords[0] - 2.0f;
}
else if (right == 1)
{
ball.coords[0] = block[i].coords[2] + 2.0f;
ball.coords[2] = block[i].coords[2] + 18.0f;
}
else if (down == 1)
{
ball.coords[1] = block[i].coords[3] + 4.0f;
ball.coords[3] = block[i].coords[3] + 20.0f;
}
else if (up == 1)
{
ball.yspeed = 0.0f;
ball.gravity = 0.0f;
ball.coords[1] = block[i].coords[1] - 17.0f;
ball.coords[3] = block[i].coords[1] - 1.0f;
}
}
if (de2dCheckCollision(ball,block[i],0.0f,0.0f)==false)
{
ball.gravity = -0.5f;
}
}
}
Чтобы объяснить, что означает этот код:
Переменная блоков - это целое число, в котором хранится количество блоков или платформ. Я проверяю все блоки, используя цикл for, и номер, на котором в данный момент находится цикл, представлен целым числом i.
Система координат может показаться немного странной, поэтому стоит объяснить.
Координаты [0] представляют позицию х (слева) от объекта (где он начинается на оси х).
Координаты [1] представляют позицию y (верхнюю часть) объекта (где он начинается на оси y).
Координаты [2] представляют ширину объекта плюс координаты [0] (справа).
Координаты [3] представляют высоту объекта плюс координаты [1] (внизу).
de2dCheckCollision выполняет обнаружение коллизий AABB.
Вверх отрицателен, а вниз положителен, как и в большинстве игр.
Надеюсь, я предоставил достаточно информации, чтобы кто-нибудь помог мне успешно. Если есть что-то, что я пропустил, что может иметь решающее значение, дайте мне знать, и я предоставлю необходимую информацию. Наконец, для тех, кто может помочь, предоставление кода было бы очень полезно и высоко ценится.
Еще раз спасибо за вашу помощь!
Редактировать 2 : я обновил свой код с помощью нового алгоритма, который проверяет, где мяч был ранее до столкновения. Угловые шкафы теперь работают на этой единственной платформе правильно, и когда у меня есть стена объектов, я могу правильно скользить по ней. Единственная оставшаяся проблема заключается в том, что возникает небольшой эффект дрожания, когда я на земле, когда шар постоянно поднимается и опускается, как будто его притягивает сила тяжести, а затем шар снова падает в объект.
Редактировать : Вот URL-адрес изображения, которое пытается показать, какие проблемы у меня возникают:
http://img8.imageshack.us/img8/4603/collisionproblem.png
Если объяснение на рисунке не имеет особого смысла, мяч не может переместиться влево за угол объекта, если я не перепрыгну через него. Однако шар может двигаться вправо, но он перемещается вправо от объекта при перемещении , что не нужно. Это создает по существу пропускающее движение, когда оно появляется, когда мяч пропускает около половины объекта или около того, когда я двигаюсь вправо. Если это не имеет смысла, пожалуйста, спросите меня, и я постараюсь уточнить больше.