Мой игрок может двигаться по вертикали, горизонтали и диагонали. У меня проблемы с написанием хорошей функции диагонального столкновения. Моя цель сделать следующее: Если игрок движется по диагонали и происходит столкновение, то игрок должен продолжать движение по оси (X или Y), не содержащей столкновения, а не просто вернуться к предыдущим координатам.
void Game::updateInput()
{
dirX = 0;
dirY = 0;
if (GetKeyState('W') < 0) dirY = -1.f;
if (GetKeyState('A') < 0) dirX = -1.f;
if (GetKeyState('S') < 0) dirY = 1.f;
if (GetKeyState('D') < 0) dirX = 1.f;
//speed reduction by 30% on each axis if the player moves diagonally
if (dirX != 0.f && dirY != 0.f)
player->move(dirX * 0.7f, dirY * 0.7f);
else
player->move(dirX, dirY);
}
for (auto& tile : mapTile) {
Vectorf playerPos = player->getPos();
if (playerPos.x < tile->coordinate_X + tileWidth &&
playerPos.x + playerWidth > tile->coordinate_X &&
playerPos.y < tile->coordinate_Y + tileHeight &&
playerPos.y + playerHeight > tile->coordinate_Y) {
Vectorf direction = player->getDirection();
if (abs(direction.x) > abs(direction.y)) {
// Horizontal movement is dominant
player->setPosition(playerPos.x - direction.x, playerPos.y);
}
else if (abs(direction.y) > abs(direction.x)) {
// Vertical movement is dominant
player->setPosition(playerPos.x, playerPos.y - direction.y);
}
else {
// Equal movement in both x and y directions -> choose one
}
}
}
Я опубликовал обновление.





Что вам нужно сделать при каждом столкновении, так это определить расстояние, на которое ваш объект прошел точку столкновения, а затем перевести объект обратно на эту точную величину.
Сделайте это для x и y независимо.
Это то, что заставит вашего персонажа двигаться вдоль стены, даже если он нажимает ввод диагонального движения.
Обновлено: Чтобы получить точную симуляцию, вам нужно определить step size в time, которое остается постоянным.
В каждом кадре вычисляйте delta time с момента последнего кадра.
Разделите это время на части, равные вашему step size.
Для каждого шага, доступного в данном кадре, запустите разрешение столкновений, уменьшенное на step size.
Из-за разной частоты кадров и необходимости согласованности в моделировании вы итерируете разрешение столкновений столько раз, сколько сможете в одном кадре, а затем ждете следующего кадра, чтобы продолжить интеграцию с того места, где оно было остановлено. Еще раз, интегрируя как можно больше шагов в этот кадр.
У некоторых кадров может быть время для интеграции 3 шагов, у некоторых может быть время для 2. Но сохранение фиксированного step size — это то, что делает его гладким.
Разбиение движения на более мелкие шаги позволяет симуляции предотвратить проблему множественных столкновений, о которой вы говорите.
Перемещая объекты понемногу несколько раз за кадр, эти другие коллизии будут обрабатываться плавно, поскольку вы не интегрируете весь фрейм времени, который является переменным, за один шаг.
Я научился определять глубину пересечения двух прямоугольников по следующему алгоритму «Теорема о разделяющих осях». Проблема в том, что может произойти несколько столкновений. Если вернуться по X и Y, считая глубину их пересечения, спрайт остановится. Нужно выбрать одну ось. Я читаю эту статью сейчас. Можешь взглянуть? gamedev.stackexchange.com/questions/69339/…
Я опубликую обновление с более подробной информацией, но суть в том, что для каждого кадра симуляция столкновения запускается несколько раз. Дельта-время между кадрами разбивается на шаги, которые повторяются и сглаживают результат.
Мой ответ вам понятен?