Создание игры «Змейка» на чистом JavaScript и HTML5
Змейка — классическая игра, которую мы знаем еще с давних времен. Мы представляем вам статью, в ходе которой мы создадим полноценную игру «Змейка» на чистом JavaScript и HTML5.
Для создания веб игр на языке JavaScript используется технология Canvas , которая позволяет выполнять JavaScript код в HTML5 документе. Вы можете более детально ознакомиться с этой технологией посмотрев видео ниже:
HTML страница может содержать классическую разметку, в которую необходимо вписать canvas для отображения игры внутри него. Пример кода:
Игра на JavaScript
Внутри этого файла мы подключаем скрипт «game.js«, который будет описывать весь функционал нашей игры.
JavaScript файл
Внутри JavaScript файла добавьте выборку канваса, а также укажите контекст игры.
var cvs = document.getElementById("canvas"); var ctx = cvs.getContext("2d");
Добавление изображений и аудио
Далее необходимо загрузить все основные изображения, которые будут использоваться в игре. Для этого используйте класс Image . Ниже вы можете скачать все необходимые картинки к игре.


Код добавления изображений и аудио в игру:
const ground = new Image(); // Создание объекта ground.src = "img/ground.png"; // Указываем нужное изображение const foodImg = new Image(); // Создание объекта foodImg.src = "img/food.png"; // Указываем нужное изображение
Рисование объектов
Чтобы нарисовать объекты, а также добавить функционал к игре необходимо прописать функцию, которая будет постоянно вызываться. Такую функцию вы можете назвать как вам будет угодно. Чтобы функция работала постоянно, вы можете запустите её выполнение через setInterval() .
function draw() < // Какой-либо код >let game = setInterval(draw, 100); // Вызов функции из вне
Весь код игры стоит помещать в этот метод, ведь в нем он будет постоянно обрабатываться и игра будет выглядеть живой и анимированной.
Чтобы отследить нажатие игрока на какую-либо клавишу, необходимо использовать отслеживание событий — addEventListener . К примеру, чтобы отследить нажатие на любую клавишу на клавиатуре надо прописать следующий код:
// При нажатии на какую-либо кнопку document.addEventListener("keydown", someMethod); // Вызывается метод someMethod function someMethod() < // Изменяем что-то в коде >
Видео урок
Это были лишь небольшие азы перед созданием самой игры. Предлагаем вам ознакомиться с большим видео уроком, в ходе которого вы создадите 2D игру «Змейка» на чистом JavaScript’е.
Полезные ссылки из видео:
- Текстовый редактор Atom.io ;
- Подбор иконок IconFinder ;
- Хостинг компания Reg.ru .
Весь JS код игры
Ниже вы можете посмотреть на полностью весь код JavaScript файла, который был создан в ходе видео урока выше:
const canvas = document.getElementById("game"); const ctx = canvas.getContext("2d"); const ground = new Image(); ground.src = "img/ground.png"; const foodImg = new Image(); foodImg.src = "img/food.png"; let box = 32; let score = 0; let food = < x: Math.floor((Math.random() * 17 + 1)) * box, y: Math.floor((Math.random() * 15 + 3)) * box, >; let snake = []; snake[0] = < x: 9 * box, y: 10 * box >; document.addEventListener("keydown", direction); let dir; function direction(event) < if(event.keyCode == 37 && dir != "right") dir = "left"; else if(event.keyCode == 38 && dir != "down") dir = "up"; else if(event.keyCode == 39 && dir != "left") dir = "right"; else if(event.keyCode == 40 && dir != "up") dir = "down"; >function eatTail(head, arr) < for(let i = 0; i < arr.length; i++) < if(head.x == arr[i].x && head.y == arr[i].y) clearInterval(game); >> function drawGame() < ctx.drawImage(ground, 0, 0); ctx.drawImage(foodImg, food.x, food.y); for(let i = 0; i < snake.length; i++) < ctx.fillStyle = i == 0 ? "green" : "red"; ctx.fillRect(snake[i].x, snake[i].y, box, box); >ctx.fillStyle = "white"; ctx.font = "50px Arial"; ctx.fillText(score, box * 2.5, box * 1.7); let snakeX = snake[0].x; let snakeY = snake[0].y; if(snakeX == food.x && snakeY == food.y) < score++; food = < x: Math.floor((Math.random() * 17 + 1)) * box, y: Math.floor((Math.random() * 15 + 3)) * box, >; > else snake.pop(); if(snakeX < box || snakeX >box * 17 || snakeY < 3 * box || snakeY >box * 17) clearInterval(game); if(dir == "left") snakeX -= box; if(dir == "right") snakeX += box; if(dir == "up") snakeY -= box; if(dir == "down") snakeY += box; let newHead = < x: snakeX, y: snakeY >; eatTail(newHead, snake); snake.unshift(newHead); > let game = setInterval(drawGame, 100);
Также вы можете скачать весь проект целиком по этой ссылке .
Больше интересных новостей

Самые интересные TED-видео о Data Science

Как перестать быть ужасным программистом?

Принцип работы беспилотных машин

Лучшие сайты, созданные на C# ASP .NET
Комментарии (4)
Саня 20 ноября 2023 в 09:47
А как сделать так, чтобы игра начиналась заново после проигрыша?
Михаил 27 марта 2023 в 11:53
а где файл со стилямимиша 05 мая 2023 в 18:18
зажми контрл и нажми на этот текст
Елена 03 августа 2022 в 13:28
Кирилл Михайлович 17 мая 2022 в 20:33
Своя игра: создаём собственную «Змейку»
Не так давно мы разбирали, как искусственный интеллект учится играть в змейку. А теперь мы сами сделаем такую игру, чтобы ей могли насладиться обычные люди. Что нам понадобится:
- HTML, чтобы можно было играть прямо в браузере;
- CSS для украшений;
- JavaScript для самой игры.
Логика игры
У классической змейки правила простые:
- есть поле из клеточек, где случайным образом появляется еда;
- есть змейка, которая всё время двигается и которой мы можем управлять;
- если змейка на своём пути встречает еду — еда исчезает, появляется в новом месте, а сама змейка удлиняется на одну клеточку;
- если змейка врежется в стену или в саму себя, игра заканчивается.
Чтобы играть было проще, мы сделаем так, чтобы змейка не врезалась в стенки, а проходила сквозь них. Если что — сможете это сами потом настроить в коде, когда захотите посложнее.
Последовательность наших действий будет такой:
- Делаем пустую HTML-страницу.
- Настраиваем внешний вид с помощью CSS.
- Рисуем игровое поле.
- Пишем скрипт, который и будет отвечать за всю игру.
Делаем HTML-страницу
С этим всё просто: берём стандартный код и сохраняем его как файл snake.html .
Змейка
Это даст нам пустую страницу, которую мы сейчас немного настроим стилями.
Настраиваем внешний вид
За внешний вид на странице у нас отвечает раздел , поэтому мы просто добавим в него CSS-код:
html, body < height: 100%; margin: 0; >/*Задаём глобальные параметры*/ body < background: black; display: flex; align-items: center; justify-content: center; >/*Делаем границу вокруг игрового поля*/ canvas
Теперь у нас на странице нет лишних отступов, зато всё по центру, есть чёрный фон и граница вокруг игрового поля. Самое время создать само игровое поле.
Рисуем игровое поле
Поле делается очень просто:
400 пикселей в ширину, столько же в высоту, название поля — game. Этого достаточно, чтобы браузер отобразил холст с такими размерами и позволил нам на нём рисовать.
Пишем скрипт
1. Зададим все переменные, которые нам понадобятся.
// Поле, на котором всё будет происходить, — тоже как бы переменная var canvas = document.getElementById('game'); // Классическая змейка — двухмерная, сделаем такую же var context = canvas.getContext('2d'); // Размер одной клеточки на поле — 16 пикселей var grid = 16; // Служебная переменная, которая отвечает за скорость змейки var count = 0; // А вот и сама змейка var snake = < // Начальные координаты x: 160, y: 160, // Скорость змейки — в каждом новом кадре змейка смещается по оси Х или У. На старте будет двигаться горизонтально, поэтому скорость по игреку равна нулю. dx: grid, dy: 0, // Тащим за собой хвост, который пока пустой cells: [], // Стартовая длина змейки — 4 клеточки maxCells: 4 >; // А это — еда. Представим, что это красные яблоки. var apple = < // Начальные координаты яблока x: 320, y: 320 >;
2. Сделаем генератор случайных чисел. Он нам понадобится, чтобы размещать еду на поле случайным образом.
// Делаем генератор случайных чисел в заданном диапазоне
function getRandomInt(min, max) < return Math.floor(Math.random() * (max - min)) + min;
3. Напишем основной игровой цикл, который будет работать бесконечно.
// Игровой цикл — основной процесс, внутри которого будет всё происходить function loop() < // Дальше будет хитрая функция, которая замедляет скорость игры с 60 кадров в секунду до 15. Для этого она пропускает три кадра из четырёх, то есть срабатывает каждый четвёртый кадр игры. Было 60 кадров в секунду, станет 15. requestAnimationFrame(loop); // Игровой код выполнится только один раз из четырёх, в этом и суть замедления кадров, а пока переменная count меньше четырёх, код выполняться не будет. if (++count < 4) < return; >// Обнуляем переменную скорости count = 0; // Очищаем игровое поле context.clearRect(0, 0, canvas.width, canvas.height); // Двигаем змейку с нужной скоростью snake.x += snake.dx; snake.y += snake.dy; // Если змейка достигла края поля по горизонтали — продолжаем её движение с противоположной стороны if (snake.x < 0) < snake.x = canvas.width - grid; >else if (snake.x >= canvas.width) < snake.x = 0; >// Делаем то же самое для движения по вертикали if (snake.y < 0) < snake.y = canvas.height - grid; >else if (snake.y >= canvas.height) < snake.y = 0; >// Продолжаем двигаться в выбранном направлении. Голова всегда впереди, поэтому добавляем её координаты в начало массива, который отвечает за всю змейку. snake.cells.unshift(< x: snake.x, y: snake.y >); // Сразу после этого удаляем последний элемент из массива змейки, потому что она движется и постоянно особождает клетки после себя if (snake.cells.length > snake.maxCells) < snake.cells.pop(); >// Рисуем еду — красное яблоко context.fillStyle = 'red'; context.fillRect(apple.x, apple.y, grid - 1, grid - 1); // Одно движение змейки — один новый нарисованный квадратик context.fillStyle = 'green'; // Обрабатываем каждый элемент змейки snake.cells.forEach(function (cell, index) < // Чтобы создать эффект клеточек, делаем зелёные квадратики меньше на один пиксель, чтобы вокруг них образовалась чёрная граница context.fillRect(cell.x, cell.y, grid - 1, grid - 1); // Если змейка добралась до яблока. if (cell.x === apple.x && cell.y === apple.y) < // увеличиваем длину змейки snake.maxCells++; // Рисуем новое яблочко // Помним, что размер холста у нас 400x400, при этом он разбит на ячейки — 25 в каждую сторону apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; >// Проверяем, не столкнулась ли змея сама с собой // Для этого перебираем весь массив и смотрим, есть ли у нас в массиве змейки две клетки с одинаковыми координатами for (var i = index + 1; i < snake.cells.length; i++) < // Если такие клетки есть — начинаем игру заново if (cell.x === snake.cells[i].x && cell.y === snake.cells[i].y) < // Задаём стартовые параметры основным переменным snake.x = 160; snake.y = 160; snake.cells = []; snake.maxCells = 4; snake.dx = grid; snake.dy = 0; // Ставим яблочко в случайное место apple.x = getRandomInt(0, 25) * grid; apple.y = getRandomInt(0, 25) * grid; >> >); >
4. Сделаем управление стрелочками на клавиатуре.
// Смотрим, какие нажимаются клавиши, и реагируем на них нужным образом document.addEventListener('keydown', function (e) < // Дополнительно проверяем такой момент: если змейка движется, например, влево, то ещё одно нажатие влево или вправо ничего не поменяет — змейка продолжит двигаться в ту же сторону, что и раньше. Это сделано для того, чтобы не разворачивать весь массив со змейкой на лету и не усложнять код игры. // Стрелка влево // Если нажата стрелка влево, и при этом змейка никуда не движется по горизонтали… if (e.which === 37 && snake.dx === 0) < // то даём ей движение по горизонтали, влево, а вертикальное — останавливаем // Та же самая логика будет и в остальных кнопках snake.dx = -grid; snake.dy = 0; >// Стрелка вверх else if (e.which === 38 && snake.dy === 0) < snake.dy = -grid; snake.dx = 0; >// Стрелка вправо else if (e.which === 39 && snake.dx === 0) < snake.dx = grid; snake.dy = 0; >// Стрелка вниз else if (e.which === 40 && snake.dy === 0) < snake.dy = grid; snake.dx = 0; >>);
5. Запускаем игру. Для этого достаточно запустить предыдущий бесконечный цикл, поэтому пишем:
6. Наслаждаемся результатом:
Чтобы у вас тоже получилось такое, просто скопируйте готовый код, сохраните его как HTML-файл и откройте в браузере.
Готовый код
Змейка html, body < height: 100%; margin: 0; >/*Задаём глобальные параметры*/ body < background: black; display: flex; align-items: center; justify-content: center; >/*Делаем границу вокруг игрового поля*/ canvas
Как улучшить
Этот код — самая простая реализация змейки, и игру можно сделать ещё лучше:
- выводить количество набранных очков;
- сделать так, чтобы нельзя было проходить сквозь стены;
- добавить препятствия;
- поставить таймер — кто больше соберёт еды за 5 минут;
- добавить вторую змейку и играть вдвоём.
Проголосуйте за тот вариант, который вам больше всего нравится, в комментариях, или сделайте свою змейку, где всё это будет одновременно.
Апскиллинг, как говорится
Апскиллинг — это, например, переход с уровня junior на уровень middle, а потом — senior. У «Яндекс Практикума» есть курсы ровно для этого: от алгоритмов и типов данных до модных фреймворков.

