Я думаю, что это вопрос механики игры в целом, а не только для игр HTML5/JS. Я не знаком с синтаксисом HTML5, поэтому вам, возможно, придется переписать некоторые детали моих примеров кода. Кроме того, я не знаю, как именно вы структурировали свой код; Я предполагаю, что и у игрока, и у блока есть некоторые функции, такие как getX()
, getXSpeed()
, setX()
и так далее.
Когда вы обнаруживаете столкновение между игроком (или любым другим объектом, который может двигаться) и блок среды, вам нужно обновить позицию игрока, чтобы он просто касался блока, не перехватывая его. Прежде чем вы сможете это сделать, вам нужно найти , как он сталкивается с блоком: игрок попал в блок сверху, слева, справа или снизу?
Во-первых, нам нужна позиция игрока.
playerX = player.getX();
playerY = player.getY();
В зависимости от направления, в котором игрок движется, вы хотите, чтобы добавить ширину и высоту игрока, чтобы получить координаты угла, который указывает в направлении, в котором игрок движется.
if(player.getXSpeed() > 0) {
playerX += player.getWidth();
}
if(player.getYSpeed() > 0) {
playerY += player.getHeight();
}
Далее вы должны будете получить боковые стороны блока, которые ближе всего к предыдущей позиции игрока. Вы можете проверить, является ли скорость игрока положительной или отрицательной, чтобы узнать, с какой стороны он идет. Вместе они представляют координаты угла, указывающего в направлении, из которого идет игрок.
blockX = player.getXSpeed() > 0? block.getX() : block.getX() + block.getWidth();
blockY = player.getYSpeed() > 0? block.getY() : block.getY() + block.getHeight();
Теперь мы имеем Y координаты вертикальной стороны и X координаты горизонтальной стороны блока, что игрок прошел через, и в общей сложности у нас есть координаты угла между обеими сторонами.
Я создал небольшую схему в случае, если вы не понимаете, почему мы делаем это:
черный ящик представляет собой блок среды. Оранжевые рамки представляют собой предыдущие и текущие позиции игрока. Синяя линия представляет собой путь, по которому игрок переместился. Теперь нам нужно проверить, находится ли синяя точка, представляющая угол блока, выше или ниже этой строки. Это говорит нам, ударил ли игрок против горизонтальной или вертикальной стороны блока.
Если игрок попадает в вертикальную сторону, наклон синей линии будет меньше, чем наклон от угла игрока до угла блока.С точки зрения математики это означает:
(currentPlayerY - previousPlayerY)/(currentPlayerX - previousPlayerX)
меньше
(currentPlayerY - blockY)/(currentPlayerX - blockX)
Если это не относится, игрок попадает в горизонтальную сторону блока. Ваш код будет выглядеть примерно так:
bool verticalSide = abs(player.getYSpeed()/player.getXSpeed()) < abs((playerY/blockY)/(playerX - blockX));
Поскольку мы можем игнорировать гравитацию, мы можем делать вид, что движение игрока является линейной. Нам нужна только одна точка на этой линии, чтобы указать, в каком направлении идет игрок. Это значит, что (currentPlayerY - previousPlayerY)/(currentPlayerX - previousPlayerX)
всегда будет равен player.getYSpeed()/player.getXSpeed()
, независимо от того, насколько далеко игрок находился в предыдущем игровом цикле. Обратите внимание, что игрок не обязательно приходит из левого верхнего положения, поэтому наклон, который мы рассчитали, может быть отрицательным. Мы используем математический класс «abs()
», который обычно предоставляют языки программирования, чтобы получить абсолютное значение, т. Е. Положите все отрицательные значения.
Теперь, когда мы знаем, имеем ли мы дело с горизонтальным или вертикальным столкновением, мы можем изменить положение игрока соответственно:
if(verticalSide) {
player.setX(player.getXSpeed() > 0? blockX - player.getWidth(): blockX);
player.setXSpeed(0);
} else {
player.setY(player.getYSpeed() > 0? blockY - player.getHeight(): blockY);
player.setYSpeed(0);
}
Если verticalSide
правда, игрок задевая сторону блока. Теперь мы проверяем, положительна ли скорость игрока, чтобы узнать, идет ли он слева или справа и обновляет свою позицию, поэтому он просто касается блока. Мы также устанавливаем его горизонтальную скорость на 0. Однако, если verticalSide
не соответствует действительности, игрок натыкается на верхнюю или нижнюю часть блока, поэтому мы делаем то же самое для оси y. Это должно быть все, что вам нужно.
Но у меня есть дополнительный совет для вас: вам, скорее всего, нужна информация о том, касается ли игрок в данный момент касания земли, чтобы определить, может ли он прыгать, когда пробел или какая-либо клавиша нажата. Для этого вам необходимо создать логическое поле grounded
в вашем классе игрока, которое при каждом перемещении игрока будет установлено на false. Во время проверки на столкновение снова установите значение true, если игрок попадает в верхнюю часть блока, то есть verticalSide
равен false
, а player.getYSpeed() > 0
- true
. Если нажать клавишу перехода, проверьте, grounded
- true
перед тем, как запустить скачок.
Самое забавное, что вчера у меня была такая же проблема, и я понял это решение, но сжал его только на несколько строк кода, поэтому мне пришлось работать назад, чтобы помнить, что именно я здесь сделал. Думаю, я должен прокомментировать мой код в будущем.
Я думаю, что это вопрос дизайна игры в целом и специально не связан с HTML5 или JS. Вы должны обновить теги вашего вопроса. – Rapti
Спасибо. Я дам вам подробный ответ в ближайшее время. – Rapti
Нет подсказки, но не обновляйте позицию игроков, когда они сталкиваются? – ManyQuestions