Движение ручки после обнаружения столкновения

Я делаю небольшой платформер на js, и у меня проблемы с коллизиями. К сожалению, кажется, что 90% информации в Интернете обнаруживает столкновения, а не то, что следует за ними. Я могу легко обнаруживать столкновения, так как все в моей игре представляет собой 2d-прямоугольник, выровненный по оси, но обработка этих столкновений — сложная часть.

Я пытался переместить игрока на ближайший этаж при обнаружении столкновения, но это также происходит при столкновении со стеной. Так что я попытался вычислить ближайшее лицо и привязать к нему игрока, но это приводит к всевозможным странностям. Вот код, который у меня есть до сих пор (текущий код сейчас предназначен только для столкновений с полом, но тот же принцип можно применить к остальным направлениям)

if (collided) {
    let ld = {'a': 'l', 'b': Math.abs(player.left.x - col.left.x)}
    let rd = {'a': 'r', 'b': Math.abs(player.right.x - col.right.x)}
    let td = {'a': 't', 'b': Math.abs(player.top.y - col.top.y)}
    let bd = {'a': 'b', 'b': Math.abs(player.bottom.y - col.bottom.y)}
            
    let dirs = [ld, rd, td, bd]
    let nearestFace = dirs.hasMin('b').a
            
    if (nearestFace == 'b') {
        player.grounded = true
        player.yvel = 0
        player.pos.y = col.top.y + player.size.y/2
    } else {
        player.grounded = false
    }
}
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
0
21
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Ваш код, кажется, не проверяет, где сталкивается ближайшее лицо, только то, что это ближайшее лицо после столкновения. Что может вызвать такую ​​проблему:

Collision detected after wall

Если ваша игра в 2D, все является прямоугольником, и ничто не имеет угла, тогда у вас есть проблема столкновения, известная как столкновение AABB (Axis-Aligned Bounding Boxes), это отличное ключевое слово для поиска в вашем случае и потрясающее начало. точка.

Во-первых, я советую вам прогнозировать коллизии, а не решать их после того, как они произошли из-за потенциальных проблем, подобных этой:

gamedev.net's tutorial bounding box image

Кроме того, если вам нужен расширенный учебник по этому вопросу, приведенное выше изображение взято из этого руководства: Обнаружение столкновений AABB и реагирование на них. В нем, наверное, есть все, что вам нужно.

Короче говоря, входными данными для вашей логики обработки столкновений должны быть старая позиция вашего объекта, текущий размер, его скорость и все другие объекты, с которыми может сталкиваться объект (их размер и положение). Ответом должно быть ожидаемое поведение вашего объекта (т. е. новая скорость, скорректированная для «избежания» столкновения). Таким образом, вы можете легко тестировать сценарии и свою реализацию, учтите следующее:

const player = {x: 0, y: 0, width: 10, height: 10, xvel: 12, yvel: 0};
// player.right = {x: player.x + player.width, y: player.y} // Your engine does this, right?
const collidableList = [{x: 15, y: 0, width: 5, height: 10}];

const newVelocity = handleCollision(player, collidableList);

Я предполагаю, что положение игрока выровнено по левому верхнему углу, поэтому в этом случае вы можете предсказать, что ваша новая скорость должна быть xvel = 5, yvel = 0. Это означает, что вам просто нужно создать handleCollision, который работает для этого тестового примера, а затем вы можете запустить несколько тестов, чтобы убедиться, что столкновение ведет себя хорошо в крайних случаях, таких как когда ничего не сталкивается и когда сталкиваются два объекта, и один из них ближе, чем другой.

Основная идея этого столкновения состоит в том, чтобы найти скорость, ближайшую к нулю, необходимую для ИЗБЕЖАНИЯ столкновения в следующем кадре.

Например, представьте себе сценарий, в котором игрок движется вправо. Давайте проигнорируем ось Y, потому что ее следует использовать только для определения того, будут ли объекты сталкиваться в будущем, и она не повлияет на расчеты самой горизонтальной скорости. Если игрок движется вправо, он должен проверить расстояние между левой стороной каждого объекта и правой стороной игрока, если это расстояние меньше скорости, это, очевидно, вызовет столкновение, например:

let targetVelocityX = player.xvel;

for (const collidable of ...) {
// ...
    if (targetVelocityX > 0) {
        // We are moving to the right so:

        // Figure out how much space do we have between the objects
        const leftOverSpace = collidable.left.x - player.right.x;

        // Is our velocity larger than the space we have available?
        if (targetVelocityX > leftOverSpace) {
            // We must restrict the velocity because the player will collide otherwise
            // We can only move as much as we have space available
            targetVelocityX = leftOverSpace;
        }
    } else if (targetVelocityX < 0) {
        // Moving to the left...
    }

Используя тестовый пример, который я сделал ранее, мы должны получить leftOverSpace = 5, что меньше, чем наше targetVelocityX = 12, поэтому новая скорость будет равна 5, что заставит его коснуться сталкивающегося объекта, а в следующем кадре наша позиция игрока будет x = 5 и xvel = 5 , если мы запустим его снова, логика столкновения скажет нам, что левое пространство равно нулю, поэтому горизонтальная скорость будет установлена ​​​​на ноль, что означает, что мы больше не можем двигаться вправо, потому что мы касаемся объекта.

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

Вова, спасибо за подробный ответ! Я исправил свою систему, и теперь она работает отлично :)

RKM 06.05.2022 21:06

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