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

Добавил пользователь Владимир З.
Обновлено: 10.09.2024

В данной статье мы продолжим создавать трехмерную браузерную игру лабиринт на чистом html, css и javascript. В предыдущей части мы сделали простой 3-мерный мир, реализовали движение, управление, столкновения игрока со статическими объектами. В этой части мы будем добавлять гравитацию, статическое солнечное освещение (без теней), загружать звуки и делать меню. Увы, как и в первой части, демок здесь не будет.

Вспомним код, который мы сделали в предыдущей части. У нас имеются 3 файла:

1. Реализация гравитации и физики прыжка

У нас есть несколько переменных, которые создаются в разных частях файла javascript. Будет лучше, если мы перенесем их в одно место:

Добавим ускорение свободного падения к ним:

В конструктор player добавим 3 переменные — vx, vy и vz:

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

Теперь игрок движется быстрее. Но он не падает и не прыгает. Нужно разрешить прыжок тогда, когда он на чем-то стоит. А стоять он будет тогда, когда столкнется с горизонтальной (или почти) поверхностью. Как определить горизонтальность? Нужно найти нормаль плоскости прямоугольника. Делается это просто. Относительно координат прямоугольника нормаль направлена вдоль оси z. Тогда в мировых координатах нормаль имеет преобразованные координаты. Найдем нормаль (добавим локальную переменную normal):

Чтобы поверхность была горизонтальной, скалярное произведение нормали на ось y в мировых координатах должно равняться 1 или -1, а почти горизонтальная плоскость – близко к 1 или -1. Зададим условие почти горизонтальной плоскости:

Не забудем, что при отсутствии столкновений игрок точно не будет на земле, поэтому по умолчанию в начале функции collision() зададим onGround = false:

Однако, если игрок столкнется с поверхностью снизу, то он тоже окажется как бы на земле. Чтобы предотвратить это, проверим игрока на нахождение сверху плоскости (point3[1] должна быть меньше point2[1]):

Что мы делаем? взгляните на картинку:


Красный крест должен находиться ниже оранжевого в мировой системе координат (или y-координата должна быть больше). Это мы и проверяем в point3[1] > point2[1]. А point3 – есть как раз координаты красной точки. Перенесем инициализацию point2 внутрь условии коллизии:

Перенесемся в update(). Здесь мы тоже сделаем изменения. Во первых, добавим гравитацию и уберем смещение по y при нажатии на пробел:

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

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

Для проверки изменений изменим мир:

Если мы запустим игру, то увидим, что игрок может взбираться по почти вертикальной зеленой стене. Запретим это, добавив else dy = y1 — y0:

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

2. Создадим меню

Меню создадим в виде html-панелей и html-блоков. Оформление у всего меню будет примерно одинаковым: фон и стиль кнопок можно задать общими для всех. Итак, зададим три панели меню: главное меню, инструкция и вывод результатов по завершению игры. Переходы между меню, переход в мир и обратно будет выполняться скриптами javascript. Чтобы не нагромождать файл script.js, для переходов меню создадим новый файл menu.js, а в index.html подключим его:

В контейнере создадим 3 элемента, которые будут панелями меню:

Оформим их, добавив в style.css свойства для класса “menu”:

В меню (в файле index.html) добавим кнопки с соответствующими надписями:

Для кнопок тоже зададим стили в style.css:

Но мы не видим меню, так как у них задан стиль display:none, При запуске же игры один из пунктов меню должен быть виден, поэтому в html для 1-го меню добавим запись style = “display:block;”, а выглядеть это будет следующим образом:

Меню стало выглядеть вот так:


Отлично. Но если мы нажмем на кнопку, то курсор у нас захватится. Значит нам нужно разрешить захват мыши только в случае игры. Для этого введем в script.js переменную canlock и добавим ее в пункт создадим переменные:

Теперь мы можем щелкать меню. Настроим переходы с помощью скриптов в файле menu.js:

Теперь все кнопки меню, за исключением “начать игру”, работают. Настроим теперь кнопку button1. Если вы помните, в файле script.js функции CreateNewWorld() и setInterval() запускаются при загрузке веб-страницы. Удалим их оттуда. Вызывать их будем только при нажатии кнопки button1. Сделаем это:

Меню мы создали. Да, оно еще некрасивое, но это легко поправляется.

3. Создадим предметы и переход уровней.

А содержимое createNewWorld() изменим:

Строка нужна для того, чтобы задавать имя id. Игра пока ничуть не изменилась. Теперь добавим 3 массива: монеты (things), ключи (keys) и финиш (finish). Вставим их сразу после массива карты:

А в menu.js применим функцию CreateSquares() внутри обработчика нажатия кнопки “button1”:

Теперь настроим исчезновение предметов. В menu.js создадим функцию проверки расстояний от игрока до предметов:

Также в этом же файле создадим функцию repeatFunction() и добавим в нее команды:

А ее циклический вызов запустим в setInterval внутри button1:

Теперь предметы исчезают, когда мы к ним подходим. Однако они ровно ничего не делают. А мы хотим, чтобы при взятии желтых квадратов нам добавлялись очки, при взятии красных – появлялась возможность взять синий и закончить игру. Модифицируем функцию interact():

Изменим входные параметры для вызовов этой функции:

А в начале файла добавим четыре новые переменные:

Вы спросите, почему мы создали массивы из одного элемента а не просто переменные? Дело в том, что мы хотели передать эти переменные в interact() по ссылке, а не по значению. В javascript обычные переменные передаются только по значению, а массивы по ссылке. Если мы передадим в interact() просто переменную, то num будет копией переменной. Изменение num не приведет к изменению k или m. А если мы передаем массив, то num будет ссылкой на массив k или m, и когда мы будем менять num[0], то будет меняться k[0] и m[0]. Можно было, конечно, создать 2 почти одинаковые функции, но лучше обойтись одной, чуть более универсальной.

Для финиша все-таки придется создать отдельную функцию:

А clearWorld() настроим в script.js:

Как видите, очистка мира проводится довольно просто. В repeatFunction() добавим finishInteract():

Что происходит в finishInteract()? Если мы не взяли ключ (k[0] == 0), то пока ничего не происходит. Если взяли, то игра заканчивается, а происходит следующее: очищается мир, останавливается функция repeatFunction(), курсор перестает быть захваченным, счетчик ключей обнуляется, а мы переходим в главное меню. Проверим, запустив игру. Все работает. Однако после нажатия снова на игру, мы оказываемся сразу на финише, а некоторые предметы исчезают. Все потому что мы не ввели место первоначального спауна игрока, а массивы изменяются в течение игры. Давайте добавим в button1 точку спауна для игрока, а именно, приравняем его координаты к элементам массива start[0]:

Теперь игрок появляется в начале координат. Но вот вопрос: а если уровней в игре будет несколько? Добавим переменную уровней в menu.js:

Переделаем переменные map, things, keys, start, finish внутри script.js в массивы, слегка изменив их название:

Добавим 2-й уровень:

А сами массивы инициализируем перед уровнями:

функцию CreateNewWorld() придется изменить, добавив туда аргумент:

Изменим вызов CreateNewWorld() в файле menu.js:

Теперь при запуске консоль выдаст ошибку. Верно, ведь мы переименовали переменные map, things, keys и finish, теперь javascript не может понять, что это за переменные. Заново их инициализируем в script.js:

А в button1 (в menu.js) этим переменным присвоим копии элементов массивов mapArray, thingsArray, keysArray и finishArray (для лучшей читабельности поставим комментарии):

Где userSlice() – функция, которая копирует массив:

Если бы мы просто написали, к примеру, keys = keysArray[level], то в переменные были бы переданы не копии массивов, а указатели на них, а значит, они изменялись бы в процессе игры, что недопустимо, ибо при повторном запуске ключа на исходном месте уже не было бы. Вероятно, вы спросите, почему я не применил просто keysArray[level].slice(), а изобрел свои функции? Ведь slice() тоже копирует массивы. Я пробовал так сделать, однако он копировал именно ссылку на массив, а не сам массив, в результате чего изменение keys приводило к изменению keysArray[level], что означало пропадание ключа при повторном запуске. Дело в том, что в документации написано, что в одних случаях он воспринимает массивы как массивы и копирует их, в других же он воспринимает массивы как объекты и копирует лишь указатели на них. Как он это определяет, для меня загадка, поэтому если мне кто-нибудь подскажет, почему slice() не работает как планировалось, то я буду ему сильно благодарен.

Сделаем переход уровней. Это довольно просто. Изменим finishInteract(), добавив внутрь else следующие строки:

То есть, значение уровня прибавляется на 1, а если все уровни пройдены (у нас их 2), то уровни сбрасываются и очки score сбрасываются. Проверить это трудно, так как наши уровни сейчас ничем не отличаются. Изменим тогда mapArray[1]:

Итак, вы хотите сделать игру с помощью Canvas и HTML5? Следуйте этому руководству и окажетесь на пути в кратчайший срок. Руководство предполагает, что у вас, по меньшей мере, средний уровень знаний по JavaScript.

Вы можете вначале сыграть в игру или перейти непосредственно к статье и просматривать исходный код игры.

Создание холста

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

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

Пока мы можем оставить методы update и draw пустыми. Главное знаем, что setInterval() периодически их вызывает.

Здравствуй, мир

Теперь, когда мы имеем зацикленный геймплей, давайте обновим наш метод draw , нарисовав какой-нибудь текст на экране.

Совет. Не забудьте запустить ваше приложение после внесения изменений. Если что-то пойдёт не так, то гораздо проще отследить, когда есть всего несколько строк.

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

Теперь всё должно кружиться. Если проследовать вдоль движения, то на экране остаются рисунки от предыдущих раз. Попробуйте догадаться, почему это происходит. Потому что мы не очищаем экран. Итак, давайте добавим некий код очистки экрана в метод draw .

Создание игрока

Создаем объект для хранения данных игрока ответственный за вещи вроде рисования. Здесь мы создаём объект player с помощью простого литерального объекта для хранения всей информации.

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

Управление клавишами

Использование jQuery Hotkeys

Плагин jQuery Hotkeys намного упрощает обработку клавиш в разных браузерах. Вместо того, чтобы плакать над кроссбраузерной расшифровкой кода клавиш keyCode и charCode, мы можем сделать привязку клавиш следующим образом.

Движения игрока

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

Хорошая новость в том, что я включил 16-строчный интерфейс на JavaScript, который делает доступным события запросов. Он называется key_status.js и вы можете запросить статус клавиши в любой момент проверив keydown.left и др.

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

Идите и подвигайте его.

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

Добавление большего числа клавиш довольно легко, так что добавим каких-нибудь снарядов.

Добавляем больше игровых объектов

Снаряды

Теперь добавим снаряды для реальности. Вначале нужна коллекция для их хранения:

Далее нам нужен конструктор для создания экземпляра пули.

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

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

Финальный шаг отрисовывает пули.

Враги

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

Загрузка и рисование изображений

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

Обнаружение столкновения

У нас есть все эти летающие штучки на экране, но они не взаимодействуют друг с другом. Чтобы каждый знал, когда надо взорваться, нужно добавить нечто для обнаружения столкновения.

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

Есть несколько видов столкновений, которые надо проверить:

  1. Пули игрока => вражеские корабли
  2. Игрок => вражеские корабли

Сделаем метод для обработки столкновений, который вызывается из метода update .

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

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

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

На прощанье

Надеюсь, вам понравилось обучение основам создания простой игры в JavaScript и HTML5. При программировании на должном уровне абстракции мы можем оградить себя от наиболее сложных частей API, а также быть устойчивыми перед лицом будущих изменений.

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

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

Внутри этого файла мы подключаем скрипт "game.js", который будет описывать весь функционал нашей игры.

JavaScript файл

Внутри JavaScript файла добавьте выборку канваса, а также укажите контекст игры.

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

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



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

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

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

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

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

Видео урок

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

Полезные ссылки из видео:

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

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

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

Вот почему опасно использовать сторонний CSS и JS на своем сайте!

Вот почему опасно использовать сторонний CSS и JS на своем сайте!

Гид по CMS MODX для новичков!

Гид по CMS MODX для новичков!

Как создать свою криптовалюту?

Как создать свою криптовалюту?

Коротко про NodeJS / Обзор, возможности, функции

Коротко про NodeJS / Обзор, возможности, функции

Вы можете создать смартап, чтобы портировать HTML5-игру в продукты SberDevices. Особенность такого смартапа в том, что ему не нужна сценарная логика: достаточно фронтенд-части.

Если вы хотите добавить в игру голосовое управление, тогда создайте обычный Canvas App.


Пример портированной HTML5-игры

Создание HTML5-игры

Шаг 1 — разработка

Для корректного портирования HTML5-игры необходимо настроить:

  • поддержку iOS;
  • сохранение прогресса игры;
  • поддержку пульта.

Поддержка iOS

Чтобы ваша HTML5-игра появилась в мобильном приложении Салют на iOS, добавьте в проект игрового приложения скрипт ниже. Для поддержки на умных устройствах SberDevices и в мобильных приложениях на Android дополнительные настройки не требуются. После этого сохраните проект в формате архива или опубликуйте его с доступом по прямой ссылке.

Сохранение прогресса в игре

Для сохранения прогресса в игре вставьте скрипт:

Поддержка пульта

Чтобы HTML5-игра работала на больших экранах, нужно поддержать работу пульта, т. к. пульт является основным способом управления на этих устройствах. Для этого настройте навигацию пульта.

Шаг 2 — настройка

Для добавления проекта в SmartMarket:

  1. Откройте SmartMarket Studio и нажмите кнопку Создать проект.
  2. Выберите проект HTML5 Game SmartApp, введите название и нажмите кнопку Создать проект.

На вкладке Параметры заполните все поля. Дополнительно заполните следующие поля:


После настройки проекта перейдите в настройки пространства: заполните поля для каталога SmartMarket и верифицируйте свою организацию, если вы ИП или представитель юрлица.

После заполнения всех параметров убедитесь, что HTML5-игра корректно работает на всех устройствах.

Шаг 3 — тестирование

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

Убедитесь, что игра работает корректно. Для этого авторизуйтесь в приложении или на устройстве с помощью Сбер ID, который вы используете в SmartMarket Studio — иначе тестовый смартап не запустится.

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

Шаг 4 — модерация

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

Шаг 5 — публикация

Доступные поверхности

Загруженная HTML5-игра будет доступна в мобильных приложениях Сбер Салют и СберБанк Онлайн, а также на устройствах SberPortal, SberBox и SberBox Top.

Читайте также: