Функция столкновения карты 2D-игра

Мой игрок может двигаться по вертикали, горизонтали и диагонали. У меня проблемы с написанием хорошей функции диагонального столкновения. Моя цель сделать следующее: Если игрок движется по диагонали и происходит столкновение, то игрок должен продолжать движение по оси (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
            

        }
    }
}

Мой ответ вам понятен?

Dan Mullin 13.04.2023 00:17

Я опубликовал обновление.

Dan Mullin 15.04.2023 05:36
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
78
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Что вам нужно сделать при каждом столкновении, так это определить расстояние, на которое ваш объект прошел точку столкновения, а затем перевести объект обратно на эту точную величину.

Сделайте это для x и y независимо.

Это то, что заставит вашего персонажа двигаться вдоль стены, даже если он нажимает ввод диагонального движения.

Обновлено: Чтобы получить точную симуляцию, вам нужно определить step size в time, которое остается постоянным.

В каждом кадре вычисляйте delta time с момента последнего кадра.

Разделите это время на части, равные вашему step size.

Для каждого шага, доступного в данном кадре, запустите разрешение столкновений, уменьшенное на step size.

Из-за разной частоты кадров и необходимости согласованности в моделировании вы итерируете разрешение столкновений столько раз, сколько сможете в одном кадре, а затем ждете следующего кадра, чтобы продолжить интеграцию с того места, где оно было остановлено. Еще раз, интегрируя как можно больше шагов в этот кадр.

У некоторых кадров может быть время для интеграции 3 шагов, у некоторых может быть время для 2. Но сохранение фиксированного step size — это то, что делает его гладким.

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

Перемещая объекты понемногу несколько раз за кадр, эти другие коллизии будут обрабатываться плавно, поскольку вы не интегрируете весь фрейм времени, который является переменным, за один шаг.

Я научился определять глубину пересечения двух прямоугольников по следующему алгоритму «Теорема о разделяющих осях». Проблема в том, что может произойти несколько столкновений. Если вернуться по X и Y, считая глубину их пересечения, спрайт остановится. Нужно выбрать одну ось. Я читаю эту статью сейчас. Можешь взглянуть? gamedev.stackexchange.com/questions/69339/…

Alex 14.04.2023 15:47

Я опубликую обновление с более подробной информацией, но суть в том, что для каждого кадра симуляция столкновения запускается несколько раз. Дельта-время между кадрами разбивается на шаги, которые повторяются и сглаживают результат.

Dan Mullin 15.04.2023 05:06

Другие вопросы по теме