Эта часть вашего детектора неверна:
Math.abs(player.position.x - blockedMapGrid[i][0]) +
Math.abs(player.position.y - blockedMapGrid[i][1]) < 36
По сути, здесь вы приближаете расстояние от игрока до точки на сетке, используя добавленные абсолютные значения вместо корня из суммы квадратов.Правда в том, что вам не нужна такая сложная сетка (повторяющиеся линии) и расстояние.
Похоже, что вы делаете обнаружение с помощью Оси-ориентированной ограничительной рамки (AABB).В Интернете есть множество из ресурсов , как оптимизировать его.
Но общий подход был бы таким.Ваш сеточный массив должен состоять из блоков с (x,y,w,h)
мерами.Может быть худым, длинным, квадратным, чем угодно.Предположим также, что у вашего игрока есть ограничивающий прямоугольник (player.x, player.y, player.w, player.h)
, затем
for (var i = 0; i < grid.length; i++) {
if (player.x < grid[i].x + grid[i].w &&
player.x + player.w > grid[i].x &&
player.y < grid[i].y + grid[i].h &&
player.y + player.h > grid[i].y) {
//collision detected! move player to previous known position
break;
}
}
. Вы можете изменить то, что вы делаете, когда обнаруживается столкновение, но ключом здесь является обнаружение, если два блока перекрываются, используя 4 условия.
Обновление
Другая проблема, возникающая из-за кода в вопросе, - это «отскок» или «застревание» после обнаружения столкновения.
Какэмпирическое правило, вы никогда не должны использовать velocity = -velocity
после столкновения, также не убедившись, что персонаж возвращается в «чистоту», то есть ограничивающий прямоугольник игрока не перекрывается никакими препятствиями.В противном случае вы застрянете в бесконечном цикле collision? -> vel = -vel, pos += vel*t -> collision -> ...
со скоростью, отскакивающей от отрицательной к положительной и обратно, не позволяя игроку выбраться из стены.
Самый простой способ исправить это - вычислить новую позициюИгрок сначала проверяет временные переменные, проверяет, не сталкивается ли новая позиция, и только затем делает его постоянным и вызывает render()
, в противном случае просто игнорируйте его и рендеринг без перемещения игрока.
Другой способ - запомнить последнюю известную «хорошую» позицию и вернуть контроль над персонажем, только когда он возвращается на эту предыдущую позицию, возможно, после анимации или группы неконтролируемых движений.
Существуют более сложные способы, в основном включающие какую-то физическую эмуляцию, позволяющую персонажу отскочить от нескольких препятствий, при условии, что управляющие входы не преодолевают инерцию - например, автомобиль на скользкой дороге или лодка, которая бьет по нескольким деревьям.Но в любом случае, после того, как вы обнаружите столкновение и перед вызовом render () вы должны будете поместить персонажа в физически возможную позицию, иначе он будет классно «застрял в текстурах».