Как делать игры на javascript
Перейти к содержимому

Как делать игры на javascript

  • автор:

2D игра на чистом JavaScript

В этом пошаговом руководстве мы создадим простую игру MDN Breakout, написанную на чистом JavaScript и отрендеренную на HTML5 .

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

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

Gameplay screen from the game MDN Breakout where you can use your paddle to bounce the ball and destroy the brick field, with keeping the score and lives.

Детали к урокам

Все уроки и версии игры MDN Breakout доступны в GitHub:

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

Примечание: Если вам интересно узнать о разработке двухмерных игр с помощью игровой библиотеки, ознакомьтесь с альтернативной серией статей 2D игра Breakout с использованием Phaser (en-US) .

Примечание: Эту серию статей можно использовать как материал для практических занятий по разработке игр. Также можно воспользоваться набором инструментов Gamedev Canvas Content Kit, основанном на этом уроке, если нужно сделать доклад о разработке игр в целом.

Создать JS-игру с мультиплеером за 24 часа и выжить

Аватарка пользователя IRLIX

Как всего за сутки мы с моими коллегами (шестью фронтендерами и одним бэкендером) создали настоящую мультиплеерную игру на JavaScript.

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

Аватарка эксперта Вадим Силантьев

Вадим Силантьев
Frontend-разработчик IRLIX

Создать JS-игру с мультиплеером за 24 часа и выжить 1

Собрались похакатонить…

Совсем недавно в компании IRLIX, где я работаю frontend-разработчиком, прошло знакомое для многих мероприятие — хакатон. На мой взгляд, это очень крутой формат, который независимо от масштаба позволяет изучить новые грани разработки. В том числе для frontend направления. Главное — объективно оценивать, на что вы способны и найти баланс между полётом фантазии и реальностью при выполнении задач.

Целью данного хакатона было создать ровно за 24 часа игру с нуля, используя только JavaScript, Node.js, Soket.io. и два ящика энергетиков.

Я очень легко соглашаюсь на разную движуху. И мне совершенно не обязательно знать, что из этого выйдет. Уже в процессе меня одергивает разум: «Чувак, зачем ты в это вписался?». Но раз пути назад нет — погнали. Этот раз тоже не стал исключением. Не успел я оглянуться — и вот уже полностью погружен в процесс разработки игры.

Почему JavaScript?

Сегодня игрушку можно сделать практически на любом языке программирования, но мы решили остановиться на JS. Выбор стека был обусловлен в основном нашими знаниями по определенным технологиям. Мы решили использовать библиотеку Soket.io, так как она поддерживает постоянную связь клиента с сервером и имеет возможность создавать кастомные эвенты между ними, что необходимо при построении мультиплеерной игры. На мой взгляд, это было идеальным решением в рамках времени, которым мы располагали.

Процесс разработки или сутки, которые я не забуду никогда

Мне казалось нереально сложным иметь только общее представление о том, что должно получиться в итоге, и ни малейшего представления о том, как это сделать. Спустя сутки я понял, что в данном случае главная фича для крутого результата — это именно свобода действий. Ведь тебя практически ничего не ограничивает (ну, кроме времени, само собой) — фантазируй, придумывай, воплощай.

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

const gameLoop = (game, io) => < io.sockets.emit('state', game); >; setInterval(() => < if (game.players && io) < gameLoop(game, io); >>, engineTimeConnect); 

Серверный движок

socket.on('state', (game) => < GAME = game; PLAYER = game.players[socket.id]; dt = 0; >); const drawLoop = () => < if (GAME) < now = performance.now(); dt = dt + (now - last); const dtPercent = dt / engineTimeConnect; last = now; context.clearRect(0, 0, WINDOW_WIDTH, WINDOW_HIGHT); // Рисуем игроков for (const id in GAME.players) < const player = GAME.players[id]; if (player.state !== 'DEATH') < drawPlayer(context, player, dtPercent); >> > window.requestAnimationFrame(drawLoop); >; window.requestAnimationFrame(drawLoop); 

Клиентский движок

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

const movement = < up: false, down: false, left: false, right: false, >document.addEventListener("keydown", (event) => < switch (event.keyCode) < case 65: // A movement.left = true; socket.emit("movement", movement); break; case 87: // W movement.up = true; socket.emit("movement", movement); break; case 68: // D movement.right = true; socket.emit("movement", movement); break; case 83: // S movement.down = true; socket.emit("movement", movement); break; >>); document.addEventListener("keyup", (event) => < switch (event.keyCode) < case 65: // A movement.left = false; socket.emit("movement", movement); break; case 87: // W movement.up = false; socket.emit("movement", movement); break; case 68: // D movement.right = false; socket.emit("movement", movement); break; case 83: // S movement.down = false; socket.emit("movement", movement); break; >>); 

Клиентский код

const movement = < up: false, down: false, left: false, right: false, >; socket.on('movement', (move) => < movement.up = move.up; movement.down = move.down; movement.left = move.left; movement.right = move.right; >); setInterval(() => < if (movement.down||movement.left||movement.right||movement.up) < const player = players[socket.id] || <>; if (movement.left && player.positionX > 0) < player.moveTo('left'); >if (movement.up && player.positionY > 0) < player.moveTo('up'); >if (movement.right && player.positionX < map.size.x) < player.moveTo('right'); >if (movement.down && player.positionY < map.size.y) < player.moveTo('down'); >> else < const player = players[socket.id] || <>; player.moveTo && player.moveTo('stop'); > >, engineTimeConnect); 

Серверный код

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

moveTo(direction)

Когда мы поняли, что движущиеся точки — это конечно круто, но недостаточно, решили пуститься «во все тяжкие» и делать мультиплеерный шутер. Первое, что мы сделали — проработали концепцию, отбросив все лишнее. После — упростили графику ( от того, что нарисовало богатое воображение в наших головах до реализуемого варианта). Затем перешли к тому, что создали персонажей и их способности к стрельбе.

Создать JS-игру с мультиплеером за 24 часа и выжить 2

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

Например, как грамотно доставить информацию на оба экрана, чтобы на каждом кадре отрисовки летевшая пуля находилась у обоих клиентов. Но выбранная архитектура решила проблему на корню: клиент просто рисовал данные приходящие с сервера и отправлял события об изменении данных, почти все расчеты происходили на серверном движке.

Еще пример: мы не знали, что делать с ФПС ( наша бравая лошадка-сервер вывозила не больше 4 человек, а после грустно ложилась помирать). Происходило это по нескольким причинам: чем больше клиентов, тем больше данных нужно отправлять, а данные отправлялись 60 раз в секунду, на 8 игроках игровой цикл замедлялся до 15 циклов в секунду. Однако для оптимизации процессов было еще слишком рано, готовой игровой модели еще не было, и мы продолжили разработку.

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

Создать JS-игру с мультиплеером за 24 часа и выжить 3

// линейная интерполяция, piece = 0.0 -> 1.0 const lerp = (start, finish, piece) => < return start + (finish - start) * piece; >; const drawProjectile = (ctx, bullet, dt) =>

Отрисовка снарядов на клиенте

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

Как я написал кастомный шрифт ради одного символа. Но сначала неделю страдал

Следующим этапом стала обработка столкновений. Первая наша попытка была просто ужасной: была куча блоков if/else, но все работало, однако глядя на такой код, хотелось плакать. Поэтому мы решили сделать все области столкновений в игре круговыми и обратиться к геометрии.

Создать JS-игру с мультиплеером за 24 часа и выжить 4

const getCollision = (obj1, obj2) => < const r = obj1.r + obj2.r; const dX = obj1.x - obj2.x; const dY = obj1.y - obj2.y; const xSq = dX * dX; const ySq = dY * dY; const dSq = xSq + ySq; const d = Math.sqrt(dSq); return r >d; >; 

Реализация с помощью кода

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

Вот тут мы и столкнулись с задачей на оптимизацию. Мы решили считать столкновения игрока со стенами на клиенте. И это сильно облегчило работу серверному движку.

Самым эмоциональным для меня стал момент записи звуков для игры. За неимением других источников нам пришлось имитировать их самим. Мы бегали вокруг стола, стучали кружками и делали что-то еще. К тому моменту прошло уже много часов хакатона, мозг немного был затуманен, что в некоторых моментах даже сыграло нам на руку. Особенно смешным и немного нелепым получился звук попадания снаряда — представьте, как рыба пытается сказать букву «П».

А что в результате?

В нашем случае результатом стал мультиплеерный 2D шутер с видом сверху. Игроки сражались каждый сам за себя, количество патронов было ограничено, но на на карте постоянно появлялись случайные объекты в виде (дополнительных патронов, усиления урона, аптечки), эти объекты создавали точки интереса на карте и вынуждали игроков постоянно двигаться, чтобы выиграть бой, от этого игра становилась более динамичной и веселой. При поражении игрок выбывал с карты на некоторое время, а после опять мог вступить в бой. На следующий день после хакатона, мы рубились в эту игрой с ребятами из офиса, и, как оказалось, шутер получился веселым и залипательным, что нас очень сильно порадовало.

Создать JS-игру с мультиплеером за 24 часа и выжить 5

Простые игры на Canvas в браузере могут сделать ваше приложение более интерактивным. Например, простой игрой вы можете заменить скучные и долгие экраны загрузок. А написание полноценных браузерных игр на JS может стать отличной альтернативой разработке однотипных, скучных приложений. Вердикт: геймдеву на JS быть!

Игра на чистом JavaScript за 20 минут

Игра на чистом JavaScript за 20 минут

На JS можно создавать сложные и простые игры любых жанров. Мы расскажем как создать 2D игру на JavaScript и HTML5 всего за 20 минут.

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

На html странице прописывается лишь тег канвас, а также подключение JS файла, в котором будет происходить обработка всей функциональности. К примеру, HTML файл может выглядеть следующим образом:

      Flappy Bird!    

В JS файле необходимо найти нужный канвас по id и указать способ работы с ним.

var cvs = document.getElementById("canvas"); var ctx = cvs.getContext("2d");

Добавление изображений и аудио

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

  • Скачать аудио файлы можно по этой ссылке ;

Код добавления изображений и аудио в игру:

var bird = new Image(); var bg = new Image(); // Создание объекта var fg = new Image(); // Создание объекта var pipeUp = new Image(); // Создание объекта var pipeBottom = new Image(); // Создание объекта bird.src = "img/bird.png"; // Указание нужного изображения bg.src = "img/bg.png"; // Аналогично fg.src = "img/fg.png"; // Аналогично pipeUp.src = "img/pipeUp.png"; // Аналогично pipeBottom.src = "img/pipeBottom.png"; // Аналогично // Звуковые файлы var fly = new Audio(); // Создание аудио объекта var score_audio = new Audio(); // Создание аудио объекта fly.src = "audio/fly.mp3"; // Указание нужной записи score_audio.src = "audio/score.mp3"; // Аналогично

Рисование объектов

Чтобы нарисовать объекты, а также добавить функционал к игре необходимо прописать функцию, которая будет постоянно вызываться. Такую функцию вы можете назвать как вам будет угодно. Главное, вам нужно вызвать эту функцию из вне её хотя бы один раз, а внутри неё прописать метод requestAnimationFrame , который будет вызывать функцию постоянно.

function draw() < // Какой-либо код requestAnimationFrame(draw); // Вызов функции постоянно >draw(); // Вызов функции из вне

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

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

// При нажатии на какую-либо кнопку document.addEventListener("keydown", someMethod); // Вызывается метод someMethod function someMethod() < // Изменяем что-то в коде >

Видео урок

Это были лишь небольшие азы перед созданием самой игры. Предлагаем вам ознакомиться с небольшим видео уроком, в ходе которого вы создадите небольшую 2D игру на чистом JavaScript’е.

Весь JS код игры

Ниже вы можете посмотреть на полностью весь код JavaScript файла, который был создан в ходе видео урока выше:

var cvs = document.getElementById("canvas"); var ctx = cvs.getContext("2d"); var bird = new Image(); var bg = new Image(); var fg = new Image(); var pipeUp = new Image(); var pipeBottom = new Image(); bird.src = "img/bird.png"; bg.src = "img/bg.png"; fg.src = "img/fg.png"; pipeUp.src = "img/pipeUp.png"; pipeBottom.src = "img/pipeBottom.png"; // Звуковые файлы var fly = new Audio(); var score_audio = new Audio(); fly.src = "audio/fly.mp3"; score_audio.src = "audio/score.mp3"; var gap = 90; // При нажатии на какую-либо кнопку document.addEventListener("keydown", moveUp); function moveUp() < yPos -= 25; fly.play(); >// Создание блоков var pipe = []; pipe[0] = < x : cvs.width, y : 0 >var score = 0; // Позиция птички var xPos = 10; var yPos = 150; var grav = 1.5; function draw() < ctx.drawImage(bg, 0, 0); for(var i = 0; i < pipe.length; i++) < ctx.drawImage(pipeUp, pipe[i].x, pipe[i].y); ctx.drawImage(pipeBottom, pipe[i].x, pipe[i].y + pipeUp.height + gap); pipe[i].x--; if(pipe[i].x == 125) < pipe.push(< x : cvs.width, y : Math.floor(Math.random() * pipeUp.height) - pipeUp.height >); > // Отслеживание прикосновений if(xPos + bird.width >= pipe[i].x && xPos = pipe[i].y + pipeUp.height + gap) || yPos + bird.height >= cvs.height - fg.height) < location.reload(); // Перезагрузка страницы >if(pipe[i].x == 5) < score++; score_audio.play(); >> ctx.drawImage(fg, 0, cvs.height - fg.height); ctx.drawImage(bird, xPos, yPos); yPos += grav; ctx.fillStyle = "#000"; ctx.font = "24px Verdana"; ctx.fillText("Счет: " + score, 10, cvs.height - 20); requestAnimationFrame(draw); > pipeBottom.onload = draw; 

Больше интересных новостей

ТОП языков программирования в 2024 году

ТОП языков программирования в 2024 году

5 команд терминала, которые должны знать все

5 команд терминала, которые должны знать все

7 портфолио разработчиков: примеры для вдохновения

7 портфолио разработчиков: примеры для вдохновения

Фриланс-платформы для программистов: ТОП-5 лучших

Фриланс-платформы для программистов: ТОП-5 лучших

Комментарии (3)

Кирилл 06 февраля 2024 в 10:15

3D Frameworks

Разработка игр на JavaScript: реально и безболезненно

ThreeJs – самая популярная 3D-библиотека. Она предлагает наборы функций для выполнения общих операций, которые должны происходить в 3D-сцене. Все мероприятия происходят на более высоком уровне, чем raw WebGL, и не надо заморачиваться с горой низкоуровневых действий.

BabylonJS

Этот фреймворк похож на предыдущий, но имеются различия:

  • API меняется каждые 3 месяца, что помогает при поиске старых решений в интернете;
  • активное и полезное сообщество;
  • продуктивные и отзывчивые разработчики (у Three.js самый старый баг на GitHub датируется 2013 годом, в Babylon.js отмечен два дня назад);
  • The playground – это отличный инструмент для быстрого “опробования” кода, объяснения проблемы и оказания помощи.

Литература

Как в любом уважающем себя мануале, далее идет подборочка книг по теме.

Кстати, у нас есть очень крутая статья по книгам для геймдэва – рекомендуем!

Мы подобрали для тебя литературу по базовым вещам. Когда определишься, какая ветка игровой разработки тебе больше нравится, будет легче подбирать книги JavaScript.

  • 3D Math Primer for Graphics and Game Development – Dunn Fletcher
  • Unity in Action – Джозеф Хокинг
  • Game Programming Patterns – Robert Nystrom
  • Архитектура игровых движков – Джейсон Грегори
  • Language Implementation Patterns – Terence Parr
  • Introduction to 3D Game Programming with DirectX 12 – Frank Luna
  • Искусственный интеллект. Современный подход – Стюарт Рассел
  • Системное программирование – Роберт Лав

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *