Найти в Дзене
Журнал «Код»

Непобедимый пинг-понг на JavaScript

Оглавление

Попробуйте продержаться как можно дольше.

Завершаем трилогию про пинг-понг на JavaScript. Если в прошлой частимы сделали не слишком умного бота, то теперь всё серьёзно — победить этого противника физически невозможно. Платформа всегда отобьёт мяч, а ваша новая задача — постичь дзен и поставить новый рекорд.

Подготовка

За основу возьмём наш последний код из второй части, когда платформа движется сама.

Что будем делать сегодня:

  1. Настроим всё, чтобы левая платформа всегда следовала за мячом.
  2. Добавим подсчёт очков.
  3. Сделаем так, чтобы компьютер запоминал новый рекорд и выводил его при каждой игре.
  4. Наконец-то уберём код, который отвечает за управление левой платформой с клавиатуры.

Настраиваем левую платформу Сначала нам нужно отключить автостарт платформы при запуске игры. Находим строчку 53 и удаляем такое:

leftPaddle.dy = paddleSpeed;

Теперь платформа не будет никуда рандомно двигаться. Дальше отключаем автоматический отскок от границ поля — удаляем ненужные строки, которые добавляли для этого:

А теперь делаем магию — добавляем автоматическое слежение платформы за мячом. Для этого находим фрагмент, который отвечает за движение мяча, и добавляем после него такое:

// Если мяч на предыдущем шаге куда-то двигался — пусть продолжает двигаться

ball.x += ball.dx; ball.y += ball.dy;

// пусть платформа движется так же, как и мяч

leftPaddle.dy = ball.dy;

Смысл тут вот в чём: нас интересует только движение мячика вверх или вниз, а за это отвечает свойство .dy. Мы берём его из мячика и отдаём в платформу. Теперь она будет двигаться вниз, если мяч идёт вниз, и вверх — если мяч летит вверх.

Всё, победить уже невозможно.
Всё, победить уже невозможно.

Считаем очки

Принцип будет такой:

  1. Сначала у игрока 0 очков. Рекорд — тоже 0.
  2. За каждое отбивание мяча игрок получает одно очко.
  3. Если игрок побил свой старый рекорд — он тут же обновляется на текущее значение очков.
  4. Когда мяч улетел за платформу, очки обнуляются, а рекорд остаётся.
  5. Постоянно выводим на экран оба этих показателя: рекорд и количество набранных очков.

Делаем нужные переменные. Находим в самом начале раздел с переменными и добавляем нужный код после скорости мяча:

// Рекорд var record = 0; // Набранные очки var count = 0;

Добавляем очки за отбивания игроком. Теперь нам нужно найти код, который проверяет касание правой платформы, и если было касание — увеличить количество набранных очков на единицу (count += 1;):

// Проверяем и делаем то же самое для правой платформы

else if (collides(ball, rightPaddle)) {   ball.dx *= -1;  

ball.x = rightPaddle.x - ball.width;  count +=1; }

Следим за рекордом. Здесь всё просто: как только игрок пропустил мяч, мы смотрим, сколько очков он набрал к этому моменту. Если их больше, чем текущее значение больше рекорда, — записываем их как новый рекорд и обнуляем.

Всё это мы сделаем в коде, который обрабатывает вылет мяча за край платформы:

// Если мяч улетел за игровое поле влево или вправо — перезапускаем его if ( (ball.x < 0 || ball.x > canvas.width) && !ball.resetting) {  

// Помечаем, что мяч перезапущен, чтобы не зациклиться  

ball.resetting = true;  

// Если игрок набрал больше рекорда — записываем это как новый рекорд

if (count > record) { record = count };   

// Обнуляем количество очков у игрока   count = 0;

// ДАЛЬШЕ ИДЁТ ОСТАЛЬНОЙ КОД ОБРАБОТКИ ВЫЛЕТА, ЕГО НЕ ТРОГАЕМ

Сохраняем рекорд в памяти компьютера. Когда мы делали свой планировщик задач на JavaScript, мы использовали localStorage для хранения данных в памяти браузера. Используем этот же подход, чтобы таким же образом сохранить текущее значение рекорда игрока.

Смысл в том, что мы точно так же, как и в планировщике, проверяем сначала размер хранилища. Если оно не пустое и в нём что-то есть — достаём значение рекорда оттуда. Если пустое — заводим запись и кладём туда ноль (значит, что рекорд пока никто не поставил). Добавим этот код после блока с переменными:

// Узнаём размер хранилища var Storage_size = localStorage.length;

// Если в хранилище что-то есть… if (Storage_size > 0){  

// Достаём оттуда текущее значение рекорда  

record = localStorage.getItem('record');  

// Если там ничего нет — }  else   {

// Делаем новую запись и кладём туда ноль — рекорда пока нет     localStorage.setItem('record',0);   }

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

// Кладём значение рекорда в хранилище браузера localStorage.setItem('record',record);

Добавляем вывод значений на экран. Будем использовать стандартные свойства объекта context:

  • fillStyle — отвечает за цвет надписей (и за цвет в принципе),
  • font — каким шрифтом будем выводить надписи,
  • fillText — выводит заданный текст в определённых координатах.

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

// Цвет текста context.fillStyle = "# ff0000";

// Задаём размер и шрифт context.font = "20pt Courier";

// Сначала выводим рекорд context.fillText('Рекорд: ' + record, 150, 550);

// Затем — набранные очки context.fillText(count, 450, 550);

Информативно и наглядно.
Информативно и наглядно.

Убираем обработку нажатий

Единственное, что мы ещё не сделали — не убрали реакцию на клавиши управления левой платформой. Исправим это — найдём и удалим вот этот код:

// Если нажата клавиша W, if (e.which === 87) {  

// то двигаем левую платформу вверх  

leftPaddle.dy = -paddleSpeed; }

// Если нажата клавиша S,

else if (e.which === 83) {              

// то двигаем левую платформу вниз  

leftPaddle.dy = paddleSpeed; }

И этот:

// А если это W или S,

if (e.which === 83 || e.which === 87) {  

// останавливаем левую платформу   leftPaddle.dy = 0; }

Готовый код

Больше статей о программирование, IT и технологиях на нашем сайте: https://thecode.media/