Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 12623 сообщений
Cообщения с меткой

html - Самое интересное в блогах

Следующие 30  »
fabkannbrosas82

Без заголовка

Понедельник, 25 Сентября 2017 г. 14:42 (ссылка)

Курсы html и css в Москве - https://vk.com/page-146710847_53180233

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
ckavashomer

Без заголовка

Понедельник, 25 Сентября 2017 г. 14:35 (ссылка)

Html курсы онлайн в Москве - https://vk.com/page-146710847_53177973

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
vicnac490

Без заголовка

Понедельник, 25 Сентября 2017 г. 13:27 (ссылка)

Базовый курс html в Москве - https://vk.com/page-146710847_53178427

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Дайджест свежих материалов из мира фронтенда за последнюю неделю №281 (18 — 24 сентября 2017)

Воскресенье, 25 Сентября 2017 г. 00:31 (ссылка)

https://habrahabr.ru/post/338632/

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Перевод] ECMAScript 6. Регулярные выражения с поддержкой Unicode

Пятница, 22 Сентября 2017 г. 12:57 (ссылка)




ollazarev


сегодня в 12:57

Разработка





ECMAScript 6. Регулярные выражения с поддержкой Unicode







  • Перевод




В ECMAScript 6 представлены два новых флага для регулярных выражений:




  1. y включает режим «липкого» сопоставления.

  2. u включает различные связанные с Unicode опции.



В данной статье объясняется влияние флага u. Эта статья будет Вам полезна, если Вы знакомы с Unicode-проблемами в Javascript.





N.B.! Поскольку при попытке публикации статьи обнаружились проблемы с отображением некоторых используемых в статье Unicode-символов, часть кода была заменена изображениями со ссылками на JSFiddle.



Влияние на синтаксис



Установка флага u в регулярном выражении позволяет использовать escape-последовательности кодовых точек ES6 Unicode (\u{...}) в шаблоне.







При отсутствии флага u такие вещи, как \u{1234}, технически могут по-прежнему возникать в шаблонах, но они не будут интерпретироваться как escape-последовательности кодовых точек Unicode. /\u{1234}/ эквивалентно записи /u{1234}/, которая соответствует 1234 последовательным символам u вместо символа, соответствующего escape-последовательности кодовых точек U+1234.



Движок Javascript делает так из соображений совместимости. Но с установленным флагом u и такие вещи как \a (где a не является escape-последовательностью) больше не будут эквивалентны a. Поэтому, даже если /\a/ обрабатывается как /a/, /\a/u выбрасывает ошибку, т.к. \a не является зарезервированной escape-последовательностью. Это позволяет расширить функционал флага u регулярных выражений в будущей версии ECMAScript. Например, /\p{Script=Greek}/u выбрасывает исключение для ES6, но может стать регулярным выражением, соответствующим всем символам греческого алфавита согласно базе данных Unicode, когда соответствующий синтаксис будет добавлен в спецификацию.



Влияние на оператор ‘.



При отсутствии флага u, . соответствует любому символу BMP (базовая многоязыковая плоскость — Basic Multilingual Plane) за исключением разделителей строки. Когда установлен флаг ES6 u, . соответствует также астральным символам.







Влияние на квантификаторы



В регулярных выражениях Javascript доступны следующие квантификаторы (а также их вариации): *, +, ?, и {2}, {2,}, {2,4}. При отсутствии флага u, если квантификатор следует за астральным символом, он применяется только к низкому суррогату (low surrogate) этого символа.







С флагом ES6 u квантификаторы применяются к символам целиком, что справедливо даже для астральных символов.







Влияние на символьные классы



При отсутствии флага u любой заданный символьный класс может соответствовать только символам BMP. Такие вещи, как [bcd] работают как мы того ожидаем:



const regex = /^[bcd]$/;
console.log(
regex.test('a'), // false
regex.test('b'), // true
regex.test('c'), // true
regex.test('d'), // true
regex.test('e') // false
);


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







Флаг ES6 u позволяет использовать цельные астральные символы в символьных классах.







Следовательно, цельные астральные символы также могут использоваться в диапазонах символьных классов, и все будет работать как мы того ожидаем, пока установлен флаг u.







Флаг u также влияет на исключающие символьные классы. Например, /[^a]/ эквивалентно /[\0-\x60\x62-\uFFFF]/, что соответствует любому символу BMP, кроме a. Но с флагом u /[^a]/u соответствует гораздо большему набору всех символов Unicode, кроме a.







Влияние на escape-последовательности



Флаг u влияет на значение escape-последовательностей \D, \S, и \W. При отсутствии флага u, \D, \S, и \W соответствуют любым символам BMP, которые не соответствуют \d, \s и \w, соответственно.







С флагом u, \D, \S, и \W также соответствуют астральным символам.







Флаг u не обращается к их обратным аналогам \d, \s и \w. Было предложено сделать \d и \w\b) более Unicode-совместимыми, но это предложение было отклонено.



Влияние на флаг i



Когда установлены флаги i и u, все символы неявно приводятся к одному регистру с помощью простого преобразования, предоставляемого стандартом Unicode, непосредственно перед их сопоставлением.



const es5regex = /[a-z]/i;
const es6regex = /[a-z]/iu;
console.log(
es5regex.test('s'), es6regex.test('s'), // true true
es5regex.test('S'), es6regex.test('S'), // true true
// Note: U+017F преобразуется в `S`.
es5regex.test('\u017F'), es6regex.test('\u017F'), // false true
// Note: U+212A преобразуется в `K`.
es5regex.test('\u212A'), es6regex.test('\u212A') // false true
);


Приведение к одному регистру (case-folding) применяется к символам в шаблоне регулярного выражения, а также к символам в сопоставляемой строке.



console.log(
/\u212A/iu.test('K'), // true
/\u212A/iu.test('k'), // true
/\u017F/iu.test('S'), // true
/\u017F/iu.test('s') // true
);


Эта логика приведения к одному регистру применяется и к escape-последовательностям \w и \W, что также влияет на escape-последовательности \b и \B. /\w/iu соответствует [0-9A-Z_a-z], но также и U+017F, поскольку U+017F из сопоставляемой строки регулярного выражения преобразуется (canonicalizes) в S. То же самое касается U+212A и K. Таким образом, /\W/iu эквивалентно /[^0-9a-zA-Z_\u{017F}\u{212A}]/u.



