Sdscompany.ru

Компьютерный журнал
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

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

Создаём простую игру на Vanilla JS

  • Переводы, 4 октября 2018 в 11:52
  • Никита Прияцелюк

В этой статье мы создадим простую игру с помощью HTML5, CSS3 и чистого JavaScript. Вам не понадобятся глубокие знания программирования. Если вы знаете, для чего нужны HTML, CSS и JS, то этого более чем достаточно. На работу игры вы можете посмотреть здесь.

Структура файлов

Начнём с создания нужных папок и файлов:

Начальный шаблон, соединяющий CSS- и JS-файлы:

В игре будет 12 карточек. Каждая карта состоит из контейнера div с классом .memory-card , внутри которого находится два элемента img . Первая отвечает за лицо ( front-face ) карточки, а вторая — за рубашку ( back-face ).

Необходимые изображения можно скачать из репозитория проекта.

Обернём набор карточек в контейнер section . В итоге получаем:

Мы используем простой, но очень полезный сброс стилей, который будет применён ко всем элементам:

Свойство box-sizing: border-box учитывает значения внутренних отступов и границ элемента при подсчёте общей высоты и ширины, поэтому нам не нужно заниматься математикой.

Если применить к body свойство display: flex и margin: auto к контейнеру .memory-game , то он будет выровнен вертикально и горизонтально.

.memory-game также будет flex-контейнером. По умолчанию ширина элементов уменьшается, чтобы они помещались в контейнер. Если присвоить свойству flex-wrap значение wrap , элементы будут располагаться на нескольких строках в соответствии с их размерами:

Ширина и высота каждой карточки подсчитывается с помощью CSS-функции calc() . Создадим три ряда по четыре карточки, установив значения ширины и высоты равными 25% и 33.333% соответственно минус 10px от внешнего отступа.

Ивент перенесён, есть новые даты ( 16 – 17 июня ) , Санкт-Петербург, 10 750–138 000 ₽

Чтобы разместить наследников .memory-card , добавим position: relative . Так мы сможем абсолютно расположить наследников относительно родительского элемента.

Свойство position: absolute , установленное для .front-face и .back-face , уберёт элементы с их исходных позиций и разместит поверх друг друга:

Поле из карточек должно выглядеть примерно так:

Добавим ещё эффект при клике. Псевдокласс :active будет срабатывать при каждом нажатии на элемент. Он устанавливает длительность анимации равной 0.2 с:

Переворачиваем карточки

Чтобы перевернуть карточку после нажатия, добавим класс flip . Для этого давайте выберем все элементы memory-card с помощью document.querySelectorAll() . Затем пройдёмся по ним в forEach -цикле и добавим обработчики событий. При каждом нажатии на карточку будет вызываться функция flipCard() . this отвечает за нажатую карточку. Функция получает доступ к списку классов элемента и активирует класс flip :

CSS класс flip переворачивает карточку на 180 градусов:

Чтобы создать 3D-эффект переворота, добавим свойство perspective в .memory-game . Это свойство отвечает за расстояние между объектом и пользователем в z-плоскости. Чем ниже значение, тем сильнее эффект. Установим значение 1000px для едва уловимого эффекта:

Добавим к элементам .memory-card свойство transform-style: preserve-3d , чтобы поместить их в 3D-пространство, созданное в родителе, вместо того, чтобы ограничивать их плоскостью z = 0 (transform-style):

Теперь мы можем применить transition к свойству transform , чтобы создать эффект движения:

Отлично, теперь карточки переворачиваются в 3D! Но почему мы не видим лицо карточки? На данный момент .front-face и .back-face наложены друг на друга из-за абсолютного позиционирования. Рубашкой каждого элемента является зеркальное отражение его лица. По умолчанию значение свойства backface-visibility равно visible , поэтому вот что мы видим при перевороте карточки:

Чтобы исправить это, применим свойство backface-visibility: hidden для .front-face и .back-face :

Если перезагрузить страницу и снова перевернуть карточку, она пропадёт!

Так как мы скрыли заднюю сторону обеих картинок, на обратной стороне ничего нет. Поэтому сейчас нам нужно перевернуть .front-face на 180 градусов:

Наконец, мы получили желаемый эффект переворота!

Ищем пару

Мы научились переворачивать карточки, теперь нужно разобраться с проверкой на совпадение.

После нажатия на первую карточку она ожидает переворота другой. Переменные hasFlippedCard и flippedCard будут отвечать за состояние переворота. Если ни одна карточка не перевёрнута, значение hasFlippedCard устанавливается равным true , а нажатой карточке присваивается flippedCard . Ещё давайте сменим метод toggle() на add() :

Теперь при нажатии на вторую карточку мы попадаем в else-блок нашего условия. Чтобы проверить, совпадают ли карточки, нужно их всех идентифицировать.

Всякий раз, когда нам нужно добавить дополнительную информацию к HTML-элементам, мы можем использовать data-* атрибуты, где вместо «*» может быть любое слово. Добавим каждой карточке атрибут data-framework :

Теперь мы можем проверить, совпадают ли карточки, с помощью свойства dataset . Поместим логику сравнения в метод checkForMatch() и снова присвоим переменной hasFlippedCard значение false . В случае совпадения будет вызван метод disableCards() и обработчики событий будут откреплены от обеих карточек, чтобы предотвратить их переворот. В противном случае метод unflipCards() перевернёт обе карточки с помощью 1500 мс тайм-аута, который удалит класс .flip :

Складываем всё воедино:

Более элегантный способ написать условие совпадения — тернарный оператор. Он состоит из трёх частей. Первая часть — это условие, вторая часть выполняется, если условие возвращает true , в противном случае выполняется третья часть:

Блокируем поле

Мы научились проверять, совпадают ли карточки, а теперь нужно заблокировать поле. Это нужно для того, чтобы два набора карточек не могли быть перевёрнуты одновременно, в противном карточки не будут переворачиваться обратно.

Объявим переменную lockBoard . Когда игрок нажмёт на вторую карточку, lockBoard будет присвоено значение true , а условие if (lockBoard) return; предотвратит переворот других карточек до того, как эти две будут спрятаны или совпадут:

Нажатие на ту же карточку

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

Чтобы избежать этого, добавим проверку на то, равняется ли нажатая карточка переменной firstCard , и вёрнемся из функции, если это так:

Переменные firstCard и secondCard нужно обнулять после каждого раунда. Реализуем эту логику в новом методе resetBoard() . Поместим в него hasFlippedCard = false и lockBoard = false . Деструктурирующее присваивание [var1, var2] = [‘value1’, ‘value2’] из ES6 позволяет писать код меньших размеров:

Новый метод будет вызываться из disableCards() и unflipCards() :

Перемешивание

Наша игра выглядит довольно неплохо, но играть в неё не очень весело, если карточки всегда на одном месте. Пора это исправить.

Когда у контейнера есть свойство display: flex , его элементы упорядочиваются сначала по номеру группы, а потом по порядку в исходном коде. Каждая группа определяется свойством order , которое содержит положительное или отрицательное целое число. По умолчанию свойство order каждого flex-элемента имеет значение 0 . Если групп больше одной, элементы сначала упорядочиваются по возрастанию порядка группы.

В игре есть 12 карточек, поэтому мы пройдёмся по ним в цикле, сгенерируем случайное число от 0 до 12 и присвоим его свойству order :

Чтобы вызвать функцию shuffle() , сделаем её IIFE (Immediately Invoked Function Expression). Это значит, что она будет выполнена сразу после объявления. Скрипт должен иметь примерно такой вид:

Создаем многопользовательскую веб-игру Javascript

Создаем многопользовательскую веб-игру Javascript

Вышедшая в 2015 году Agar.io стала прародителем нового жанра игр .io, популярность которого с тех пор сильно возросла. Рост популярности игр .io я испытал на себе: за последние три года я создал и продал две игры этого жанра..

На случай, если вы никогда раньше не слышали о таких играх: это бесплатные многопользовательские веб-игры, в которых легко участвовать (не требуется учётная запись). Обычно они сталкивают на одной арене множество противоборствующих игроков. Другие знаменитые игры жанра .io: Slither.io и Diep.io.

В этом посте мы будем разбираться, как с нуля создать игру .io. Для этого достаточно будет только знания Javascript: вам нужно понимать такие вещи, как синтаксис ES6, ключевое слово this и Promises. Даже если вы знаете Javascript не в совершенстве, то всё равно сможете разобраться в большей части поста.

Пример игры .io

Для помощи в обучении мы будем ссылаться на пример игры .io. Попробуйте в сыграть в неё!

Игра довольно проста: вы управляете кораблём на арене, где есть другие игроки. Ваш корабль автоматически стреляет снарядами и вы пытаетесь попасть в других игроков, в то же время избегая их снарядов.

1. Краткий обзор/структура проекта

В примере используется следующее:

  • Express — самый популярный веб-фреймворк для Node.js, управляющий веб-сервером игры.
  • socket.io — библиотека websocket для обмена данными между браузером и сервером.
  • Webpack — менеджер модулей. О том, зачем использовать Webpack, можно прочитать здесь.

Вот как выглядит структура каталога проекта:

public/

Всё в папке public/ будет статически передаваться сервером. В public/assets/ содержатся используемые нашим проектом изображения.

Весь исходный код находится в папке src/ . Названия client/ и server/ говорят сами за себя, а shared/ содержит файл констант, импортируемый и клиентом, и сервером.

2. Сборки/параметры проекта

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

webpack.common.js:

Самыми важными здесь являются следующие строки:

  • src/client/index.js — это входная точка клиента Javascript (JS). Webpack будет начинать отсюда и станет рекурсивно искать другие импортированные файлы.
  • Выходной JS нашей сборки Webpack будет располагаться в каталоге dist/ . Я буду называть этот файл нашим пакетом JS.
  • Мы используем Babel, и в частности конфигурацию @babel/preset-env для транспиляции (transpiling) нашего кода JS для старых браузеров.
  • Мы используем плагин для извлечения всех CSS, на которые ссылаются файлы JS, и для объединения их в одном месте. Я буду называть его нашим пакетом CSS.

Вы могли заметить странные имена файлов пакетов ‘[name].[contenthash].ext’ . В них содержатся подстановки имён файлов Webpack: [name] будет заменён на имя входной точки (в нашем случае это game ), а [contenthash] будет заменён на хеш содержимого файла. Мы делаем это, чтобы оптимизировать проект для хеширования — можно приказать браузерам бесконечно кешировать наши пакеты JS, потому что если пакет изменяется, то меняется и его имя файла (изменяется contenthash ). Готовым результатом будет имя файла вида game.dbeee76e91a97d0c7207.js .

Файл webpack.common.js — это базовый файл конфигурации, который мы импортируем в конфигурации разработки и готового проекта. Вот, например, конфигурация разработки:

webpack.dev.js

Для эффективности мы используем в процессе разработки webpack.dev.js , и переключается на webpack.prod.js , чтобы оптимизировать размеры пакетов при развёртывании в продакшен.

Локальная настройка

Рекомендую устанавливать проект на локальной машине, чтобы вы могли следовать за этапами, перечисленными в этом посте. Настройка проста: во-первых, в системе должны быть установлены Node и NPM. Далее нужно выполнить

и вы готовы к работе! Для запуска сервера разработки достаточно выполнить

и зайти в веб-браузере на localhost:3000. Сервер разработки будет автоматически пересобирать заново пакеты JS и CSS в процессе изменения кода — просто обновите страницу, чтобы увидеть все изменения!

3. Входные точки клиента

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

index.html

Этот пример кода слегка упрощён для понятности, то же самое я сделаю и со многими другими примерами поста. Полный код всегда можно посмотреть на Github.

  • Элемент HTML5 Canvas ( ), который мы будем использовать для рендеринга игры.
  • для добавления нашего пакета CSS.

Пишем игру на HTML5/JS

На выходных нашлось немного свободного времени и я решил попрактиковаться в gamedev разработке. Давно собирался написать какую-нибудь игрушку, но все руки не доходили. Бегло пробежался по сети в поисках как это делают настоящие гуру. Мне понравилась вот эта статья. За основу своей будущей игры я взял фреймворк автора статьи.

Начало

  • sprite.js — библиотечка работы со спрайтами
  • resources.js — подгрузка ресурсов
  • input.js — библиотека ввода с клавиатуры
  • app.js — основной файл игры

Далее буду рассказывать только о файле app.js . Разберем его содержимое.

Для плавности анимации будем использовать requestAnimationFrame . Подробно о нем ознакомиться можно здесь

Разделим разработку нашей игры на несколько этапов:

  1. Создание и инициализация холста (canvas) на странице
  2. Добавление основной функции-цикла игры
  3. Инициализация и рендер объектов и ресурсов игры
  4. Обработка событий ввода пользователя
  5. Математика и расчет столкновений объектов в игре
  6. Окончание и перезагрузка игры

Этап 1. Создание и инициализация холста

Первым делом что мы должны сделать — это создать canvas элемент и добавить его к тегу body основной страницы игры.

  • Создаем объект canvas
  • Указываем, что мы создаем 2D игру (далее будем использовать везде в коде объект ctx )
  • Задаем размеры холста
  • Добавляем холст к тегу body на странице

Этап 2. Добавление основной функции-цикла

Основной цикл необходим для обновления и рендера игры.

Здесь вызываем функцию requestAnimFrame (к сожалению, поддерживается не во всех браузерах), которая генерирует 60 фреймов/секунду (как это было описано выше).

Этап 3. Инициализация и рендер объектов и ресурсов игры

Используем resource.js для загрузки ресурсов в игру. Хорошим правилом является добавить все изображения в 1 спрайт, но т.к я рисовал не сам, а брал готовые картинки, поэтому я решил с этим на заморачиваться, тем более, что в данном случае это не столь критично. Так это выглядит в коде

В функции init загружаем мир и добавлеем хэндлер кнопки reset , после game over.

Начальное состояние

Обновление состояния игрового процесса

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

Здесь же используем sprite.js . Всю функцию можно посмотреть в исходниках.

Этап 4. Обработка событий ввода пользователя

Наш герой должен уметь двигаться вверх, вниз, влево, вправо. Соответственно привожу ниже реализацию данного решения

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

Этап 5. Математика и расчет столкновений объектов в игре

Анимация персонажей, математика движения пуль, и логика движения NPC в игре описаны в функции updateEntities . Вот тут как раз нам и потребуются базовые знания линейной алгебры.

Логика обновления анимации спрайтов башни. И создаем патроны для каждой башни в своем массиве.

Динамика пуль башни:

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

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

Полный код функции updateEntities можно посмотреть в исходникак на GitHub.

Математика расчета столкновений хорошо описана в статье автора (раздел Collision Detection) используемого мной 2d бутстрапа.

Этап 6. Game Over и рестарт

Когда пауки доползают до нашего героя наступает конец света игры.

Показываем окно GAME OVER и кнопку «Начать заного». Кликаем ее и все начинается сначала 🙂

Заключение

В итоге, я для себя понял, что в gamedev много плюсов:

  • Весело и интересно проводишь время
  • Повторяешь курс школьной геометрии. Если игра серьезней, то и универ вспоминаешь 🙂
  • Практика программирования игр
  • Удовлетворение от проделанной работы

Посмотреть исходники можно тут, поиграть здесь.

Разработка игр на JavaScript

Web — удобная платформа для быстрого старта разработки игр, особенно если вы знакомы с языком JavaScript. Эта платформа обладает богатыми возможностями по отрисовке содержимого и обработке ввода с различных источников.

C чего же начать разработку игры для web? Определим для себя следующие шаги:
— Разобраться с game loop и отрисовкой;
— Научиться обрабатывать пользовательский ввод;
— Создать прототип основной сцены игры;
— Добавить остальные сцены игры.

Game loop

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

А в виде кода простейшая реализация игрового цикла на JavaScript может выглядеть так:

Функция update() отвечает за логику игрового процесса и обновление состояния игры в зависимости от пользовательского ввода. Функция render() отрисовывает текущее состояние игры. При этом абсолютно неважно, с помощью каких технологий происходит отрисовка (Canvas, DOM, SVG, console etc).

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

Реализация game loop в браузере

Рассмотрим несколько способов реализации игрового цикла c помощью метода requestAnimationFrame. В самой простой реализации мы столкнемся с определенными проблемами, которые постараемся решить в последующих реализациях.

Простой и ненадежный способ. Просто используем requestAnimationFrame и надеемся на стабильные 60 FPS. Код для такого игрового цикла мог бы выглядеть так:

Следует отличать плавность отрисовки игровой сцены (так называемые «тормоза» в играх) и скорость изменений в сцене (скорость событий в игре).

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

Получается, что указанный FPS может не только быть нестабильным, но ещё и в некоторых ситуациях выдавать частоту, в 2 раза отличающуюся от «идеальных» 60 FPS — как в положительную, так и в отрицательную сторону.

На примере ниже можно увидеть, как при наивном подходе скорость игры будет зависеть от частоты кадров — попробуйте подвигать ползунок:

Совсем плохо — скорость игровой логики зависит от мощности и загруженности устройства

Данный подход категорически не рекомендуется использовать — он приведен здесь только для примера.

Использовать RAF и рассчитывать время между кадрами. Сделаем наш код более гибким — будем считать, сколько времени прошло между предыдущим и текущим вызовами requestAnimationFrame:

Теперь при проседании или изменении производительности скорость игры не изменится, а изменится только плавность отрисовки:

Данный подход работает, но решает ли он все проблемы?

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

Можно ли добиться фиксированного интервала, если подобное не поддерживается браузером? Есть способ, но код придется немного усложнить:

Демо работы аналогично предыдущему примеру:

Постоянный интервал для update()

Таким образом, фиксированный временной шаг дает следующие преимущества:
— Упрощение кода логики игры update();
— Предсказуемость поведения игры, а соответственно, и возможность создания replay игровой сцены;
— Возможность легкого замедления/ускорения игры (slomo);
— Стабильная работа физики.

Зависимость физических движков от FPS

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

Ядро игрового движка

Осталась еще одна проблема, которую нужно решить — неактивные вкладки браузера. С текущим кодом, если пользователь на несколько минут сделает вкладку неактивной, а потом вернется, код для update() будет вызван очень много раз за все время отсутствия, и игровая логика может убежать далеко вперёд. Конечно, можно продумать механизмы вроде паузы состояния игры, но все равно стоит избавиться от многократного вызова update().

Подобные случаи можно проконтролировать и разрешить максимальную задержку между вызовами не более, чем 1 секунда. Собрав всё вышесказанное вместе, получаем код, который можно использовать как заготовку для создания игры:

Этот код можно взять как основу для игрового цикла, и останется только реализовать две функции —update() и render().

Различный FPS для update() и render()

Game loop с фиксированным временным шагом позволяет контролировать желаемое количество FPS для игровой логики. Это очень полезно, так как позволяет снизить нагрузку на устройство в играх, где нет необходимости просчитывать логику 60 раз в секунду. Тем не менее, даже при низком FPS для игровой логики возможно продолжать рендеринг с высоким FPS:

Оба квадрата изменяют свое положение и угол на частоте 10 FPS и рендерятся на частоте 60 FPS

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

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

LERP дает возможность получить промежуточные значения для отрисовки при указании процента от 0 до 1

Реализация функции линейной интерполяции:

Добавление поддержки slow motion

Совсем немного изменив код игрового цикла, можно добиться поддержки slow motion без изменения остального кода игры:

Добавим slow motion в предыдущее демо. Используя ползунок, можно регулировать скорость игровой сцены:

Обработка пользовательского ввода

Обработка ввода в играх отличается от классических web-приложений. Основное отличие состоит в том, что мы не сразу реагируем на различные события, вроде keydown или click, а сохраняем состояние клавиш в обычный объект:

Пока определенная кнопка нажата, значение будет true, а как только пользователь отпустит кнопку, значение вернется на false.

Затем, когда будет вызван очередной update(), мы можем отреагировать на пользовательский ввод и изменить игровое состояние:

Примечание: не используйте пиксели как единицу измерения для логики игры. Правильнее создать константу, например, const METER = 100; и от нее рассчитывать все остальные значения, такие как высота персонажа, скорость и т. п. Таким образом, можно отвязаться от рендеринга и сделать рендеринг для retina-устройств без лишней головной боли. В примерах кода этой статьи для простоты значение модели напрямую привязано к рендерингу.

Ниже приведен пример реализации пользовательского ввода, используйте кнопки W, S, A, D и R для движения и вращения квадрата:

Структура игры. Сцены

Сцены в играх — довольно удобный инструмент для организации кода. Они позволяют разделить части игры на различные компоненты, каждый из которых может обладать своими update() и render().

В большинстве игр можно наблюдать следующий набор сцен:

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

Обратите внимание на вызов метода setScene — он находится в основном объекте игры и позволяет сменить текущую сцену на другую:

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

Используйте W, S, A, D, R и ENTER для управления

Добавляем звук

Познакомиться поближе с Web Audio API поможет статья на html5rocks.

Вместо выводов

Если вы знакомы с JavaScript, то, используя небольшой сниппет для реализации game loop, вы можете в кратчайшие сроки создать простенькую игру. Для игрового цикла рекомендуется использовать именно фиксированный временной шаг, так как это не только удобно, но и функционально.

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

Подробнее о создании игр я рассказывал на встрече «Съесть собаку» — доступна запись доклада.

H Простейшая игра на JavaScript в черновиках Из песочницы

Доброго всем времени суток.

Занялся изучением JavaScript и решил применить его для браузерной игры, естественно несложной – «Камень, ножницы, бумага». Игру эту, я полагаю, знают все, принцип объяснять не буду.

Перейдем к делу , начал я с того, что написал страничку, на которой этот код будет запускаться:

Выглядит это следубщим образом:

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

Перейдем к самому коду игры:

Принцип следующий, задаем функцию, назовем ее «game». Сразу определим несколько переменных:

в конце дописал .toLowerCase(), чтобы любой способ ввода распознавался одинаково и принимался функцией, далее это важно.

Обратите внимание, выбор компьютера — computerChoice мы определяем рандомно, задаем границы выбора для рандома:

Теперь немного информации по сабжу, Math.Random() — функция, которая рандомно выбирает число от 0 до 1, таким образом мы можем смело разбивать этот интервал на 3 части: от 0 до 0,34; от 0,34 до 0,68; от 0,68 до 1.
Расставим выбор компьютера следующим образом, первый интервал — камень, второй — бумага, третий — ножницы. (тут на ваше усмотрение, кому какой порядок больше нравится, разницы нет, рандом — он и в Африке рандом)

Далее у меня были большие проблемы с выводом результата, дело все в том, что первично при изучении JS рассказывают о console.log(), но при использовании console.log(), запись будет вестись в лог-файл, а я хотел, чтобы результаты выводились на странице. Решил эту проблему при помощи document.write():

Таким образом выводим на страницу выбор игрока и выбор компьютера.

Далее нам надо бы сравнить выбор игрока с выбором компьютера, тут зададим переменную compare, она будет содержать в себе выбор обоих игроков.

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

В этих условиях нам необходимо рассмотреть абсолютно все возможные исходы, то есть, что будет, если игрок выберет камень, а компьютер ножницы или бумагу. Проще всего с одинаковым выбором, коротко и ясно, если выбор игрока соответствует выбору компьютера if (choice1 === choice2), то выдаем следующее сообщение document.write(«Ничья!»);

А как же нам быть со случаями, когда игрок оставляет поле ввода пустым или пишет слово, не соответствующее тому, которое нам подходит для игры (камень, ножницы или бумага)? Воспользуемся еще несколькими условиями:

Сначала мы определяем результат для случая, когда слово не ввели, затем определяем результат для случая, когда введенный текст не соответсвует ни одному из предложенных вариантов, напомню, что отрицание обозначается как «!==».

На завершающем этапе выдаем результат игры на страницу:

Результат выглядит так:

Вероятно вы заметили, что здесь я использовал не document.Write, а HTMLElement.Write. Это связано с тем, что в данной строке при использовании document.Write мы получим «undefined» в конце строки с результатом на странице. С чем это связано, я, к сожалению, ответить не готов.

Всем спасибо за внимание!
Не уверен, что на хабре можно спокойно размещать ссылки на собственные сайты, поэтому, если кому-то будет интересен этот код в действии, пишите мне на почту: orange.fox@icloud.com

Под спойлер спрячу код игры целиком, не жадный, можно заимствовать, не обижусь, если автора укажете. (:

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

Читать еще:  Configure java скачать
Ссылка на основную публикацию
Adblock
detector