Получите ИТ-профессию
В «Яндекс Практикуме» можно стать разработчиком, тестировщиком, аналитиком и менеджером цифровых продуктов. Первая часть обучения всегда бесплатная, чтобы попробовать и найти то, что вам по душе. Дальше — программы трудоустройства.
Игра «Змейка»

Итак, приступим к написанию игры «Змейка» и закрепим навыки перемещения. Используем клоны для создания эффекта ползания змеи.
Для начала необходимо нарисовать голову змейки (рисуем в режиме векторной графики). Для этого:
- Удаляем спрайт кота;
- Выбираем нарисовать новый спрайт «Голова«;
- Переходим в костюмы;
- Рисуем голову с размерами 40 х 40.

Размер 40 х 40 выбран не случайно. Ведь игра «Змейка» относится к числу игр на клетчатом поле.
Среди таких игр также известны:
- Крестики-нолики;
- Морской бой;
- Тетрис;
- Сапёр и другие.
Соответственно, 40 х 40 – условный размер клетки нашего поля. Хоть клетки и не видны, перемещения будем делать с шагом 40.

Вспоминаем, как управлять движениями. Мы это уже делали в игре «Лабиринт«:

С учётом принципа управления движением, напишем код для «Головы«:

Следующим шагом необходимо:
- Продублировать спрайт «Головы«;
- Переименовать получившийся спрайт «Голова2» в «Хвост«.

Дорабатываем костюм «Хвоста«, удалив улыбку и глаза. Поскольку голова рисовалась в режиме векторной графики, то достаточно выделить и удалить глаза и улыбку:

Нужно, чтобы голова хоть как-то отличалась от хвоста. Поэтому, когда «Хвост» доработан, вернёмся к костюму головы и зададим ей размеры 38 х 38:

Создание эффекта движения
Пришла пора задействовать клоны. Код для спрайта «Хвост» будет следующим (предварительно необходимо удалить продублированный код «Головы«):

Пора добавить спрайт «Еда«. Подойдёт Яблоко (Apple):

Поскольку появляться «Еда» должна в случайных местах, используем следующий код:
Тут важно, чтобы положение яблока было кратным 40: как по X, так и по Y. Таким образом, код, приведённый выше, поместит яблоко в одну из условных «клеток»:
И змейка всегда встретит яблоко на своём пути. Также необходимо соблюсти сопоставимость размеров головы змейки и яблока. Для этого зайдём в костюм «Еда» (яблоко) и установим для него размеры 40 x 40 пикселей:

Код для «Еда» (яблоко):

Пора научиться управлять длиной змейки. Для этого переименуем уже имеющуюся переменную в новом проекте:

дав ей имя «Длина хвоста»:

Для начала добавим в код «Головы» начальное значение для «Длины хвоста» в момент старта игры:

А когда хвост у змейки должен вырасти? Правильно, когда она «съест» яблоко, т.е. коснётся спрайта «Еда«. Поэтому в код «Еда» добавляем увеличение хвоста:

Игру уже можно начать тестировать.
Ограничения
Тест игры показал, что змейка может пересекать сама себя (проходить головой «сквозь» хвост):

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

и будет передавать сообщение о завершении Игры.

ожидает, пока переданное сообщение будет обработано всеми спрайтами, и только потом «разрешает» программе выполнять следующий шаг. Соответственно, код «Головы» примет следующий вид:

Чтобы скорость игры увеличивалась с каждым съеденным яблоком, необходимо регулировать задержку в блоке «Ждать:»

Для этого создадим переменную «Задержка»:

При нажатии «Флажка» в коде любого спрайта игры необходимо задать стартовую величину задержки, чтобы змейка изначально двигалась медленно и ей было легко управлять. Пусть это будет величина в 1,5 (хотя позднее её можно поменять):

Затем во всех блоках «Ждать» (с задержкой 0,25 сек.), необходимо применить «Ждать» с использованием переменной «Задержка»:
Код для «Хвоста» примет вид:

Что нужно сделать самостоятельно?
- Добавить переменную «Очки» и организовать подсчёт очков;
- Обработать сообщение «Игра окончена» для «Хвоста«, «Еда» и смены фона.
Если пока не получилось, не расстраивайся.
Посмотри, как это сделано в проекте здесь?
ПРОТЕСТИРУЙ. РАЗБЕРИСЬ САМОСТОЯТЕЛЬНО.

Надеюсь, разобрался как сделать заставку с кнопкой?
Надоело работать во фронтенд с JavaScript? Используйте Python для браузера!
“Как так?” —думаю, примерно такой будет реакция большинства на заголовок этой статьи. Что значит “Используйте Python для браузера?”. Ведь всем известно, что в браузерах может выполняться только JavaScript.
Что ж, ниже приведён скриншот исходного кода моего личного веб-сайта. Обратите внимание на его отличия:
Всё верно, это Python!
А теперь давайте поговорим о том, как он работает, и какие другие альтернативы браузерному JS существуют.
Знакомимся с Brython
Brython — это реализация Python 3, написанная на JavaSсript и позволяющая писать код для браузеров на Python. По сути, это JS библиотека, преобразующая код Python в JS-эквивалент и вычисляющая его при выполнении.
И поскольку “написание кода для браузера на Python” звучит круто, я решил эту тему осветить.
Создаём “Змейку” при помощи Brython
Как и ожидалось, скорость вычисления кода Brython при выполнении ниже, чем у JavaScript. Конкретно в моём случае отличие в 1,7 раза.
Предполагаю, что для более сложных проектов Brython будет в несколько раз медленнее чистого JS.
Тем не менее вы можете заранее транспилировать код Brython и добавить JavaScript только на ту страницу, от которой требуется повышенная производительность.
Я пробовал использовать Brython Editor для преобразования кода Brython в JS и выполнить итоговый JS на странице, но при этом выбрасывалось огромное количество ошибок, и я решил пока эту затею отложить.
Выводы по использованию Brython
Несмотря ни на что, Brython меня весьма впечатлил. Ниже я привёл плюсы и минусы, обнаруженные на личном опыте использования этого языка:
Плюсы
- Мне удалось создать “Змейку” без лишних хлопот и при этом я получил позитивный опыт отладки.
- В моём простом проекте Brython легко взаимодействовал с нативными объектами JS доступными на странице.
- Я ценю тот факт, что мой код выглядит чище, чем в Python, а также, что я могу использовать полезный синтаксис Python в написании кода для браузера.
- Что касается “Змейки, то несмотря на её более долгую загрузку по сравнению с чистым JS, для пользователя эта разница заметна не будет.
- Меня порадовало видеть Python в исходном коде моего сайта 🙂
Минусы
- При выполнении Brython намного медленнее чистого JS.
- Разработчику для удобства работы с Brython необходимо в некоторой степени знать JavaScript.
- Неизбежно большее число ошибок.
- Документация Brython и его веб-сайт неудобен в навигации и обучения.
- Brython недостаёт развитой экосистемы и инструментов для разработки.
Закончив в итоге свой первый проект Brython, я могу с уверенностью сказать, что однажды вернусь к этому языку ещё.
Тем не менее я считаю, что в своём текущем состоянии Brython больше подходит JS разработчикам, знающим Python и уставшим от JavaScript, нежели Python разработчикам, желающим заниматься веб-разработкой, не изучая при этом JavaScript.
На мой взгляд, для успешной работы в Brython вам нужно понимать некоторые аспекты JS. Если же вы решите затратить на их изучение столько времени, чтобы в итоге писать на Brython легко, то можете с тем же успехом просто использовать сам JavaScript.
Другие альтернативы браузерному JS
Я выбрал Brython по причине того, что среди всех альтернатив JS на основе Python, с которыми я познакомился, только эта по-прежнему активно дорабатывается на GitHub. Большинство известных мне транспиляторов Python -> JavaScript не видели коммитов уже на протяжении нескольких лет. Тем не менее другие альтернативы существуют.
Достаточно интересно выглядит в этом плане Pyodide. Он компилирует Python (вместе с его библиотеками для обработки данных) в WebAssembly, который позволяет выполнять код Python в браузере.
Как можно догадаться из названия, WebAssembly является веб-ассемблером. Так же как ассемблер в наших компьютерах может выступать в качестве посредника между высокоуровневым языком и машинным кодом, так и WebAssembly может позволять производить аналогичные операции в веб.
Таким образом, можно написать в WebAssembly компилятор для Python или любого другого языка, который позволит этому языку выполняться в браузере.
Это амбициозный и многообещающий проект, который скорее всего приведёт к росту объёмов веб-разработки без применения JavaScript.
Тем не менее он по-прежнему пребывает на начальной стадии (около 3 лет) развития, поэтому пройдёт ещё, вероятно, немало времени, прежде чем JavaScript будет повсеместно замещён другим языком.
И пока этот день не настанет, разработчики будут вынуждены прибегать к использованию инструментов вроде Brython, если уж работать с JavaScript очень надоест.
Но лично я считаю, что это неплохое начало!
- 20 сокращений JavaScript, которые сэкономят ваше время
- Одномерный клеточный автомат в JavaScript
- Введение: 4 новейших операции JavaScript