console.log(
/\w/iu.test('\u017F'), // true
/\w/iu.test('\u212A'), // true
/\W/iu.test('\u017F'), // false
/\W/iu.test('\u212A'), // false
/\W/iu.test('s'), // false
/\W/iu.test('S'), // false
/\W/iu.test('K'), // false
/\W/iu.test('k'), // false
/\b/iu.test('\u017F'), // true
/\b/iu.test('\u212A'), // true
/\b/iu.test('s'), // true
/\b/iu.test('S'), // true
/\B/iu.test('\u017F'), // false
/\B/iu.test('\u212A'), // false
/\B/iu.test('s'), // false
/\B/iu.test('S'), // false
/\B/iu.test('K'), // false
/\B/iu.test('k') // false
);


Влияние на HTML-документы



Верьте или нет, но флаг u также влияет и на документы HTML.



Атрибут pattern для элементов input и textarea позволяет вам указать регулярное выражение для проверки ввода пользователя. Затем браузер обеспечивает вас стилями и скриптами для создания поведения, основанного на достоверности ввода.







Флаг u всегда включен для регулярных выражений, скомпилированных через HTML атрибут pattern. Вот демонстрационный пример.



Поддержка



На данный момент флаг ES6 u для регулярных выражений доступен в стабильных версиях всех основных браузеров, кроме Safari. Браузеры постепенно начинают использовать этот функционал для HTML атрибута pattern.


































Browser(s) JavaScript engine u flag u flag for pattern attribute
Edge Chakra issue #1102227 + issue #517 + issue #1181 issue #7113940
Firefox Spidermonkey bug #1135377 + bug #1281739 bug #1227906
Chrome/Opera V8 V8 issue #2952 + issue #5080 issue #535441
WebKit JavaScriptCore bug #154842 + bug #151597 + bug #158505 bug #151598


Рекомендации для разработчиков




  • С этого момента используйте флаг u для каждого регулярного выражения, которое вы пишете.

  • … но не добавляйте флаг u слепо в существующие регулярные выражения, поскольку это может неявным образом изменить их смысл.

  • Избегайте комбинирования флагов u и i. Лучше явно включать в регулярное выражение символы всех регистров, чем страдать от неявного программного приведения символов к одному регистру.

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





Преобразование (transpiling) Unicode ES6 регулярных выражений в ES5



Мной создан regexpu, транспилер, который преобразовывает регулярные выражения Unicode ES6 в эквивалентный код ES5, который работает уже сегодня. Это позволит вам играться с новым, развивающимся функционалом.







Полномасштабные транспилеры ES6/ES7, такие как Traceur и Babel, зависят от regexpu при транспиляции u. Дайте мне знать, если вам удастся это сломать.


Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/338366/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

It's a (focus) Trap

Вторник, 19 Сентября 2017 г. 15:33 (ссылка)

https://habrahabr.ru/post/338130/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Концепция развития платформы: ожидания 2013 года и реальность 2017-го

Вторник, 19 Сентября 2017 г. 11:17 (ссылка)




sapozhkov


сегодня в 11:17

Разработка





Концепция развития платформы: ожидания 2013 года и реальность 2017-го














    Четыре года назад я выступал на осенней конференции Tabtabus с рассказом о том, как мы в WebCanape разрабатываем и выпускаем сайты. В процессе выступления я сделал несколько прогнозов на 4 года вперед. Срок прошел, и настало время проанализировать, насколько они были верны и как все поменялось за это время.



    Сначала проведу небольшой сравнительный анализ предметной области (2013 vs 2017), затем расскажу об основных направлениях в работе и наших методах реализации.



    Если кому интересно, добро пожаловать под кат.






    Пять лет назад нам хотелось доказать, что даже небольшая группа энтузиастов может создать действительно классную программную платформу для создания сайтов, не хуже «1С-Битрикс» с его миллионными инвестициями.



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



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



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



    Работу студии можно разделить на несколько направлений


    1. Продажа и производство сайта

    2. Продвижение и реклама сайтов — генерация клиентов (абонентские платы и разовые услуги)

    3. Инструменты для работы — CRM (абонентка)





    Ожидание №1. Основную прибыль будет приносить не разработка сайтов, а их продвижение



    Реальность. Прогноз оправдался.



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



    Каким должен быть процесс разработки сайта, чтобы клиент был довольным и заинтересованным в дальнейшей работе именно с нами?


    • Быстрым — максимально быстро создать и запустить в работу сайт

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

    • Надежным — полученный в результате разработки проект должен работать без ошибок и отказов

    • Гибким — сайт можно дорабатывать по желанию клиента, вносить изменения, которые позволят лучше выполнять задачи бизнеса.



    Отсюда требования к работе команды Canape CMS и к продукту.


    • Платформа Canape CMS и все процессы разработки должны быть стандартизированы и описаны в регламентах разработчиков;

    • Наличие инструментов для удобной и быстрой доработки индивидуальных функциональных модулей;

    • Регулярный сбор требований от пользователей для формирования пула доработок;

    • Ведение актуальная документация по продукту: 1) для пользователей, 2) для разработчиков.

    • Автоматическое тестирование типовых проблем и функций;

    • Доработка инструментов для упрощения разработки.



    Примерно таким же подход был и в 2013. Радикальных изменений делать не пришлось и сегодня, несмотря на то, что рынок сильно поменялся.



    Ожидание №2. Через 4 года будет выпущено более 5000 сайтов



    Реальность. На текущий момент сдано более 2350 сайтов.



    Клиентам больше не нужен сайт за 12 000 рублей со стандартным функционалом. За такую же стоимость клиент хочет продукт с множеством уникальных доработок под конкретный бизнес.



    Ожидание №3. Будем выпускать типовые сайты с минимальными доработками



    Реальность. Многие клиенты хотят серьезных индивидуальных доработок, а количество запросов на типовые решения сокращается. Если раньше большинство продаваемых нами сайтов были без глобальных доработок и собирались на конвейере по 30 штук за месяц, то теперь таких клиентов единицы — большинство хотят серьезные проекты с уникальным функционалом.



    Почему клиентов для типовых решений стало меньше?



    Возможно, из-за финансового кризиса. Возможно, из-за серьезного развития конструкторов сайтов.



    5-6 лет назад бесплатные конструкторы на выходе давали достаточно топорный сайт. Элементы были расклеены, как стикеры, на четко определенные места. Чтобы настроить SEO-продвижение такого сайта, необходимо было долго разбираться в этом вопросе.



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



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



    Ожидание №4. Выпустим свой конструктор сайтов, чтобы компенсировать недостаток типовых проектов и займем эту нишу



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



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




    • Единый центр управления для сайтов

    • Горизонтальное масштабирование — ввод в строй новых серверов должен быть максимально простым

    • Регулярные обновления — быстрый и удобный инструмент накатывание изменений на сервера / площадки

    • Ускорение и упрощение процесса разработки конечных сайтов — площадки для новых проектов должны создаваться быстро



    Как мы решаем эти задачи

    Для работы с большим количеством однотипных площадок был разработан собственный продукт: SMS — Site management system (по аналогии с CMS — Content management system).



    Это система управления площадками. Из функциональности на борту:


    • создание базовых конфигураций сайтов с набором предустановленных функциональных модулей;

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

    • резервное копирование — как по cron, так и в ручном режиме;

    • архивирование — перемещение в архив площадок временно не используемых или устаревших, с возможностью их быстрого восстановления;

    • импорт/экспорт — сохранение файлов и данных с метаинформацией в архив, для их дальнейшей публикации на сторонних хостингах или для перемещения на другой сервер Canape SMS;

    • привязка доменов к площадкам;

    • формирование очередей задач, выполняемых по cron, для выравнивания нагрузки на ресурсы сервера;

    • мониторинг состояния сервера;

    • и многое другое.



    Система активно используется:


    • для размещения сайтов — как хостинг для разработанных на Canape CMS проектов;

    • для разработки — мы создаем сайты в аналогичной инфраструктуре с небольшим дополнительным функционалом для разработчиков;

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



    Пример — сайты органов государственной власти, сформированные на Canape SMS, находятся в одном кластере: admin-smolensk.ru, korso.admin-smolensk.ru, antinark.admin-smolensk.ru, antiterror.admin-smolensk.ru и другие. Все площадки имеют типовую структуру, сгенерированную заказчиком, вынесены на собственные домены и имеют отдельные системы управления содержимым.





    Ожидание №5. Будет много заказов на «мультисайтовые» системы с единым центром управления



    Реальность. У малого и среднего бизнеса таких потребностей почти нет. Ключевые задачи нашей целевой аудитории решаются системой из 2-4 связанных сайтов, где применение такого подхода нецелесообразно.



    «Кластерные» и «отцепленные» площадки



    Это внутренние термины. «Кластерной» мы называем площадку (сайт), созданную через SMS и не имеющую собственных файлов ядра CMS. Все файлы ядра лежат в специальной директории, которой заведует SMS. Для каждой версии сборки есть свой набор файлов.



    Соответственно, «отцепленными» от кластера площадками мы называем обычные сайты, содержащие в рабочей директории полный комплект файлов для функционирования.



    Что дает эта концепция работы?


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

    • Ускорение работы — одни файлы делают работу для многих сайтов.

    • Возможность обновления менеджером — если площадка кластерная, то доработок на ней гарантированно нет, и можно провести автоматическое обновление. Участие программиста не требуется.

    • Возможность быстро накатить «баг фигсы» на часть площадок



    Доработка уникального функционала проектов



    Если проект не может быть собран на типовом функционале и его надо дорабатывать, то он «отцепляется» от кластера. Для этого есть специальный инструмент в SMS, и впоследствии сайт спокойно дорабатывается независимо от общего программного ядра.



    Вот как это происходит с технической точки зрения.



    Основная сборка разрабатывается с использованием системы контроля версий Git. При этом для каждого релиза создается отдельный тэг.


    • SMS создает Fork (копию проекта) от основного репозитория.

    • Разворачивает его в отдельной директории.

    • Создает индивидуальную ветку доработок в том месте, где стоит метка текущей версии проекта.

    • Разворачивает эту ветку.

    • Поверх копируются файлы площадки.



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



    Fork позволяет решить:


    • вопрос с Pull Request (запросами на добавление нового реализованного функционала в основной репозиторий);

    • вопрос с точечными заборами коммитов (изменений) из доработанного проекта в сборку.



    Ожидание №6. Система должна быть понятна для клиентов, администраторов и разработчиков



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



    Разработчики могут быстро (в зависимости от сложности задачи и собственного опыта) дорабатывать конкретные решения.



    SEO-специалисты регулярно транслируют информацию о том, что Canape CMS — очень удобная и прогрессивная платформа с точки зрения поискового продвижения. Понятно, что лучшая – та CMS, которую знаешь ты. Но наш отдел продвижения работает почти со всеми популярными на рынке системами. И такая оценка с их стороны является показателем хороших результатов работы нашей команды и неплохой мотивацией для дальнейшего развития платформы Canape CMS.



    Итоги



    Это слайд с моего доклада 2013 года.





    Четыре года назад мы прогнозировали выпуск более 5 000 сайтов к 2017 году. По факту сегодня создано 2350+ сайтов. Изначально мы ориентировались на несложные сайты с типовым дизайном, то по факту сейчас разрабатываем достаточно объемные проекты с интеграциями, адаптивным дизайном и уникальными программными модулями.



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

    В завершении статьи



    Есть набор вопросов, которые часто задают, поэтому сразу отвечу на некоторые из них





    Почему создали свою CSM, а не использовали другую?

    — Canape CMS — система полного цикла для быстрого производства сайта студией. Не одиноким фрилансером, не собственными силами клиента, не системным администратором компании, а именно студией, где все процессы регламентированы и стандартизированы. Сайт с индивидуальным функционалом и дизайном разрабатывается не за год или полгода, а за 2-3 недели.



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



    Почему не взяли бесплатное решение?

    — Потому что оно не соответствует первому пункту.



    Почему не взяли приличное платное решение?

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



    Почему не облачное решение по подписке для конечного клиента, а CMS с исходным кодом?

    — Потому что ваш сайта — это ваша собственность и ресурс.



    Другие материалы по теме:





    Original source: habrahabr.ru (comments, light).

    https://habrahabr.ru/post/338184/

    Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
    rss_rss_hh_new

    Постъядерный караван в 35 килобайт

    Понедельник, 18 Сентября 2017 г. 20:15 (ссылка)




    Zoolander


    сегодня в 20:15

    Разработка





    Постъядерный караван в 35 килобайт










      35 килобайт минифицированного кода на обычном JavaScript, семь городов, пустоши, радиоактивные гекконы, съедобные кактусы, встречные караваны и бандиты. Что это? Это небольшая игра, которая запускается в браузере. Ее принципы довольно просты для повторения и в самой примитивной версии ее можно воссоздать, наверное, на любом устройстве, если там есть устройство вывода и генератор случайных чисел. Но сегодня я хочу рассказать, как я реализовал ее для современных браузеров.



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



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







      Возможности игры



      Ваши следопыты могут найти съедобный кактус или довоенные консервы. В пустыне можно найти трупы других путешественников, с которых можно поднять немного денег. У встречных караванов можно купить еды или браминов, а также нанять людей. А еще к вам могут присоединиться встречные бродяги, а иногда — даже бандиты, если вы поразите их своей харизмой. Шутка. На самом деле харизмы в игре пока нет, она эмулируется рандомом.



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



      Функционал можно легко расширить, харизму и другие настоящие ролевые факторы добавить самим. Даже если вы не хотите программировать — можно просто открыть файлы с набором событий в Notepad и добавить новые события, изменить баланс или даже полностью переписать мир и лор, превратив путешествие по постъядерной пустыне в приключения караванщика Лютика в стране эльфов. Или в странствия космического корабля между разными звездными системами (правда, придется выбросить съедобные кактусы, попадающиеся по дороге).



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



      Основная идея и логика программы



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


      1. Движение к заданной точке

      2. Отсчет дней

      3. Потребление еды

      4. Проверка на вероятность для события, которое нас ждет в пустоши



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



      Как это происходит? Очень просто — каждое событие просто меняет числовые параметры каравана или мира, а затем сообщает об этом в лог. И вот тут возникает магия — параметры могут быть одними и теми же, но сообщать можно о совершенно разных причинах. Минус несколько единиц еды? Это могут быть нападения крыс, выпадение радиоактивных осадков или голодных бродяг. Плюс несколько единиц еды? Значит, ваши люди нашли съедобный кактус, раскопали в придорожных руинах довоенные консервы или нашли на дороге замечательные кожаные сапоги с мягкой подошвой.



      Первая версия, с которой я начал экспериментировать, выглядела чистой иллюстрацией описанного алгоритма:







      Я сделал этот прототип как ремейк игры про орегонский караван из этого туториала.



      Одномерный прототип — караван для js13kGames



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







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



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



      Список изменений

      1. Многоразовое путешествие — игра не прекращается с достижением цели

      2. Двухмерная карта мира и города

      3. Другой сеттинг мира и никакой дизентерии

      4. Бандиты могут вступать в переговоры и наниматься

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

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







      Движок каравана и архитектура



      Игра, как уже было сказано, сделана на чистом JavaScript без использования сторонних библиотек (вы можете сами добавить их, если сочтете нужным). Для отображения карты мира и интерфейса используется обычный HTML и CSS. Чтобы изменять их, используются базовые операции с DOM и классическая операция document.getElementById



      Пример отображения количества игроков в караване
      this.view = {}; // объект для хранения элементов DOM
      this.view.crew = document.getElementById('game-stat-crew'); // находим элемент при запуске игры
      // ...
      this.view.crew.innerHTML = world.crew; // записываем число людей в караване как обычный html






      WorldState — модель мира



      Мир в игре — это класс WorldState. Он хранит в себе все важные параметры и не содержит никакой логики. Логику мы привяжем потом, за счет плагинов.



      function WorldState(stats) {
      this.day = 0; // текущий день, с десятичными долям
      this.crew = stats.crew; // количество людей
      this.oxen = stats.oxen; // количество быков
      this.food = stats.food; // запасы еды
      this.firepower = stats.firepower; // единиц оружия
      this.cargo = stats.cargo; // товаров для торговли
      this.money = stats.money; //деньги

      // лог событий, содержит день, описание и характеристику
      // { day: 1, message: "Хорошо покушали", goodness: Goodness.positive}
      this.log = [];

      // координаты каравана, пункта отправления и назначения
      this.caravan = { x: 0, y: 0};
      this.from = {x: 0, y: 0};
      this.to = {x: 0, y: 0};

      this.distance = 0; // сколько всего пройдено

      this.gameover = false; // gameover
      this.stop = false; // маркер для обозначения того, что караван стоит
      this.uiLock = false; // маркер для блокировки интерфейса
      }




      Game — создание мира и игровой цикл



      Игровой цикл запускается и управляется объектом Game. Этот же объект создает мир. Обратите внимание на поле plugins — по умолчанию это пустой массив. Game ничего не знает о плагинах, кроме двух вещей — у них должна быть функция инициализации init(world) и функция обновления update.



      Game = {
      plugins: [], // генераторы событий,
      };

      Game.init = function () {
      // создаем мир по стартовому состоянию которое хранится в отдельном файле
      // в объекте StartWorldState в директории data
      this.world = new WorldState(StartWorldState);

      var i;
      for (i = 0; i < this.plugins.length; i++) {
      this.plugins[i].init(this.world);
      }
      };

      // добавление плагинов
      Game.addPlugin = function (plugin) {
      this.plugins.push(plugin);
      };

      // игровой цикл
      Game.update = function () {
      if (this.world.gameover) return; // никаких действий
      var i;
      for (i = 0; i < this.plugins.length; i++) {
      this.plugins[i].update();
      }
      };

      Game.resume = function () {
      this.interval = setInterval(this.update.bind(this), GameConstants.STEP_IN_MS);
      };

      Game.stop = function () {
      clearInterval(this.interval);
      };

      Game.restart = function () {
      this.init();
      this.resume();
      };




      Для запуска новой игры надо вызвать функцию Game.restart. Но прежде чем это произойдет, надо добавить какой-нибудь плагин — иначе ничего не будет происходить, у нас просто будет вхолостую работать игровой цикл.



      Ешь, живи, двигайся — CorePlugin



      Самые базовые действия каравана — перемещение, отсчет времени и потребление пищи — реализованы в объекте CorePlugin:



      исходный код CorePlugin
      CorePlugin = {};

      CorePlugin.init = function (world) {
      this.world = world; // запоминаем world
      this.time = 0; // общее время с начала игры, в миллисекундах
      this.dayDelta = GameConstants.STEP_IN_MS / GameConstants.DAY_IN_MS; // сколько дней в одном шаге игру
      this.lastDay = -1; // отслеживаем наступление нового дня
      this.speedDelta = Caravan.FULL_SPEED - Caravan.SLOW_SPEED; // разница между полной и минимальной скоростью
      };

      CorePlugin.update = function () {
      if (this.world.stop) return; // если стоим - никаких изменений
      this.time += GameConstants.STEP_IN_MS; // увеличение времени
      this.world.day = Math.ceil(this.time / GameConstants.DAY_IN_MS); // текущий день, целый

      // Движение каравана в зависимости от того, сколько дней прошло
      this.updateDistance(this.dayDelta, this.world);

      // события связанные с наступлением нового дня
      if (this.lastDay < this.world.day) {
      this.consumeFood(this.world);
      this.lastDay = this.world.day;
      }
      };

      // еда выдается один раз в день
      CorePlugin.consumeFood = function (world) {
      world.food -= world.crew * Caravan.FOOD_PER_PERSON;
      if (world.food < 0) {
      world.food = 0;
      }
      };

      // обновить пройденный путь в зависимости от потраченного времени в днях
      CorePlugin.updateDistance = function (dayDelta, world) {
      var maxWeight = getCaravanMaxWeight(world);
      var weight = getCaravanWeight(world);

      // при перевесе - Caravan.SLOW_SPEED
      // при 0 весе - Caravan.FULL_SPEED
      var speed = Caravan.SLOW_SPEED + (this.speedDelta) * Math.max(0, 1 - weight/maxWeight);

      // расстояние, которое может пройти караван при такой скорости
      var distanceDelta = speed * dayDelta;

      // вычисляем расстояние до цели
      var dx = world.to.x - world.caravan.x;
      var dy = world.to.y - world.caravan.y;

      // если мы находимся около цели - останавливаемся
      if(areNearPoints(world.caravan, world.to, Caravan.TOUCH_DISTANCE)){
      world.stop = true;
      return;
      }

      // до цели еще далеко - рассчитываем угол перемещения
      // и получаем смещение по координатам
      var angle = Math.atan2(dy, dx);
      world.caravan.x += Math.cos(angle) * distanceDelta;
      world.caravan.y += Math.sin(angle) * distanceDelta;
      world.distance += distanceDelta;
      };

      // регистрируем плагин в игре
      Game.addPlugin(CorePlugin);






      Тут все элементарно. Сначала при запуске игры у нас вызывается init, который позволит сохранить ссылку на модель мира. Затем в игровом цикле у нас будет вызываться update, который будет менять мир к лучшему, как любят говорить персонажи из сериала «Силиконовая долина». Шутка — меняться мир будет во все стороны.



      Наш базовый плагин отсчитывает время в миллисекундах, переводит их в дни, а затем обновляет дистанцию и запасы еды. В принципе, объект плагина просто должен содержать функции init(world) и update(), а делать он может что угодно. Можно даже просто вызывать какую-нибудь другую игру на HTML5 или создавать диалоговое окно.



      Чтобы подключить плагин, надо добавить его код между определением объекта Game и первым вызовом Game.restart(). Примерно так, как это сделано сейчас в index.html:














      Итак, как сделать игру про караван



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



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



      Существующие плагины можно отключать (убирая их исходный код из index.html или закомментировав строку с Game.addPlugin(SomePlugin) в конце их кода). Они ничего не знают друг о друге и просто меняют модель мира или интерфейс игры.



      Ну и последний вариант, для писателей — просто открывать файлы в директории data и редактировать описания событий и константы. Хотя это те же JavaScript-исходники, они довольны просты для изменений. Особенно тексты. Чтобы доказать это, я вкратце расскажу, как устроены другие плагины в текущей версии.



      Случайные события



      Все примитивные случайные события лежат в файле data/RandomEvents.js в переменной RandomEvents в таком формате:



      var RandomEvents = [
      {
      goodness: Goodness.negative,
      stat: 'crew',
      value: -4,
      text: 'На караван напал смертокогть! Людей: -$1'
      },
      {
      goodness: Goodness.negative,
      stat: 'food',
      value: -10,
      text: 'Кротокрысы на привале сожрали часть еды. Пропало пищи: -$1'
      },
      {
      goodness: Goodness.positive,
      stat: 'money',
      value: 15,
      text: 'У дороги найден мертвый путешественник. На теле найдены монеты. Денег: +$1'
      },
      {
      goodness: Goodness.positive,
      stat: 'crew',
      value: 2,
      text: 'Вы встретили одиноких путников, которые с радостью хотят присоединиться к вам. Людей: +$1'
      },




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



      Первое поле — goodness- означает позитивную, негативную и нейтральную окраску сообщения в логе. Второе поле — stat — содержит название параметра WorldState, который должен меняться. Value — это среднее значение для изменения этого параметра. Последнее поле — должно содержать любой произвольный текст, описывающий произошедшее. Вместо символом $1 в текст будет подставлено реальное изменение параметра, которое выпадет в игре.



      Случайные события проверяются на выпадение в объекте RandomEventPlugin и радуют взгляд игрока в логе:







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



      Как написать или отредактировать диалог



      За диалоговую систему отвечает объект DialogWindow. Если вы заглянете в его исходный код, то увидите мутанта, который находит в HTML-коде нужный div-элемент и привязывает к нему общий обработчик кликов мышкой. Идея заключается в том, что когда мы просим этот объект показать нам новый диалог, мы передаем ему массив наших диалогов. И обработчик нажатия на конкретный выбор описывается в конкретном диалоге в таком формате:



      var DeathDialogs = {
      "start": {
      icon: "images/pic_death.jpg", // ссылка на url картинки
      title: "Погибший в пустоши", // заголовок диалога
      desc: "", // статический текст диалога
      desc_action: function (world, rule) { // функция для создания вычисляемого текста диалога
      var desc = " Причина смерти: "+rule.text+". Вы сумели пройти "+Math.floor(world.distance) + " миль и накопить "+Math.floor(world.money) + " денег";
      desc += "Может быть, следующим караванщикам повезет больше?"
      return desc;
      },
      choices:[ // массив выборов
      {
      text: 'Начать новую игру', // текст на кнопке
      action: function () { return "stop"; } // функция, возвращающая тег следующего диалога
      }
      ]
      },
      };




      В диалогах смерти только один вариант, описанный как поле «start». Но таких вариантов может быть бесконечно много. К примеру, в диалогах бандитов я реализовал 12 развилок. Как происходит переход между ними? Наш универсальный объект DialogWindow при вызове функции show сохраняет у себя список переданных диалогов и показывает тот, который определен в поле «start».



      При отображении очередного диалога его массив choices отображается как набор кнопок, в атрибуты которых записывается номер выбора. А все функции action из choices записываются во внутренний массив dialogActions. При клике мышкой на кнопке выбора универсальный обработчик определяет номер функции в dialogActions и вызывает ее, попутно передавая два аргумента, которые мы решили использовать в этом диалоге. Таким образом, в диалогах с бандитами функция action в конкретном choice может принимать состояние мира (world) и описание текущих бандитов (bandits). А в диалогах к другим плагинам — другие параметры. Да можно и вообще без них, особенно, если смысл выбора — просто закончить диалог, как при геймувере.







      Чтобы диалог закончился и игрок вернулся к карте мира, надо, чтобы функция action в объекте choice возвращала один из зарезервированных тегов «finish»,«exit»,«stop». Вообще смысл этой функции в том, чтобы возвращать имя следующей развилки. Но до этого заветного return-a можно и порой нужно вставить любую логику, любые вычисления, которые позволят выбрать следующую развилку — «run», «fight» или, быть может, даже «love».



      Как вызвать диалог из плагина



      В любой момент времени в update любого работающего плагина можно вызвать диалог следующим образом:



          // ... где-то в недрах update у объекта-плагина
      // останавливаем караван, аналог паузы
      world.stop = true;
      // просим показать диалог с набором развилок из DeathDialogs
      // в развилки будут передаваться аргументы world и rule
      DialogWindow.show(DeathDialogs, world, rule, this);




      Также в плагине должна быть реализована функция onDialogClose — этот коллбэк будет вызываться после закрытия диалога. Пример из плагина, определяющего наступление смерти:

      DeathCheck.onDialogClose = function () {
      Game.restart();
      };




      Краткое описание существующих плагинов



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



      Map2DPlugin — перемещение каравана по карте. Поиск городов, которые задаются в index.html как обычные div с параметрами top и left. Здесь же определяется прибытие в город и происходит автоматическая торговля.



      ShopPlugin — генерация случайных встречных караванов или других торговцев. Позволяет купить еду, браминов и нанять наёмников. Или ничего не покупать и пойти дальше.



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



      DropPlugin — плагин перегруза. В прототипе из туториала про орегонский караван игра сама автоматически сбрасывала вещи — сначала оружие, а потом еду. Это было не очень комфортно и вызывало недоумение — как так-то? Ведь с оружием можно добыть еду, а «жареным мясом нельзя убить врага» (с) один известный стрим по Fallout 4. Так что я решил сделать диалог, в котором ты просто выбираешь, от чего избавиться.



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



      WorldViewPlugin — интерфейсный плагин. Он просто обновляет интерфейс, показывая текущие параметры мира. Возможно, эта идея покажется кому-то странной — самостоятельный объект интерфейса, который отслеживает в цикле обновления изменения переменных. Но зато благодаря этой странной идее мы избавились от многочисленных updateUi и получили независимость между блоками разной логики.



      Небольшие советы по текущей игре и балансу



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



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



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



      Ссылки и дистрибутивы



      Я использовал графику с лицензией Creative Common 0 с ресурсов pixabay.org и opengameart.org, так что и графика, и код распространяется на этих условиях — свободное копирование и использование, без каких-либо обязательств.



      Исходный код можно взять с GitHub или скачать zip-архивом отсюда. Первый вариант предпочтительнее, так как чаще обновляется.



      Для тестирования даже на локальном компьютере достаточно открыть index.html в браузере — там не используются функции, которым обязательно требуется сервер.



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


      Original source: habrahabr.ru (comments, light).

      https://habrahabr.ru/post/336724/

      Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
      vprum

      КОДЫ ДЛЯ ОФОРМЛЕНИЯ БЛОГА

      Понедельник, 18 Сентября 2017 г. 05:44 (ссылка)

      Это цитата сообщения Бахыт_АБМ Оригинальное сообщение

      Окошко для кода -
      Рамочка вокруг текста -
      Рамочка вокруг текста (разрыв слева) -
      Рамочка вокруг текста (разрыв справа) -
      Картинки в записи:
      Картинка слева от текста -
      Картинка справа от текста -
      Картинки по бокам текста -
      Картинки в ряд:
      2 картинки -
      3 картинки -
      4 картинки -
      5 картинок -
      6 картинок -
      Кнопки в записи:
      Текст на кнопке -
      Картинка на кнопке -
      Текст и картинка на кнопке -
      Кнопка на фоне -
      Номера страниц в блоге -
      Рамка с картинками по углам -
      Таблица -
      Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
      rss_rss_hh_new

      Дайджест свежих материалов из мира фронтенда за последнюю неделю №280 (11 — 17 сентября 2017)

      Воскресенье, 17 Сентября 2017 г. 22:56 (ссылка)

      https://habrahabr.ru/post/338122/

      Комментарии (0)КомментироватьВ цитатник или сообщество
      rss_rss_hh_new

      Пишем «Тир» на JavaScript для рекламы на сайте

      Суббота, 16 Сентября 2017 г. 17:56 (ссылка)




      Skaner


      сегодня в 17:56

      Разработка





      Пишем «Тир» на JavaScript для рекламы на сайте






      • Tutorial




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

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

      image





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


      1. Пользователь заходит на сайт

      2. Видит игру (тут надо его как-то заинтересовать)

      3. Играет (набирает очки)

      4. [если проиграл] Видит рекламу

      5. [если выиграл] Видит рекламу только в другом контексте





      В этой части статьи рассмотрим пункт номер 3 и опишем саму игру, используя язык программирования JavaScript.



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



      Я посмотрел на три кандидата:

      Phaser (навес на Pixi)

      Pixi (отсылка к Phaser из-за рендера, но более низкоуровневый)

      PointJS (от наших)



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

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



      Выглядит эта штука вот так:

      image



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

      Настройки проекта
      image





      Немного о файлах:

      init.js — файл с объявлениями всех глобальных переменных

      game.js — игровой цикла Game

      menu.js — игровой цикл Menu



      init.js — Приготовления



      В данном файле, как упоминал ранее — объявление переменных глобальных.

      // объявляем движок
      var pjs = new PointJS(640, 480, {
      backgroundColor : 'white' // optional
      });

      // растягиваем игру на всю страницу
      pjs.system.initFullPage(); // for Full Page mode

      // системные функции для сокращения
      var log = pjs.system.log; // log = console.log;
      var game = pjs.game; // Game Manager
      var point = pjs.vector.point; // Constructor for Point
      var camera = pjs.camera; // Camera Manager
      var brush = pjs.brush; // Brush, used for simple drawing
      var OOP = pjs.OOP; // Objects manager
      var math = pjs.math; // More Math-methods
      var levels = pjs.levels; // Levels manager

      // включим мышь
      var mouse = pjs.mouseControl.initControl();

      // получим новые ширину и высоту экрана
      var width = game.getWH().w; // width of scene viewport
      var height = game.getWH().h; // height of scene viewport

      // заголовок
      pjs.system.setTitle('Tir'); // Set Title for Tab or Window

      // отключим показ кусора (заменим своим)
      mouse.setVisible(false);

      // переменная для счета
      var score = 0;

      // при изменении размера перезагрузим игру
      window.onresize = function () {
      location.reload();
      };

      // этой функцией будем прогонять зависимые от высоты экрана значения
      var i = function (num) {
      return num * (height/260);
      };




      menu.js — Работаем с меню



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

      Сам файл (с комментариями)

      // Объявляем игровой цикл
      game.newLoopFromConstructor('Menu', function () {

      // Для меню мне требуется создать красивый фон в стиле DNS
      var bg = game.newImageObject({
      x : 0, y : 0, // позиция
      file : 'dns_logo.jpeg', // файл фона
      w : width, // ширину установим, высота подгонится сама
      alpha : 0.8 // немного блеклый
      });

      this.update = function () {

      // запомним на всякий случай позицию курсора
      var mp = mouse.getPosition();

      // при наведении мыши сделаем ярче
      if (mp.x > 10 && mp.x < width - 10 && mp.y > 10 && mp.y < height - 10) bg.setAlpha(1);
      else bg.setAlpha(0.5);


      // по клику перейдем в игру
      if (mouse.isPress('LEFT')) {
      game.setLoop('Game');
      }

      // отрисуем фон
      bg.draw();

      // отрисуем свой курсор
      brush.drawImage({
      x : mp.x - 10, y : mp.y - 10, // 10 - смещение картинки из-за обрамления
      file : 'menu_cursor.png'
      });

      };

      });

      // Запускаем игру на текущем игровом цикле
      game.startLoop('Menu');




      И результат:

      image



      game.js — Пишем логику игры



      Тут у нас все достаточно просто: есть три полки, по ним будут «ехать» ноутбуки, на некоторых из них будет логотип DNS, на других синий экран смерти. Задача игрока — убрать с полок все «сломанные» ноутбуки.



      Реализация в коде:

      game.newLoopFromConstructor('Game', function () {

      // создадим полки, по которым будут плыть компьютеры
      var bg = game.newImageObject({
      x : 0, y : 0, // позиция
      file : 'bg_game.jpg', // файл фона
      w : width, // ширину установим, высота подгонится сама,
      h : height
      });

      // массив с количеством компьютеров на полочках (для инициализации)
      var cntShelf;

      var cntRIP = 0;

      // уровни полок по оси Y
      var shelf = {
      1 : i(15), // верхняя полка
      2 : i(86), // средняя
      3 : i(160) // нижняя
      };

      // скорости движения на полках
      var shelfSpeed = {
      1 : math.random(2, 8),
      2 : math.random(2, 8),
      3 : math.random(2, 8)
      };

      var createLaptop = function (s) { // агрументом передаем полку
      var rnd = s ? s : math.random(1, 3); // выбираем полку (случайно) или из агрумента
      var rip = math.random(1, 5) == 5; // выберем тип компьютера (случайно)

      // увеличим количество компьютеров, которые надо убрать (для инициализации)
      if (!s && rip) cntRIP++;

      return game.newImageObject({
      y : shelf[rnd], // установим на выбранную полку
      h : i(50), // выота компьютера
      file : !rip ? 'laptop.png' : 'laptop_rip.png', // выбираем нужный спрайт

      userData : { // дополнительные данные (нестандартные)
      shelf : rnd, // полка
      rip : rip // тип компьютера
      },

      onload : function () { // отпозиционируем после загрузки по оси X
      var dist = 10; // дистанция между компьютерами
      this.x = -cntShelf[rnd] * (this.w + dist); // рссчитываем позицию
      cntShelf[rnd]++; // увеличиваем количество на выбранной полке
      }
      });
      };

      // объекты для "отстрела"
      var cells = []; // это массив

      var fog = 0; // степень прозрачности после тумана после выстрела
      var scale = 1; // степень деформации прицела

      // при входе в игровой цикл установим первичные данные
      this.entry = function () {
      score = 0; // сбросим счет

      // сбросим количества компьютеров
      cntShelf = {
      1 : 0,
      2 : 0,
      3 : 0
      };

      // заполнение массива
      OOP.fillArr(cells, math.random(20, 90), function () {
      return createLaptop(); // вернем в массив только что созданный объект
      });
      };

      this.update = function () {
      var dt = game.getDT(30); // для плавного движения возьмем дельту и поделим на 100

      // запомним на всякий случай позицию курсора
      var mp = mouse.getPosition();

      // запомним так же скорость мыши
      var mps = Math.max(mouse.getSpeed().x, mouse.getSpeed().y);

      // запомним состояние нажатия (true/false) для текущего кадра
      var fire = mouse.isPress('LEFT');

      // имитируем выстрел
      if (fire) {
      fog = 1;
      scale = 1.5;
      }

      // рисуем полочки
      bg.draw();

      // рисуем объекты
      OOP.forArr(cells, function (c, i) {
      var rnd;
      c.draw();
      c.move(point(shelfSpeed[c.shelf] * dt, 0)); // двигаем по оси X

      // если объект ушел за пределы видимости, меняем его позицию по X
      if (c.x > width) {
      c.x = -c.w * cntShelf[c.shelf];
      }

      // если выстрел, проверим попадание
      if (fire) {
      // если курсор попадает в статический бокс объекта BBOX
      if (mouse.isInStatic(c.getStaticBox())) {
      // если компьютер с синим экраном - то увеличиваем счет
      if (c.rip) {
      score++;

      // если мы набрали нужное количество очков
      if (score >= cntRIP) {
      score = 1;
      game.setLoop('Menu');
      }

      } else { // а иначе выкидываем в меню из-за неправильного выбора
      score = -1;
      game.setLoop('Menu');
      return;
      }

      cells.splice(i, 1);
      cells.push(createLaptop()); // добавляем еще новый компьютер
      return;
      }
      }

      });


      // рисуем прицел
      brush.drawImage({
      x : mp.x - i(50) * scale, y : mp.y - i(50) * scale, // 10 - смещение картинки из-за обрамления
      w : i(100) * scale, h : i(100) * scale, // размеры установим фактические
      file : 'cell.png'
      });

      // рисуем счет
      brush.drawText({
      text : 'Убрано: ' + score + '/' + cntRIP,
      color : 'black',
      size : i(15),
      font : 'serif'
      });

      // если есть туман, рисуем его и меняем прозрачность
      if (fog > 0) {
      brush.drawRect({
      w : width, h : height, // закрываем всё
      fillColor : 'rgba(255, 255, 255, '+fog+')'
      });

      fog -= 0.1; // прозрачность
      scale -= 0.05; // степень деформации прицела
      }


      };

      });




      Результат:

      image



      Рекламные вставки и переработка menu.js



      Теперь нам надо переработать файл menu.js, и ввести в него дополнительные условия, что выводить, когда score == -1 (проиграл) и score == 1 (выиграл).



      Переделанный файл menu.js выглядит:

      // Объявляем игровой цикл
      game.newLoopFromConstructor('Menu', function () {

      // Для меню мне требуется создать красивый фон в стиле DNS
      var bg = game.newImageObject({
      x : 0, y : 0, // позиция
      file : 'dns_logo.jpeg', // файл фона
      w : width, // ширину установим
      h : height,
      alpha : 0.8 // немного блеклый
      });

      // объявим функция входа в игровой цикл
      this.entry = function () {

      var div, _s;

      if (score) {
      div = pjs.system.newDOM('div', true);
      _s = div.style; // ссылка на стили
      _s.height = _s.width = '100%'; // установили ширину и высоту HTML блока
      _s.backgroundColor = 'white'; // заливка
      _s.cursor = 'default'; // курсор

      if (score == 1) { // если выиграл
      div.innerHTML = `

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


      Перейти в магазин и попробовать лично

      Сыграть еще раз
      `;
      } else if (score == -1) { // если проиграл
      div.innerHTML = `

      Задача - убрать только сломанные компьютеры!


      Я понял, запускай!

      Перейти в магазин и попробовать лично
      `;
      }
      }
      };

      this.update = function () {
      // запомним на всякий случай позицию курсора
      var mp = mouse.getPosition();

      // при наведении мыши сделаем ярче
      if (mp.x > 10 && mp.x < width - 10 && mp.y > 10 && mp.y < height - 10) bg.setAlpha(1);
      else bg.setAlpha(0.5);


      // по клику перейдем в игру
      if (mouse.isPress('LEFT')) {
      game.setLoop('Game');
      }

      // отрисуем фон
      bg.draw();

      // отрисуем свой курсор
      brush.drawImage({
      x : mp.x - 10, y : mp.y - 10, // 10 - смещение картинки из-за обрамления
      file : 'menu_cursor.png'
      });

      };

      });

      // Запускаем игру на текущем игровом цикле
      game.startLoop('Menu');




      Оформление самой рекламной информации следует переработать, это да, но сам прототип уже работает.

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



      Посмотреть живой пример: Запустить в браузере


      Original source: habrahabr.ru (comments, light).

      https://habrahabr.ru/post/338058/

      Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
      rss_rss_hh_new

      Как правильно вставлять SVG

      Пятница, 15 Сентября 2017 г. 19:00 (ссылка)

      https://habrahabr.ru/post/337284/

      Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
      rss_rss_hh_new

      Web-приложения в Android без Cordova, Phonegap и SMS

      Пятница, 15 Сентября 2017 г. 12:45 (ссылка)




      musicriffstudio


      сегодня в 12:45

      Разработка





      Web-приложения в Android без Cordova, Phonegap и SMS










        Начиная с 5 версии Android компонент WebView поставляется не как часть системы, а как обычное приложение которое может быть обновлено из Google Play:



        image



        Что это даёт разработчикам? Теперь HTML-приложения можно встраивать в .apk без дополнительных костылей. Все возможности HTML5 будут доступны.



        Рассмотрим пример публикации в Google Play реального HTML5 приложения.



        Готовое приложение можно скачать в Google Play, все исходные файлы (JS/HTML, ресурсы, код Java-оболочки) доступны в справке там же.



        Шаг 1. Создание приложения HTML5 и настройка окружения



        Этот шаг пропустим.



        Если у вас нет готового приложения в HTML5 то и публиковать в Google Play пока нечего.

        Последнюю Android Studio можно самостоятельно скачать тут.

        Регистрация аккаунта в Google Play Console также выходит за рамки примера.



        Шаг 2. Создание приложение Android



        Открываем Студию, создаём новый проект и в минимальный API Level указываем как 21 (т.е. Android 5.0). Студия подсказывает что на данный момент это охватывает более двух третей устройств:



        image



        в ближайшие пару лет более старые устройства канут в Лету, но пока так.



        В приложении нам нужна только одна (одно?) Activity содержащее WebView. Весь код буквально убирается на одной странице:



        image



        если интересно, его можно посмотреть по ссылке в приложении.



        Всё что нам нужно это при старте в onCreate сделать пару настроек и открыть файл HTML-страницей. Примерно так



        WebView webView = (WebView) findViewById(R.id.webview);
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDomStorageEnabled(true);
        webView.loadUrl("file:///android_asset/index.html");


        Шаг 3. Добавление файлов HTML



        Добавляем в проект папку Asset:



        image



        и вываливаем туда наши файлы. Это всё.



        Шаг 4. Интеграция с Android



        В приложении есть внешние ссылки (например на исходники в GitHub или на создание сообщения в Twitter). Для этого сделаем свою реализацию shouldOverrideUrlLoading, примерно так:




        @Override
        boolean shouldOverrideUrlLoading(String url) {
        String host = Uri.parse(url).getHost();
        if (host.trim().length() > 0) {
        Uri webpage = Uri.parse(url);
        Intent myIntent = new Intent(Intent.ACTION_VIEW, webpage);
        startActivity(myIntent);
        return true;
        } else {
        return false;
        }
        }


        — всего несколько строк, из них видно, что в случае ссылки на локальную страницу (в host пустая строка) оно не перехватывается и открывается в нашем WebView.



        Если это внешняя страница то ссылка передаётся системе и она сама решит, нужно ли открыть её в Twitter, в выбранном пользователем браузере или ещё как-то.



        Иногда нужно сделать наоборот и указать системе перехватывать некоторые ссылки и открывать их в нашем приложении. Для этого добавим в манифесте для нашего Activity дополнительный фильтр:











        — теперь любые ссылки в почте или веб-страницах будут проверяться на соответствие нашему сервису. Если это ссылка на наш сервис то будет предложено его открыть в нашем приложении:



        image



        Итого



        Файл инсталляции занимает меньше 4Мб, есть полная интеграция с платформой Android, доступны все средства HTML5 (в данном примере это Web Audio).



        В ближайшие пару лет доля старых устройств снизится до нуля и от Cordova можно будет полностью отказаться.


        Original source: habrahabr.ru (comments, light).

        https://habrahabr.ru/post/337990/

        Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

        Следующие 30  »

        <html - Самое интересное в блогах

        Страницы: [1] 2 3 ..
        .. 10

        LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
        О проекте: помощь|контакты|разместить рекламу|версия для pda