Переместить мяч

Это 2й шаг из 10 Gamedev Canvas tutorial (en-US). Вы можете найти исходный код для данного урока по ссылке Gamedev-Canvas-workshop/lesson2.html.

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

Определяем цикл рисования

Чтобы canvas постоянно обновлялся, необходимо определить функцию отрисовки, которая будет циклически запускаться с разными параметрами, чтобы изменять позицию элемента. Функцию можно циклически запускать с помощью JavaScript временной функции, такой как setInterval() (en-US) или requestAnimationFrame().

Удалите весь JavaScript-код, который сейчас хранился в вашем HTML файле, за исключением первых двух строк, и добавьте следующий код после них. Функция draw() будет исполняться внутри функции setInterval каждые 10 мс:

js
function draw() {
  // код отрисовки
}
setInterval(draw, 10);

Благодаря бесконечности функции setInterval функция draw() будет выполняться каждые 10 мс бесконечно или же пока мы не остановим её. Теперь давайте нарисуем мяч - добавьте в свой код функцию draw():

js
ctx.beginPath();
ctx.arc(50, 50, 10, 0, Math.PI * 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();

Попробуйте сейчас ваш обновлённый код - каждый раз мяч будет перерисовываться.

Перемещение

Вы не можете определить, перерисовывается ли мяч в конкретный момент, так как его позиция не меняется. Давайте исправим это. Прежде всего, в позиции (50,50) определим стартовую точку в нижней центральной части Canvas в переменной x и y, и потом используем их для определения текущего положения мяча.

Для начала добавьте следующие две строки до функции draw(), чтобы определить переменные x и y:

js
var x = canvas.width / 2;
var y = canvas.height - 30;

Далее обновите функцию draw(), чтобы использовать переменные x и y в методе arc(), как показано на подсвеченной линии:

js
function draw() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

Теперь важная часть: мы хотим добавлять небольшое значение к переменным x и y после каждой итерации, чтобы заставить мяч двигаться. Давайте определим эти небольшие значения в переменных dx и dy и установим их 2 и -2 соответственно. Добавьте следующий код после определения переменных x и y:

js
var dx = 2;
var dy = -2;

И последнее, необходимо обновить переменные x и y на значение dx и dy каждую итерацию, чтобы мяч отрисовывался каждый раз на новой позиции. Добавьте ещё две строки кода в функции draw():

js
function draw() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}

Сохраните ваш код и откройте страницу в браузере. Всё работает хорошо, вот только мяч оставляет позади след:

Очищение объекта после каждого кадра

Мяч оставляет след, потому что мы рисуем круг на каждой итерации без удаления предыдущей отрисованной фигуры. Не переживайте, потому что существует метод для очистки canvas элемента: clearRect(). Этот метод принимает четыре параметра: x и y координаты верхнего левого угла прямоугольника, x и y координаты нижнего правого угла прямоугольника. Вся площадь, покрытая прямоугольником, будет очищена от любого содержимого, которое когда-либо было там отрисовано.

Добавьте следующую подсвеченную строку в функцию draw():

js
function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
  x += dx;
  y += dy;
}

Сохраните ваш код и попробуйте снова, и на этот раз вы увидите, что мяч перемещается без следов. Каждые 10 мс canvas очищается, голубой круг (наш мяч) отрисовывается на заданной позиции, переменные x и y каждую итерацию обновляются.

Рефакторинг

Мы будем добавлять каждый раз всё больше команд в функцию draw(), поэтому было бы неплохо содержать наш код настолько простым и понятным, на сколько это возможно. Давайте вынесем команды перемещения мяча в отдельную функцию.

Замените существующую функцию draw() следующими двумя функциями:

js
function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, 10, 0, Math.PI * 2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

function draw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  x += dx;
  y += dy;
}

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

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

Упражнение: попробуйте изменить скорость перемещения мяча, или направление перемещения.

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

Мы нарисовали мяч и заставили его двигаться, но он продолжает пропадать на краю canvas. В третьей части мы рассмотрим, как заставить его отскакивать от стен (en-US).