Я пытаюсь создать 2D-платформер (типа Марио), и у меня возникают проблемы с правильной обработкой коллизий. Я пишу эту игру на C ++, используя SDL для ввода, загрузки изображений, загрузки шрифтов и т. Д. Я также использую OpenGL через библиотеку FreeGLUT в сочетании с SDL для отображения графики.
Мой метод обнаружения столкновений - AABB (ограничивающая рамка с выравниванием по оси), и это действительно все, с чего мне нужно начать. Мне нужен простой способ как определить, на какой стороне произошло столкновение, так и правильно обработать столкновения. Итак, в основном, если игрок сталкивается с вершиной платформы, переместите его на вершину; если есть столкновение по сторонам, переместите игрока обратно сбоку от объекта; если произойдет столкновение с дном, переместите игрока под платформу.
Я пробовал много различных способов сделать это, например, попытаться найти глубину проникновения и переместить игрока назад по глубине проникновения. К сожалению, ничего из того, что я пробовал, похоже, не работает правильно. Движение игрока оказывается очень глючным и меняет положение игрока, когда я этого не хочу. Отчасти причина, вероятно, в том, что я чувствую, что это что-то настолько простое, но я слишком много над этим думаю.
Если кто-то думает, что они могут помочь, взгляните на приведенный ниже код и помогите мне попытаться улучшить это, если сможете. Я бы хотел воздержаться от использования библиотеки для обработки этого (поскольку я хочу научиться самостоятельно) или чего-то вроде 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. Система координат может показаться немного странной, так что это стоит пояснить. coords [0] представляет позицию x (слева) объекта (где он начинается на оси x). coords [1] представляет позицию y (вверху) объекта (где он начинается на оси y). coords [2] представляет собой ширину объекта плюс координаты [0] (справа). coords [3] представляет высоту объекта плюс координаты [1] (внизу). de2dCheckCollision выполняет обнаружение столкновений AABB. Вверх - отрицательный y, а вниз - положительный y, как и в большинстве игр.
Надеюсь, я предоставил достаточно информации, чтобы кто-то смог мне успешно помочь. Если я упустил что-то важное, дайте мне знать, и я предоставлю необходимую информацию. Наконец, для всех, кто может помочь, предоставление кода было бы очень полезным и очень полезным.
Еще раз спасибо за вашу помощь!
Редактировать 2: я обновил свой код новым алгоритмом, который проверяет, где мяч находился ранее до столкновения. Угловые шкафы теперь работают на этой единственной платформе правильно, и когда у меня есть стена из объектов, я теперь могу правильно скользить по ней. Единственная оставшаяся проблема заключается в том, что есть небольшой эффект дрожания, который возникает, когда я нахожусь на земле, когда мяч постоянно поднимается и опускается, как будто его тянет сила тяжести, а затем мяч снова падает в объект.
Изменить: вот URL-адрес изображения, пытающегося показать, какие у меня проблемы: http://img8.imageshack.us/img8/4603/collisionproblem.png
В случае, если объяснение на картинке не имеет особого смысла, мяч не может переместиться влево за угол объекта, если я не перепрыгну через него. Однако мяч может двигаться вправо, но он перемещается вправо от объекта при движении, что не требуется. По сути, это создает движение с пропуском, когда оно выглядит так, как будто мяч перескакивает через половину объекта или около того, когда я двигаюсь вправо. Если в этом нет смысла, спросите меня, и я постараюсь уточнить подробности.