Как привязать браузер к игре
Современная вычислительная техника позволяет создавать классные компьютерные игры! И сейчас, достаточно популярны игры с 3d-графикой, так как, играя в них, ты окунаешься в вымышленный мир и теряешь всякую связь с реальностью. Развитие интернета и браузерных технологий сделало возможным запускать головоломки и стрелялки в любимом Хроме, Мозилле или еще в чем-то там (про Эксплорер помолчим) в онлайн-режиме, без загрузки. Так вот, здесь я расскажу о том, как создать простую трехмерную браузерную игру.
Выбор жанра, сюжета и стилистики игры является достаточно интересной задачей, и от решения этих вопросов может зависеть успех игры. Кроме этого, свои нюансы вносит и выбор технологии, на основе которой будет создаваться продукт. Моя цель – показать элементарные основы этого увлекательного процесса, поэтому я буду делать 3-мерный лабиринт с незамысловатым оформлением. Более того, я это сделаю на чистом коде без использования библиотек и движков, типа three.js (хотя большие проекты лучше делать все-таки на нем), чтобы показать, как можно создать движок для своих нужд. Полностью самописная игра может быть оригинальной, а потому интересной. В общем, оба подхода имеют свои плюсы и минусы.
Я полагаю, если вы читаете эту статью, то вам интересна тема создания игр для гугл Хром, а, значит, понимаете, как работает связка html-css-javaScript, поэтому не буду останавливаться на основах, а сразу приступлю к разработке. В html5 и css3, которые поддерживают все современные браузеры (Эксплорер не в счет), есть возможность расположения блоков в 3-мерном пространстве. Также есть элемент , в котором можно рисовать линии и графические примитивы. Большинство браузерных движков используют , так как на нем можно сделать больше вещей, да и производительность на нем выше. Но для простых вещей вполне можно использовать методы transform-3d, которые будут занимать меньше кода.
1. Инструменты для разработки
Я использую для проверки сайтов и игр только 2 браузера: Chrome и Mozilla. Все остальные браузеры (кроме того самого Эксплорера) построены на движке первого, поэтому использовать их я не вижу смысла, ибо результаты точно такие же, как и в Chrome. Для написания кода достаточно Notepad++.
2. Как реализуется трехмерное пространство в html?
Посмотрим на систему координат блока:
По умолчанию, дочерний блок имеет координаты (left и top) 0 пикселей по x и 0 пикселей по y. Смещение (translate), также 0 пикселей по всем трем осям. Покажем это на примере, для чего создадим новую папку. В нем создадим файлы index.html, style.css и script.js. Откроем index.html и запишем туда следующее:
В файле style.css зададим стили для элементов “container” и “world”.
Сохраним. Откроем index.html c помощью Chrome, получим:
Попробуем применить translate3d к элементу “world”:
Как вы поняли, я перешел в полноэкранный режим. Теперь зададим смещение по оси Z:
transform:translate3d(200px,100px,-1000px);
Если вы снова откроете html-файл в браузере, то никаких изменений вы не увидите. Чтобы увидеть изменения, нужно задать перспективу для объекта “container”:
Квадрат отдалился от нас. Как работает перспектива в html? Взглянем на картинку:
d – расстояние от пользователя до объекта, а z – его координата. Отрицательный z (в html это translateZ) означает, что мы отдалили объект, а положительный – наоборот. Значение perspective определяет величину d. Если же свойство perspective не задано, то значение d принимается за бесконечность, а в этом случае объект визуально не изменяется для пользователя с изменением z. В нашем случае мы задали d = 600px. По умолчанию, точка взгляда перспективы находится в центре элемента, однако ее можно изменить путем задания свойства perspective-origin: .
Теперь повернем “world” вокруг какой-нибудь оси. В сss можно использовать 2 способа вращения. Первый – вращение вокруг осей x,y и z. Для этого используются transform-свойства rotateX(), rotateY() и rotateZ(). Второй – вращение вокруг заданной оси с помощью свойства rotate3d(). Мы будем использовать первый способ, так как он больше подходит для наших задач. Обратите внимание, что оси вращения выходят из центра прямоугольника!
Точка, относительно которой происходят трансформации, может быть изменена путем задания свойства translate-origin: . Итак, зададим вращение “world” по оси x:
Заметно смещение против часовой стрелки. Если же мы добавим rotateY(), то получим смещение уже по оси Y. Важно заметить, что при вращении блока оси вращения также поворачиваются. Вы также можете поэкспериментировать с различными значениями вращения.
Теперь внутри блока “world” создадим еще один блок, для этого добавим тег в html-файл:
В style.css добавим стили к этому блоку:
То есть, элементы внутри блока “world” будут трансформироваться в составе этого блока. Попробуем повернуть “square1” по оси y, добавив к нему стиль вращения:
transform: rotateY(30deg);
«Где вращение?» — спросите вы? На самом деле именно так выглядит проекция блока “square1” на плоскость, образуемую элементом “world”. Но нам нужна не проекция, а настоящее вращение. Чтобы все элементы внутри “world” стали объемными, необходимо применить к нему свойство transform-style:preserve-3d. После подстановки свойства внутрь списка стилей “world” проверим изменения:
3. Создаем движение в трехмерном мире
Для того, чтобы пользователь мог по этому миру передвигаться, нужно задать обработчики нажатия клавиш и перемещения мыши. Управление будет стандартным, какое присутствует в большинстве 3д-шутеров. Клавишами W, S, A, D мы будем перемещаться вперед, назад, влево, вправо, пробелом мы будем прыгать (проще говоря – перемещаться вверх), а мышью мы будем менять направление взгляда. Для этого откроем пока еще пустой файл script.js. Сначала впишем туда такие переменные:
Изначально клавиши не нажаты. Если мы нажмем клавишу, то значение определенной переменной изменится на 1. Если отпустим ее, то она снова станет 0. Реализуем это посредством добавления обработчиков нажатия и отжатия клавиш:
Номер 32 – код пробела. Как видите, тут появилась переменная onGround, указывающая на то, находимся ли мы на земле. Пока разрешим движение вверх, добавив после переменных press… переменную onGround:
Итак, мы добавили алгоритм нажатия и отжатия. Теперь необходимо добавить само передвижение. Что, собственно, мы передвигаем. Представим, что у нас есть объект, который мы двинаем. Назовем его “pawn”. Как и принято у нормальных разработчиков, для него мы создадим отдельный класс “Player”. Классы в javaScript создаются, как ни странно, с помощью функций:
Вставим этот код в script.js в самом начале файла. В конце же файла создадим объект данного типа:
Распишем, что означают эти переменные. x, y, z – это начальные координаты игрока, rx, ry – углы его поворота относительно осей x и y в градусах. Последняя записанная строка означает, что мы создаем объект “pawn” типа “player” (специально пишу тип, а не класс, так как классы в javascript означают несколько другие вещи) с нулевыми начальными координатами. Когда мы двигаем объект, координата мира изменяться не должна, а должна изменяться координата «pawn». Это с точки зрения переменных. А с точки зрения пользователя, игрок находится на одном месте, а вот мир двигается. Таким образом, нужно заставить программу изменять координаты игрока, обрабатывать эти изменения и двигать, в конце концов, мир. На деле это проще, чем кажется.
Итак, после загрузки документа в браузер мы запустим функцию, которая перерисовывает мир. Напишем функцию перерисовки:
В новых браузерах world будет соответствовать элементу с однако надежнее ее присвоить перед функцией update() с помощью следующей конструкции:
Мы будем изменять положение мира каждые 10 мс (100 обновлений в секунду), для чего запустим бесконечный цикл:
Запустим игру. Ура, теперь мы можем двигаться! Однако мир вылазит за пределы рамок элемента «container». Чтобы этого не происходило, зададим css-свойство для него в style.css. Добавим строку overflow:hidden; и посмотрим на изменения. Теперь мир остается в пределах контейнера.
Вполне возможно, что вы не всегда понимаете, куда нужно записывать те или иные строчки кода, поэтому сейчас я вам представлю файлы, которые, как я полагаю, у вас должны получиться:
Если у вас что-то по-другому, обязательно поправьте!
Мы научились двигать персонажа, однако мы еще не умеем поворачивать его! Поворот персонажа, конечно же, будет осуществляться с помощью мыши. Для мыши к переменным состояния клавиш press… мы добавим переменные состояния движения мыши:
А после обработчиков нажатия-отжатия вставим обработчик движения:
В функцию update добавим поворот:
Обратите внимание на то, что движение мыши по оси y вращает pawn по оси x и наоборот. Если мы посмотрим на результат, то ужаснемся от увиденного. Дело в том, что если смещения нет, то MouseX и MouseY остаются прежними, а не приравниваются к нулю. Значит, после каждой итерации update смещения миши должно обнуляться:
Уже лучше, мы избавились от инерции вращения, однако вращение происходит все равно странно! Чтобы понять, что все-таки происходит, добавим div-элемент «pawn» внутрь «container»:
Зададим ему стили в style.css:
Проверим результат. Теперь все ровно! Единственное — синий квадрат остается впереди, но пока оставим это. Чтобы сделать игру от первого лица, а не от третьего, нужно приблизить мир к нам на значение perspective. Сделаем это в script.js в функции update():
Теперь можно делать игру от первого лица. Скроем pawn добавив строку в style.css:
Отлично. Сразу скажу, что ориентироваться в мире с одним квадратом крайне тяжело, поэтому создадим площадку. Добавим в «world» блок «square2»:
А в style.css добавим стили для него:
Теперь все четко. Ну… не совсем. Когда мы нажимаем по клавишам, мы движемся строго по осям X и Z. А мы хотим сделать движение по направлению взгляда. Сделаем следующее: в самом начале файла script.js добавим 2 переменные:
Градус — это pi/180 от радиана. Нам придется применить синусы и косинусы, которые считаются от радиан. Что нужно сделать? Взгляните на рисунок:
Когда наш взгляд направлен под углом и мы хотим пойти вперед, то изменятся обе координаты: X и Z. В случае перемещения в сторону тригонометрические функции просто поменяются местами, а перед образовавшимся синусом изменится знак. Изменим уравнения смещений в update():
Внимательно просмотрите все файлы полностью! Если у вас что-то оказалось не так, то потом обязательно буду ошибки, из-за которых вы сломаете голову!
С движением мы почти разобрались. Но осталось неудобство: курсор мыши может двигаться только в пределах экрана. В трехмерных шутерах можно вращать мышью сколь угодно долго и сколь угодно далеко. Сделаем также: при нажатии на экран игры (на “container”) курсор будет пропадать, и мы сможем вращать мышью без ограничений на размер экрана. Активируем захват мыши при нажатии на экран, для чего перед обработчиками нажатия клавиш поставим обработчик нажатия мыши на “container”:
Теперь совсем другое дело. Однако лучше вообще сделать так, чтобы вращение производилось только тогда, когда курсор захвачен. Введем новую переменную после переменных нажатия клавиш press…
Добавим обработчик изменения состояния захвата курсора (захвачен или нет) перед обработчиком захвата курсора (извините за тавтологию):
А в update() добавим условие вращения “pawn”:
А сам захват мыши при клике по контейнеру разрешим только тогда, когда курсор еще не захвачен:
С движением мы полностью разобрались. Перейдем к генерации мира
4. Загрузка карты
Мир в нашем случае удобнее всего представить в виде множества прямоугольников, имеющих разное местоположение, поворот, размеры и цвет. Вместо цвета также можно использовать текстуры. На самом деле, все современные трехмерные миры в играх – это набор треугольников и прямоугольников, которые называют полигонами. В крутых играх их количество может достигать десятков тысяч в одном только кадре. У нас же их будет около сотни, так как браузер сам по себе имеет невысокую графическую производительность. В предыдущих пунктах мы вставляли блоки “div” внутрь “world”. Но если таких блоков много (сотни), то вставлять каждый из них в контейнер очень утомительно. Да и уровней может быть много. Поэтому пусть эти прямоугольники вставляет javaScript, а не мы. Для него же мы будем создавать специальный массив.
Откроем index.html и удалим из блока “world” все внутренние блоки:
Теперь создадим массив прямоугольников (запихнем его, примеру, между конструктором player и переменными press… в script.js):
Можно было это сделать в виде конструктора, но пока обойдемся чисто массивом, так как запуск цикла расстановки прямоугольников проще реализовать именно через массивы, а не через конструкторы. Я же поясню, что означают цифры в нем. Массив map содержит одномерные массивы из 9 переменных: [. ]. Я думаю, вы понимаете, что первые три числа – это координаты центра прямоугольника, вторые три числа – углы поворота в градусах (относительно того же центра), затем два числа – его размеры и последнее число – фон. Причем фон может быть сплошным цветом, градиентом или фотографией. Последнее очень удобно использовать в качестве текстур.
Массив мы записали, теперь запишем функцию, которая переделает этот массив в собственно прямоугольники:
Поясню, что происходит: мы создаем новую переменную, которая указывает на только что созданный элемент. Ему мы присваиваем id и css-класс (именно это и имеется ввиду под словом класс в языке javaScript), задаем ширину с высотой, фон и трансформацию. Примечательно, что в трансформации помимо координат центра прямоугольника мы указываем смещение на 600 и 400 и половины размеров для того, чтобы центр прямоугольника точно оказался в точке с нужными координатами. Запустим генератор мира перед таймером:
Теперь мы видим площадку с розовыми стенами и серым полом. Как видите, создание карты технически несложно реализовать. А в результате ваш код в трех файлах должен получиться примерно таким:
Если все хорошо, переходим к следующему пункту.
5. Столкновения игрока с объектами мира
Мы создали технику движения, генератор мира из массива. Мы можем передвигаться по миру, который может быть красивым. Однако наш игрок еще никак не взаимодействует с ним. Чтобы это взаимодействие происходило, нам необходимо проверять, сталкивается ли игрок с каким-нибудь прямоугольником или нет? То есть, мы будем проверять наличие коллизий. Для начала вставим пустую функцию:
А вызывать ее будем в update():
Как это происходит? Представим себе, что игрок – это шар с радиусом r. И он движется в сторону прямоугольника:
Очевидно, что если расстояние от шара до плоскости прямоугольника больше r, то коллизии точно не происходит. Чтобы узнать это расстояние, можно перевести координаты игрока в систему координат прямоугольника. Напишем функцию перевода из мировой системы в систему прямоугольника:
И обратную функцию:
Вставим эти функции после функции update(). Я не буду объяснять, как это работает, потому что мне не хочется рассказывать курс аналитической геометрии. Скажу, что есть такие формулы перевода координат при вращении и мы просто ими воспользовались. С точки зрения прямоугольника наш игрок расположен вот так:
В этом случае условие коллизии становится таким: если после смещения шара на величину v (v – это вектор) координата z между –r и r, а координаты x и y лежат в пределах прямоугольника или отстоят от него на величину, не большую r, то объявляется коллизия. В этом случае координата игрока по z после смещения будет составлять r или – r (в зависимости от того, с какой стороны придет игрок). В соответствии с этим, смещение игрока изменяется. Мы специально вызываем коллизию перед тем, как в update() координаты игрока будут обновлены, чтобы вовремя изменить смещение. Таким образом, шар никогда не пересечется с прямоугольником, как бывает в других алгоритмах коллизии. Хотя физически игрок будет представлять собой, скорее, случае куб, мы не будем обращать на это внимание. Итак, реализуем это в javaScript:
x0,y0 и z0 – начальные координаты игрока в системе координат прямоугольника (без поворотов. x1,y1 и z1 – координаты игрока после смещения без учета коллизии. point0, point0, point1 и point2 – начальный радиус-вектор, радиус-вектор после смещения без коллизии и радиус-вектор с коллизией соответственно. map[i][3] и другие, если вы помните, это углы поворота прямоугольника. Заметим, что в условии мы к размерам прямоугольника прибавляем не 100, а 98. Это костыль, зачем, подумайте сами. Запустите игру и вы увидите довольно качественные столкновения.
Как видим, все эти действия происходят в цикле for для всех прямоугольников. При их большом количестве такая операция становится очень дорогой, так как тут и так есть 3 вызова функций преобразований координат, которые тоже производят достаточно много математических операций. Очевидно, что если прямоугольники находятся очень далеко от игрока, то коллизию считать не имеет смысла. Добавим это условие:
Итак, с коллизиями мы разобрались. Мы спокойно можем взбираться и по наклонным поверхностям, а возникновение багов возможно только на медленных системах, если, конечно, возможно. По сути, вся основная техническая часть на этом закончилась. Нам осталось лишь добавить частные вещи, такие как гравитация, вещи, меню, звуки, красивую графику. Но это достаточно легко сделать, а к самому движку, который мы только что сделали, это отношения не имеет. Поэтому об этом я расскажу в следующей части. А сейчас проверьте то, что у вас получилось с моим кодом:
— Я скачал(а) приложение Хроники Хаоса себе на телефон. Как можно привязать мой прогресс в мобильном приложении к моему аккаунту в ВК?
— Привязать мобильную версию к версии игры в ВК нельзя, мобильная и браузерная версии игры никак не синхронизируются. Это разные версии Хроник Хаоса, и их разработкой занимаются разные команды.
— Почему я не могу получить подарок из группы ВК? Я играю на мобильном телефоне.
— Для браузерной и мобильной версий игры существуют две разные группы: Хроники Хаоса и Хроники Хаоса (Android/iOS). В каждой группе есть свои подарки, которые нельзя получить в другой версии игры.
— Я создал(а) новую страницу ВК. Можно как-нибудь перенести игровой прогресс с предыдущего аккаунта на новый?
— К сожалению, нет. Ваш игровой прогресс в Хрониках Хаоса привязан к вашей странице ВКонтакте, его нельзя перенести на другую страницу.
— Я купил(а) Изумруды/Героический набор, но ничего не получил(а) в игре. Что происходит?
— Сообщите об этом в нашу техподдержку через кнопку «Помощь» в игре —информацию обязательно проверят и решат проблему.
— Какой шанс выпадения у Тесака/Супертитанов/Тотема?
— Тесак, Супертитаны и Тотемы — одни из самых редких сущностей в игре. У них крайне небольшой шанс выпадения, и для того чтобы их получить, нужно открыть много Героических сундуков (для Тесака), Сфер Призыва (для Супертитанов) и Сфер Артефактов Титанов (для Тотемов).
— Почему мне не пришла награда за рейтинг на Арене/Гранд Арене?
— Для того чтобы получить награду за рейтинг на Арене/Гранд Арене, вам нужно совершить хотя бы одно нападение за день на Арене до выдачи награды в 20:00 по вашему времени.
— Когда откроется новый сервер?
— Выход сервера зависит от скорости заполнения предыдущего активными игроками. Это всегда происходит по-разному, и поэтому заранее дата открытия нового сервера неизвестна.
— Почему нельзя обменять Бронзовые Трофеи на Серебряные и Золотые?
— Серебряные и Золотые Трофеи Войны Гильдий — ключевой стимул для игроков переходить в Лиги выше. Чем активнее и мощнее ваша Гильдия, тем больше разнообразных наград она будет получать. Наша команда не планирует вводить в игру обмен Бронзовых Трофеев на Серебряные и Золотые, а Серебряных на Золотые.
Если вы разрабатываете игры на HTML и JavaScript, то эта статья для вас. Мы уже много писали о том, что под Windows 8.x можно разрабатывать приложения на HTML/JS, причем, как правило, вы можете с легкостью просто взять и использовать ваш текущий движок, работающий в современных браузерах.
Просто в качестве примера: если вы делаете платформер, то вы можете воспользоваться таким движком, как Phaser (кстати, он поддерживает разработку на TypeScript!), или, нашим Platformer Game StarterKit для Windows 8. К слову, если вы хотите сделать игрушку в жанре Tower Defense, то у нас есть еще один Starter Kit. А если вы хотите создать что-то трехмерное с использованием WebGL, то наше все для вас – это Babylon.js.
GamePad
Но в этой статье я не буду рассказывать, как создать саму игру. Мы зададимся другим вопросом: как подключить к игре для Windows 8.x или в браузере геймпад? Например, игровой контроллер от Xbox 360 или Xbox One:
Будем считать, что вы уже подключили сам геймпад к своему ПК (инструкция для Xbox 360, инструкция для Xbox One). Теперь давайте разберемся, что вам нужно сделать, чтобы добавить его поддержку в своей игре.
В качестве примера я буду использовать платформер RubbaRabbit из приведенного выше стартет-кита. Мы рассмотрим два варианта: игра для Windows 8.x и игра в браузере.
Игра для Windows 8.x на HTML и JavaScript
Чтобы добавить поддержку геймпада в игру на JavaScript под Windows 8.x вам понадобится научиться работать с интерфейсами XInput. Это может звучать страшновато, потому что для этого нужно погрузиться в код на C++, но мы уже сделали практически все, что вам нужно, чтобы не пересекаться с ними напрямую.
Для работы вам нужно скачать пример XInput and JavaScript controller sketch. Внутри него вы легко найдете папочку с кодом на C++, в которой находится проект библиотеки-обвязки над XInput, с которой вы в свою очередь сможете работать в своей игре на JavaScript.
Этот проект вам нужно добавить в свой солюшн с игрой и добавить ссылку на него внутри проекта для Windows 8.x:
При желании вы можете залезть внутрь файлов на C++ и выяснить, что они фактически выставляют наружу очень простой интерфейс доступа к контроллеру: конструктор для получения ссылки на геймпад и функцию getState для получения его текущего состояния с проекцией на кнопки геймпада Xbox.
Теперь нужно добавить поддержку геймпада в самой игре. Для этого, обычно, нужно сделать довольно небольшие изменения в обработке ввода со стороны игрока.
Игровой цикл
Как правило, внутри кода игры у вас есть регулярный цикл, в рамках которого формируется каждый следующий кадр игры. Для того, чтобы понять, как изменилась игровая обстановка, вы в частности проверяете, нажал ли пользователь определенные кнопки.
В моем случае игровой цикл задается внутри функции update:
Где-то внутри этой функции есть обработка нажатий на кнопки, которая выглядит примерно так:
Как вы можете заметить, разработчики движка уже позаботились о том, что пользователь может передавать команды не только с разных кнопок с клавиатуры, но и, например, с виртуальных кнопок на сенсорном устройстве (переменные touchleft, touchright и т.п.).
В целом, скорее всего, в вашем коде должны быть какие-то переменные, отвечающие различным «игровым действиям» и аккумулирующие в себе различные способы ввода для их активации. Именно на работу с такими переменными и будет завязано добавление поддержки геймпада.
Поддержка геймпада
Чтобы добавить поддержку геймпада осталось совсем немного: нужно инициализировать работу с контроллером при старте игрушки и далее регулярно получать его состояние.
Для инициализации контроллера мы создаем объект Controller через конструктор, доступный нам из подключенной ранее библиотеки на C++:
Далее нам нужно с определенной периодичностью обновлять состояние контроллера, для этого опишем функцию updateState, которая будет запрашивать вызов себя на каждый кадр анимации:
Это весь(!) код, который необходимо добавить в игрушку, чтобы она научилась взаимодействовать с геймпадом от Xbox 360. Не забудьте только при старте вызвать саму функцию initXboxpad.
Обратите внимание, что в данном случае мы «эксплуатируем» уже существующие переменные, аккумулирующие в себе команды от возможного сенсорного интерфейса, и обновляем их в зависимости от того, каково текущее состояние элементов управления на геймпаде. Например, если игрок нажал кнопку «A», то соответствующее состояние state.a будет равно true и мы его проецируем на «прыжок» в игре.
Кстати, через функцию setState геймпада вы можете заставить его вибрировать.
Игра в браузере
Теперь давайте посмотрим, что мы можем сделать в браузере. Для браузеров в W3C разрабатывается специальный стандарт Gamepad API, который позволит единообразно работать с разными типами игровых геймпадов.
Стандарт предполагает, что есть некоторая «общая модель», к которой можно свести разные игровые контроллеры:
Если вы хотите привязать обозначения к конкретному типу устройства (например, геймпаду Xbox), вам это нужно будет сделать самостоятельно, прописав в своем коде соответствующее отображение.
В сам стандарт в этой статье погружаться не буду, благо в интернете уже есть достаточное количество обзорных статьей. Например, вот документация от Mozilla. Единственное, что хочу тут отметить – это то, что она устарела относительно предположения, что Gamepad API не поддерживает в Internet Explorer. На самом деле, в свежих сборках Internet Explorer 11 Gamepad API уже поддерживается.
В контексте данной статьи про стандарт нужно знать только одно: он предоставляет доступ к сырым данным, разбитым по осям и нумерованным кнопкам. Чтобы понять реальное соответствие, вам нужно будет проделать определенные умственные операции в своем коде.
Игровой цикл и код игры
Для демонстрации я продолжаю использовать тот же пример из стартер кита, только на этот раз создаю пустой веб-проект и копирую в него оригинальные исходные файлы. Так как они не имеют на самом деле никакой завязки на платформу Windows, то игра просто работает в браузере:
Все остальное пока остается неизменными, и верны те же самые предположения про игровой цикл, которые мы делали для проекта под Windows 8.
Поддержка геймпада
Чтобы упростить себе работу с геймпадом, я воспользуюсь готовым кодом из библиотеки Babylon.js – babylon.gamepads.ts (GitHub). Вы можете просто скопировать библиотеку себе или сделать ее форк.
- умеет поверх Gamepad API симулировать событийную модель (если вам вдруг нужно);
- упрощает доступ к отдельными элементами контроллера (например, объединяет оси джойстика в один объект);
- различает контроллер Xbox, делая необходимое мне отображение обобщенных кнопок на конкретные.
Не забудьте подключить библиотеку на страницу с игрой:
Далее схема подключения геймпада очень похожа на то, что мы делали в случае с Windows 8.x:
Внутрь функции BABYLON.Gamepads передается обработчик события подключения геймпада у компьютеру. Как видите, добавление в проект поддежки геймпада – это примерно 20 строчек кода!
Вариант кода с событийной моделью:
В результате мы легко можем управлять действиями героя в игре прямо с подключенного геймпада:
Иногда возникает необходимость передать данные между работающим в браузере приложением и программой, выполняющейся на той же системе, на которой запущен браузер. Это может понадобиться, например, если нам нужно поработать с оборудованием, подключенным локально. Считывателем смарт-карт, аппаратным ключом шифрования и так далее.
Первыми приходят в голову три способа решить эту задачу:
Первый пункт точно принесёт много боли, поддерживать браузеры придётся отдельно, сделать в плагинах для браузера можно далеко не всё. Всё же, теоретически, поработать со смарт-картами через плагины возможно. Но нужен способ проще.
Второй пункт просто реализовать, но для этой схемы придется делать авторизацию не только на сайте, но и в локальном приложении. Значит понадобится какой-никакой, но интерфейс, при смене пароля потребуется повторная авторизация и в программе. Плюс в корпоративных сетях будут дополнительные проблемы с сетью, у них часто доступ в интернет реализован через прокси-серверы с суровой фильтрацией и авторизацией, для настройки прокси тоже придётся делать интерфейс, не всегда можно отделаться автоматическим определением настроек. Далёкому от IT пользователю будет сложнее с этим работать, создадим больше работы техподдержке. Конечно, можно формировать установочный пакет индивидуально для каждого пользователя, чтобы убрать необходимость первичной авторизации, но это только добавит проблем.
Для работы с браузерами также потребуется указывать в программе правильные заголовки Access-Control-Allow-Origin, Access-Control-Allow-Methods, Access-Control-Allow-Headers (CORS).
IE не будет доверять самоподписанному SSL сертификату, его надо подписать доверенным корневым сертификатом (а он может быть и самоподписанный).
Можно сгенерировать корневой сертификат и SSL сертификат и распространять их с программой, добавляя в локальное хранилище сертификатов. Выглядит небезопасно. И тоже может возникнуть необходимость отозвать или обновить сертификат. Поэтому, сертификаты с ключами будем генерировать прямо на компьютере пользователя при первом запуске программы.
В примере эту работу делает метод RegisterSslOnPort в классе SslHelper.
Для примера создадим endpoint, занимающийся сложением двух чисел. Важно тут установить правильные заголовки CORS, иначе браузер не будет выполнять запрос к нашему API.
Добавим инициализацию Nancy в наше приложение, и мы готовы к бою.
При первом запуске нужно сгенерировать сертификаты и поместить их в хранилище, запросив при этом соответствующие права. Для этих манипуляций служит класс SslHelper, в котором единственный публичный метод CheckOrCreateCertificates делает эту работу. В качестве параметров ему передаются SubjectName сертификатов. Метод проверяет нет ли нужных сертификатов и системе, если нет — создаёт их.
Для симуляции тяжелой работы и долгих задержек в примере добавим Thread.Sleep(1000) в вызовы нашего API.
На этом приложение готово к запуску, перейдём к вебу.
Как понятно из таблицы поведения браузеров, каким-то одним эндпоинтом обойтись не получится, придётся использовать как минимум два:
Работу по сложению чисел поместим в компонент AppComponent. При нажатии кнопки “Calculate”, веб-приложение делает запрос к GET /Calc/Add?num1=&num2=. Ответ или ошибка отображается в поле Result.
Можно запустить веб-приложение локально.
для этого нужно клонировать репозиторий:
в папке AngularWebApp нужно выполнить команды:
Локальное приложение можно либо скомпилировать из примера (открыть CsClientApp.sln из папки CsClientApp) с помощью Visual Studio и запустить, либо использовать скрипт для программы LINQPad.
Важно правильно формировать заголовки CORS в реальном приложении, чтобы злодеи с других сайтов не могли обратиться к нашей программе. Если же у злодея есть возможность работать с привилегиями пользователя на его компьютере и обходить проверку CORS, значит он и так сможет сделать всё, что может делать наша программа.
В любом случае, программа должна работать с минимальными правами, а если делает что-то чувствительное с документами, надо добавить в неё запросы на подтверждение операций.
Несложная на вид задача на деле оказалась довольно объемной, да еще и требующей дополнительных костылей для работы с сертификатами.
Этот подход хорошо себя показал в реальном приложении. Конечно, чтобы использовать код из примера, нужно добавить нормальную обработку ошибок.
Никто на Virustotal на эту программу не реагирует, а хотелось бы! Зато если собрать установочный пакет в InnoSetup, пара третьесортных антивирусов начинает на него срабатывать. Помогает от этого избавиться подписывание установщика с помощью code signing certificate.
Автоматическое обновление программы здесь оставлено за кадром, но оно точно не будет лишним в реальном приложении. Для управления автоматическим обновлением хорошо подходит Squirrel. Еще с помощью squirrel удобно удалить наши сертификаты из системы при удалении программы.
Доброго времени!
Признаться честно, за последние дни меня "засыпали" различными вопросами: спасибо Adobe, Microsoft - скучать не дают никому 😉 (извиняюсь, что многим не ответил - просто это сделать физически невозможно одному человеку).
Так вот, добрые ∼три десятка вопросов были относительно флеш-игр и плеера (который 13 января был заботливо отключен компанией Adobe — и, разумеется, игры и флеш-контент перестали запускаться. ). Ключевой мотив всех вопросов: "Что теперь делать, и как быть. ".
Ниже постараюсь привести несколько способов решения (на момент публикации они все работают, но время "неумолимо" и часть могут "отвалиться").
Нажмите, чтобы включить Adobe плагин // Chrome не позволяет запускать флеш-контент
Способы запуска флеш-игр
👉 Вариант 1
Есть китайский браузер Maxthon (нужна 5-я версия - ссылка на офиц. сайт). Они пока что не отключили флеш-плеер (и вроде бы не собираются это делать).
Когда установите Maxthon — перейдите на страничку с флеш-игрой, и разрешите браузеру установить компонент. См. как выглядит это предложение.
После перезапуска программы — вы сможете играть как ни в чем не бывало. 👇
👉 Вариант 2
Браузер Falcon (ссылка на офиц. сайт) также не собирается отключать флеш-плеер. После его установки - все работает в штатном режиме. 👌
Кстати, браузер отличается минималистическим интерфейсом и достаточно быстро работает даже на относительно слабых машинах.
Falcon-браузер - запуск игры
👉 Вариант 3
На сайте 👉 Internet Archive собрано несколько тысяч флеш-игр (наиболее популярных и интересных), которые можно запустить практически в любом браузере*. (на сайте есть свой встроенный эмулятор, а значит всё будет работать без доп. "плясок". ).
Кстати, частично заменить флеш-контент могут 👉 старые DOS-игры (во многом они похожи: такие же простые, не притязательные, с "легкой" графикой. ).
👉 Кстати!
В сети появилась еще одна интереснейшая коллекция флеш-игрушек от Flash Game Archive. Более подробно о ней здесь!
Internet Archive — флеш игра про гонки
Для справки!
Internet Archive – это американская некоммерческая ассоциация (и веб-портал), представляющая собой "историю" интернета.
*
Кстати, довольно много интересных мини-игр собрано 👉 на сервисе Яндекса. Тут, правда, есть далеко не все "флешки", что есть в сети, но всё-таки коллекция приличная. Возможно, ваша игра тут тоже есть.
👉 Вариант 4
1) Удалить свой текущий флеш-плеер с компьютера полностью.
2) Установить более старую версию Adobe Flash Player. Например, 27-я версия работает и с Chrome, и с Firefox. Найти старые версии можно в сети (если не знаете как и где - ссылка в помощь).
👉 Вариант 5
Установить на ПК "виртуальную ОС Windows XP/7" (например, какой-нибудь "зверский" сборник). Разумеется, важно, чтобы в него был включен Flash Player и браузеры. Благо, в сети этого добра хватает.
Примечание : этот способ хорош тем, что позволяет запускать многие старые приложения (которые не работают в Windows 10). Кроме этого, это гораздо безопаснее — т.к. в случае чего, мы "испортим" только виртуальную машину. (ее всегда можно быстро восстановить).
👉 В помощь!
Как установить и настроить виртуальную машину VirtualBox (пошаговый пример / или как запустить старую Windows в новой ОС).
PS
Риторический вопрос (к Adobe, например).
Они ратуют за безопасность, но явно забывают, что во время резкого отказа от флеш-плеера — многие пользователи ринуться его "восстанавливать" и с высокой долей вероятности немалый процент что-нибудь "подхватят". В этом ли смысл безопасности. Странный подход. 👀
Спасибо! Вариант 3 работает отлично, а мне больше ничего и не нужно
Наконец хоть дельный способ увидел. Спасибо добрый человек
Может я и не добрый
с MX5 не работает.
При первом запуске он спросит "установить компонент flash" - подтверждаете и перезапускаете браузер. Всё работает. (попробуйте Falcon и др. варианты).
Как только это произошло - я сначала вспомнил один коммент на каком-то сайте, мол дату старую поставлю. Ради прикола поставил 5 января и о чудо! Flash заработал! И тут то до меня дошло, что они всего лишь блокировку на дату поставили, а не какую-то блокировку где-то на сервере произвели!
Затем я поискал старую версию Flash и нашёл Flash Player 25 версии, на Firefox работает! Причём на самой новой версии Firefox! При запуске игры в ОК допустим спрашивает "Вы хотите запустить старый плагин?" Нажимаем запустить и всё работает! Затем другие игры уже без вопроса открываются! Я надеюсь, что Firefox не будет удалять возможности запускать старый Flash.
Ведь иначе старая версия браузера рано или поздно может начать плохо поддерживаться сайтами.. А Хром тот же ещё где-то в 2019 году начал ставить палки в колёса при попытке запустить Flash! Mozila Firefox тьфу-тьфу в этом более лояльный!
Кстати, да. С датой срабатывает. Еще один вариант
Читайте также: