Возродите немного ностальгии: воссоздание игры «Змейка» с использованием HTML5 Canvas API и JavaScript
22 января 2024 г.Если вы никогда не играли в знаменитую игру со змеями, поднимите рука!
Я говорю это, но предполагаю, что сегодня новое поколение, возможно, никогда не слышало об этой игре, которая может показаться немного старомодной, учитывая возможности, предлагаемые сегодняшними компьютерами и Интернетом.
И все же было время, когда игра «Змейка» была игрой, в которую все владельцы мобильных телефонов проводили огромное количество времени. Да, тогда речь шла не о смартфонах, а о телефонах.
Это было хорошее время, как говорится, и Nokia популяризировала игру через свои мобильные устройства, которые тоже были эталоном. Сегодня от доминирования Nokia в мире мобильных устройств и игры «Змейка» мало что осталось.
Для тех, кто ностальгирует по этой игре – и я один из них, должен признаться – это руководство научит вас, как воссоздать ее для Интернета. Для этого я буду использовать Canvas API и JavaScript HTML5.
Это также возможность научиться использовать классы Javascript и создать эффективный игровой цикл для веб-игр.
Создание веб-страницы для нашей игры «Змейка»
Для начала мы создадим веб-страницу, которая позволит нам играть в игру «Змейка», которую мы будем разрабатывать в этом руководстве. Вскоре вы увидите, что эта веб-страница не представляет никаких трудностей. Два элемента div: один для заголовка страницы, а другой для отображения области, в которой будет двигаться змея.
К этому я добавлю небольшой CSS, чтобы центрировать эти элементы управления, применив к ним фиксированную ширину:
https://gist.github.com/ssaurel/52d2a7ffd8b417fb48e27ae86237487f?embedable=true р>
Проектирование класса Snake
Как я объяснял во введении к этому уроку, для моделирования игры я собираюсь использовать специальный класс Snake. Это также позволит вам узнать, как управлять классами в JavaScript.
Наша Змея будет иметь следующие свойства:
- bw и bh обозначают размер доски по ширине и высоте соответственно.
- nbx и nby обозначают количество ячеек, доступных на доске.
- eltw и elth обозначают размер элемента змеи по ширине и высоте.
- dirx и diry, обозначающие вектор смещения змеи.
- marginx и marginy добавляют небольшой запас к ширине и высоте элементов змеи, чтобы игрок мог видеть границу между каждым элементом змеи.
- keyup, keydown, keyleft, keyright, которые сохраняют состояние движущихся стрелок в данный момент. .
- startftps хранит количество кадров в секунду, необходимое для перемещения змеи в начале игры.
В конце конструктора вызывается метод init для инициализации змеи в начале игры. Если нужно запустить новую игру, просто вызовите этот метод инициализации еще раз.
Это дает нам следующий код для нашего класса Snake:
https://gist.github.com/ssaurel/719918967c6bc4d5a0bde7252fdfc617?embedable=true р>
В методе init вы можете определить другие свойства змеи, например указатель на ее голову и указатель на ее хвост. Массив elements будет хранить все элементы змеи в данный момент. Свойство Points используется для хранения очков за текущую игру, а свойство level используется для определения количества накопленных очков для увеличения частоты кадров в игре. Чем выше количество кадров в секунду, тем быстрее будет двигаться змея.
Поскольку свойство fps представляет количество кадров в секунду, нам необходимо иметь свойство fpsinterval, значение которого равно результату деления 1 секунды (или 1000 миллисекунд) на желаемое количество кадров в секунду.
Принцип игры «Змейка»
Принцип игры «Змея» прост: вам нужно направлять змею с помощью четырех стрелок направления так, чтобы она съела максимальное количество яблок, которые появляются на доске. Каждый раз, когда вы едите яблоко, змея увеличивается на один элемент. По мере того, как змея растет, вам будет трудно не коснуться ее собственного хвоста. Если вы этого не сделаете, вы проиграете, и счет снова начнется с нуля. Конечно, каждый раз, когда вы съедаете яблоко, вы получаете очко.
Стоит отметить, что версия Snake, которую мы собираемся реализовать, — это та версия, в которой прикосновение к краям доски не приводит к проигрышу. Это просто заставляет вас опрокинуться на противоположную сторону. Таким образом компания Nokia реализовала вторые версии игры «Змейка».
Поскольку змея должна съесть яблоко, нам нужно отобразить это яблоко на доске случайным образом, стараясь не создавать яблоко непосредственно на элементе змеи.
Это дает нам следующий метод генерации еды для нашего класса Snake:
https://gist.github.com/ssaurel/01123c58385dfb7b2a43ca4d186eb0fd?embedable=true р>
Рендеринг змеи на экране
Наш класс Snake развивается, и теперь нам нужно создать метод для отображения змеи на экране. Нам также нужно будет отобразить количество очков игрока в данный момент времени и, наконец, отобразить яблоко, которое нужно съесть. Позиция яблока хранится в свойстве food класса Snake.
Чтобы отобразить Змею на экране, я использую Canvas API HTML5.
Я буду использовать примитивы рисования этого API для рисования прямоугольников, представляющих различные элементы змеи, а также яблоко, которое нужно съесть. Я применю к яблоку и змее разный цвет, чтобы игрок мог их различать.
Это дает следующий код для метода рисования нашего класса Snake:
https://gist.github.com/ssaurel/a1381047c4849f76f38a99db5730231d?embedable=true< / р>
Перемещение змеи
Теперь у нас есть змея, которую мы можем отобразить на экране. Это все очень хорошо, но нам нужно добавить поддержку движения змеи. Как объяснялось выше, змейка движется по координатному вектору (dirx, diry). Итак, каждый раз, когда мы вызываем метод перемещения, который я собираюсь здесь определить, змея будет перемещаться на одно и то же расстояние.
В этом методе перемещения мы проверяем, что координаты головы змеи соответствуют координатам съедобного яблока. Если да, то змея только что съела яблоко. Игрок получает очко, но что более важно, нам нужно предпринять четыре действия:
- Добавьте элемент к элементам змеи. Этот элемент становится новым хвостом.
- Сгенерируйте новое яблоко, вызвав функцию Genefood.
- Добавить очко игроку.
- Если игрок проходит уровень, мы обновляем количество отображаемых кадров в секунду, чтобы ускорить движение Змеи. ол>
Тем не менее, в методе перемещения нам нужно проверить, не допустил ли игрок ошибку, коснувшись головой элемента змеи. В этом случае игра проиграна и мы начинаем заново! Для этого мы вызываем метод init класса Snake, представленный выше.
Теперь нам нужно завершить метод перемещения, фактически переместив змею. Для этого к координатам головы змеи добавляем dirx и diry. Это дает нам возможность добавить новую голову. Вы также заметите, что перемещение змеи осуществляется разумно: каждый раз удаляется хвост и добавляется новая голова. Это позволяет избежать необходимости обновлять положение всех элементов змеи.
В завершение не забудьте обновить новую головку. Кстати, вы также заметили, что когда голова змеи пересекает границу доски, мы заставляем ее переместиться на противоположную сторону доски. Это относится как к ширине, так и к длине.
Это дает нам следующий код метода перемещения:
https://gist.github.com/ssaurel/857a654c2b6dd065a15bfdb5751cdcab?embedable=true р>
Игровой цикл нашей игры со змеями
Нашу Змею можно отобразить на экране. Нашу Змею можно переместить, вызвав ее метод перемещения. Чего нам не хватает?
Нам не хватает реализации GameLoop в нашей игре!
Без этого GameLoop, который будет вызывать методы перемещения и рисования через равные промежутки времени, Змея не сможет двигаться. Далее мы покажем вам, как правильно реализовать GameLoop в JavaScript, оставив браузеру возможность вызывать его, когда он сочтет нужным, чтобы не блокировать поток рендеринга веб-страницы игры.
Для этого мы воспользуемся методом requestAnimationFrame стандартного окна объекта JavaScript. Затем браузер адаптирует максимальную частоту кадров, которую он может поддерживать, к компьютеру или смартфону, на котором будет использоваться веб-страница.
В рамках нашего метода gameloop мы затем декоррелируем количество кадров в секунду, поддерживаемое браузером, от количества кадров в секунду, на которое мы хотим переместить нашу змею. Мы будем вызывать методы перемещения и рисования только тогда, когда находимся в пределах диапазона кадров в секунду, определенного ранее.
Важно обновить координаты вектора движения змеи в соответствии с состоянием четырех клавиш направления: вверх, вниз, влево и вправо.
Наконец, мы вызываем GameLoop, делегируя браузеру задачу выбора наилучшего момента для этого. Это дает нам следующий код для GameLoop:
https://gist.github.com/ssaurel/ef5abcd238e63cacd906a039b7647eaf?embedable=true р>
Обработка взаимодействия пользователя со Snake
Чтобы Змея могла перемещаться в соответствии с клавишами направления, нажимаемыми игроком, мы используем события keydown и keyup. Для каждого из этих событий мы будем вызывать метод класса Snake. Логически это будет нажатие для события нажатия клавиши и нажатие для события нажатия клавиши.
Мы обновляем значение связанных свойств класса Snake в соответствии с тем, что игрок делает с этими ключами. Как видите, мы не блокируем игру, обновляя положение змеи напрямую. Вместо этого мы обновляем состояние в методе gameloop, который вызывается через регулярные промежутки времени.
Сборка различных компонентов Snake
Чтобы завершить эту игру «Змейка», нам нужно собрать различные элементы. Мы получаем объект Canvas по его идентификатору. Затем мы получаем 2D-контекст, связанный с этим Canvas. Примените желаемые размеры. Мы создаем объект Snake, передавая в качестве параметров различные ожидаемые значения, включая количество ячеек на доске.
Добавьте прослушиватели событий нажатия клавиш и нажатия клавиш.
Наконец, все, что осталось сделать, — это один раз вызвать игровой цикл нашей Змейки, чтобы начать игру. Это дает нам следующий полный код знаменитой игры Snake, созданный с использованием Canvas API и адской веб-пары HTML5/JavaScript:
https://gist.github.com/ssaurel/e01731169b9f0dca1a3fb19ba6e8f3a2?embedable=true р>
Наша игра-змейка в действии
Наша Змея готова, пришло время протестировать ее в веб-браузере, чтобы увидеть, работает ли магия Змеи снова, как это было, когда Nokia возмутительно доминировала в мобильном мире:
Из этой игры «Змейка» вы можете представить себе несколько возможных улучшений. Например, вы можете добавить звук каждый раз, когда змея ест яблоко. Вы можете использовать API веб-хранилища HTML5 для хранения локального рекорда игрока. Таким образом, когда игрок побьет свой рекорд, вы сможете отобразить поздравительное сообщение. Возможности безграничны, и единственным ограничением, как всегда в программировании, является ваше воображение.
Посмотрите это руководство на YouTube
Это руководство также можно посмотреть на YouTube на канале SSaurel:
https://www.youtube.com/watch?v=0uSfTEq2JMo&embedable=true а>
Также опубликовано здесь.
Оригинал