Отскок от стен

Это 3-й этап из 10  Gamedev Canvas tutorial. Вы можете найти исходный код как он должен выглядеть после завершения этого урока в Gamedev-Canvas-workshop/lesson3.html.

Приятно наблюдать за нашим мяч, но он быстро исчезает с экрана, удовольствие длится недолго! Чтобы продлить, мы реализуем некоторое очень простое обнаружение столкновений (о которых будет рассказано далее более подробно), чтобы сделать отскок мяча от четырех краев холста.

Простое обнаружение столкновений

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

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

var ballRadius = 10;

Теперь обновите строку, которая рисует шарик, внутри функции drawBall() :

ctx.arc(x, y, ballRadius, 0, Math.PI*2);

Отскакивание от верхней и нижней стены

Есть четыре стены, от которых мяч будет отскакивать — давайте сначала сосредоточимся на верхней. При каждом кадре нужно проверять, коснулся ли мяч верхней границы — если да, то будет обратное движение мяча, поэтому он начнет двигаться в противоположном направлении и остановится в пределах видимой границы. Вспомнив, что система координат начинается с левого верхнего угла, мы можем придумать что-то вроде этого:

if(y + dy < 0) {
    dy = -dy;
}

Если значение y положения шара ниже нуля, изменить направление движения по оси y установив его с тем же значением но с другим знаком. Если мяч движется вверх со скоростью 2 пикселя на кадр, теперь он будет двигаться "вверх" со скоростью -2 пикселя, что на самом деле означает движение вниз со скоростью 2 пикселя.

Приведенный выше код описывает отражение только от верхней границы, так что теперь давайте думать о нижнем крае:

if(y + dy > canvas.height) {
    dy = -dy;
}

Если положение мяча по оси y больше, чем высота полотна (помните, что мы рассчитываем значения y от верхнего левого, чтобы верхний край начинался с 0, а нижний край — 480 пикселей, высота нашего <canvas>), затем после отскока от нижней кромки обратное движение по оси y.

Мы можем объединить эти две конструкции в одну, чтобы уменьшить код:

if(y + dy > canvas.height || y + dy < 0) {
    dy = -dy;
}

Если одно из двух утверждений верно, тогда направление мяча меняется.

Отскоки влево и вправо

Мы сделали отражение от верхней и нижней границ, нельзя забывать и про боковины. Задача очень похожа на самом деле, все, что вам нужно сделать, это повторить конструкцию заменив Y на X:

if(x + dx > canvas.width || x + dx < 0) {
    dx = -dx;
}

if(y + dy > canvas.height || y + dy < 0) {
    dy = -dy;
}

На этом этапе вы должны вставить этот блок кода в функцию Draw (), непосредственно перед закрывающей фигурной скобкой.

Мяч продолжает исчезать в стене!

Проверьте сейчас свой код, и вы будете впечатлены — теперь мяч, отскакивает от всех четерёх краёв нашего <canvas>!  Однако есть некоторая проблема - когда мяч попадает в любую стену, он немного заходит за границы <canvas> перед отскоком:

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

if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
    dx = -dx;
}
if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
    dy = -dy;
}

Когда расстояние между центром шара и краем стены равно радиусу шарика, шарик изменит направление движения. Вычитая радиус при отскоке от одной стены и добавляя при отскоке от другой, мы получили простое обнаружение столкновений. Шарик отскакивает от стен как надо.

Сравните ваш код

Давайте еще раз провериим готовый код для этой части, и код, что у вас есть, и играйте:

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

Следующий шаг

Теперь мы добрались до стадии, где наш мяч одновременно двигается и остаётся на игровом поле. В четвертой главе мы рассмотрим реализацию управления — см. Paddle and keyboard controls.