Движок уміє сам вбивати код, коли гравець дійшов до потрібної точки на місцевості. Зробити це можна двома способами:
{! on gps … !} у тексті завдання. Координат цілі немає в сторінці гравця ніде: ні в тексті, ні в скрипті, ні у відповідях сервера. Це основний спосіб.g_targets у «Скрипті завдання». Перевірка йде в браузері, тому координати цілі лежать у вихідному коді сторінки. Спосіб старий, але потрібен, коли браузеру самому треба знати, де ціль: показати відстань, намалювати точку на карті.Важливо: геолокація вмикається лише з дозволу гравця. Якщо гравець відмовить, жодна зона не спрацює, тому залишайте запасний спосіб пройти рівень (звичайний код, підказка зі зливом) або заздалегідь попередьте команди, що GPS обов'язковий.
Трек команди. Поки стеження увімкнене, рушій записує шлях команди — по пристрою, сегментами «стояли» і «йшли», плюс спрацьовування зон і відкинуті заміри. На сторінці гри в автора є посилання «Треки GPS»: там звіт з ознаками підміни геолокації по командах (вердикт — не вирок, у кожної ознаки є чесні пояснення), спірні моменти на кшталт «дійшли до зони, але код не введено» і карта. Трек зберігається 90 днів від останнього запису; видалити раніше можна там само.
Обидва способи починаються однаково — з виклику gps_start() у полі «Скрипт завдання»:
gps_start();
Без нього браузер не запитає координат, і жодна зона не спрацює. Якщо в завданні є тригери, а gps_start() ніде немає, редактор попередить про це під час збереження.
Бібліотеку геолокації движок підключає лише завданням, яким вона потрібна, — окремо вмикати нічого не треба.
У завдання з GPS поруч із назвою стоїть значок-супутник. Він показує гравцеві, чи працює геолокація, і сам же її вмикає: на телефоні браузер дає координати лише після натискання, тому значок стоїть від самого початку, ще до першого заміру.
| Колір | Що означає | Що зробить натискання |
|---|---|---|
| сірий | стеження не ввімкнено | увімкне його |
| червоний | позиції немає: шукаємо супутники, гравець заборонив доступ або геолокація недоступна | почне пошук заново або підкаже, як дозволити доступ |
| жовтий | позиція є, але точність гірша за 30 метрів — такий замір движок не зараховує | оновить позицію |
| зелений | усе працює, можна йти | оновить позицію |
Якщо навести на значок, підказка назве стан словами й поточну точність.
Зона оголошується маркером у тексті завдання:
{! on gps 51.5299 -0.1275 radius 30: code ньютон !}
51.5299 -0.1275 — центр зони: широта й довгота, у тому вигляді, в якому їх копіюють із Google Maps чи OpenStreetMap. Кома між ними не обов'язкова.radius 30 — радіус у метрах. Можна не писати — за замовчуванням 30.code ньютон — що зробити, коли гравець у зоні: вбити код. Код має бути кодом або бонусом цього завдання.{! on gps /* задній двір */ 51.5299 -0.1275: code ньютон !}. Гравець його не побачить, а тестувальник побачить на карті.Загальні правила маркера — де він спрацьовує, що перевіряє збереження, як пишуться кілька дій — на сторінці Серверні дії.
Двір, сквер, квартал — зона-багатокутник. Після слова polygon ідуть координати вершин поспіль, парами «широта довгота», від 3 до 30 вершин. Радіуса в багатокутника немає — межі задають вершини.
{! on gps /* сквер */ polygon 51.5305 -0.1280 51.5320 -0.1262 51.5313 -0.1230 51.5291 -0.1238: code сквер !}
Поки гравець іде, сторінка надсилає його координати на сервер — коли він зсунувся хоча б на кілька метрів, але не частіше, ніж раз на пару секунд. Сервер відповідає, в якій зоні гравець стоїть, і сторінка вбиває код цієї зони — мовчки, звичайною відповіддю. У журналі відповідей такий код записано за гравцем, який дійшов.
g_targets.Звичайний код зона вбиває один раз. Умова про поле у квадратних дужках дозволяє вбивати знову — і тут вона найпотрібніша:
{! on gps /* північний двір */ 51.5221 -0.1072 radius 30: code [c1 !=] north !}
{! on gps /* південний двір */ 51.5201 -0.1072 radius 30: code [c1 !=] south !}
Дві зони на один сектор — перемикач: у першому секторі стоїть код тієї зони, в якій команда була останньою. Шаблон {% match code_1 %} показує за ним, де команда зараз. Зони перемикача не мають перетинатися: стоячи у двох одразу, гравець отримає обидва коди поспіль.
{! on gps /* далеко */ 51.5190 -0.1072 radius 30: code [c2 <] 1far !}
{! on gps /* біля дверей */ 51.5215 -0.1072 radius 30: code [c2 <] 4door !}
Набір зон із < — пріоритет: код із більшим числом на початку замінює менший, але не навпаки. Так у секторі залишається найкраща з досягнутих точок.
Докладно про умову про поле — на сторінці Серверні дії.
Буває, що за зоною нічого вбивати не треба — треба лише показати гравцеві щось, поки він стоїть біля альтанки. Для цього є дія zone з іменем:
{! on gps /* альтанка */ 51.5241 -0.1072 radius 30: zone альтанка !}
Коду в такої зони немає. Сторінка повідомляє скрипт завдання, що гравець увійшов у зону або вийшов із неї, — один раз на зміну, а не на кожен замір:
QEng.Gps.onZone = function (name, inside) { if (name === 'альтанка') $('#gazebo').toggle(inside); };
zone; пробіли в ньому можна. Приходить воно лише тому, хто вже стоїть у зоні, — де зона, сторінка й далі не знає.{! on gps 51.5299 -0.1275: code ньютон: zone двір !}.Маркер працює, поки видно текст, у якому він стоїть. Тому зона в описі бонусу є, поки бонус не розв'язано, а зона в підказці з'являється разом із підказкою. Так набір зон змінюється протягом рівня без жодного рядка скрипта.
Сама зона гру не завершує. Це два кроки: зона вбиває код, а finish_game стоїть у гілці шаблону за цим кодом:
{! on gps 51.5299 -0.1275: code фініш !}
{% match code_1 }:{ {%= фініш}:{ {! finish_game !} %} %}
Приклад у грі: перемикач, багатокутник, пріоритет, зона без коду, зони в бонусі й у підказці
У тестувальника в панелі тестування внизу сторінки є вкладка «GPS» — вона з'являється на завданні, скрипт якого викликає gps_start().
Що вбили маркери на цьому завантаженні сторінки, показує сусідня вкладка «Дії» — див. Серверні дії.
Старий спосіб, і він працює як працював. Координати точок лежать у вихідному коді сторінки, тож для загадки «знайдіть місце» він не годиться — гравець відкриє вихідний код і побачить ціль. Потрібен він, коли браузеру самому треба знати, де ціль: показати відстань, намалювати точку на своїй карті.
Точки складаються в масив g_targets. Кожна точка — об'єкт з координатами, радіусом та діями:
gps_start(); window.target_lat1 = 51.5211367; // Широта точки window.target_lon1 = -0.10723867; // Довгота точки g_targets.push({ 'lat': window.target_lat1, 'lon': window.target_lon1, 'r': 30, // Радіус у МЕТРАХ 'action_inside': "enter_silent('finish_code_123')", 'action_outside': "$('#distance_to').text(gps_distance(window.target_lat1, window.target_lon1).toFixed(0))" });
lat, lon — координати точки.r — радіус спрацювання в метрах.action_inside — рядок з javascript, виконується, коли гравець усередині радіуса.action_outside — рядок з javascript, виконується, коли гравець зовні радіуса.
Точок може бути скільки завгодно — просто додайте в g_targets кілька об'єктів.
Дії виконуються при кожному оновленні координат, а не один раз при вході в зону. Поки гравець стоїть усередині радіуса,action_insideспрацює багато разів поспіль. Для введення коду це безпечно:enter()таenter_silent()надсилають код лише один раз. А от показ повідомлення чи програвання звуку краще захистити власним прапорцем:
'action_inside': "if (!window.was_inside) { window.was_inside = 1; play_sound('limit'); }"
Функція gps_distance(широта, довгота) повертає відстань від поточного положення гравця до вказаної точки в метрах. Зазвичай її показують гравцеві, щоб він розумів, тепліше чи холодніше:
<p>Відстань до точки: <span id="distance_to">???</span> м.</p>
Функцію можна викликати лише після того, як отримано перші координати, — до цього положення гравця невідоме. Найпростіше викликати її з action_outside, як у прикладі вище: движок сам виконає її, коли координати з'являться.
Якщо потрібно не просто перевірити радіус, а намалювати карту чи свій індикатор, перевизначте функцію on_update_position() — движок викликає її щоразу, коли надійшли нові координати. Поточне положення лежить у g_position (поля lat, lon, а також accuracy — точність заміру в метрах, timestamp, altitude, speed, heading):
gps_start(); on_update_position = function () { $('#my_coords').text(g_position.lat.toFixed(5) + ', ' + g_position.lon.toFixed(5) + ' (±' + Math.round(g_position.accuracy) + 'м)'); };
Також можна відстежувати стан роботи датчика через on_gps_status(status, details):
requesting — запит дозволу у браузера;searching — очікування захоплення супутників GPS;locked — координати отримано і вони оновлюються;timeout — пошук супутників затягнувся (движок робить м'які авто-повтори);denied — гравець заборонив доступ до геопозиції;unavailable — геолокація недоступна або вимкнена.
Для зупинки відстеження (наприклад, при переході між етапами для економії батареї) є функція gps_stop(). Повторний виклик gps_start() не перезапускає чип GPS з нуля, а перевикористовує активний спостерігач і відразу застосовує поточні координати до нових цілей.
Ті самі функції є й під спільним ім'ям QEng.Gps: QEng.Gps.start() і stop(), distance(lat, lon), position, targets, addTarget({…}), onUpdatePosition, onStatus. Старі імена працюють і працюватимуть.
Службова функція init_debug_map(широта, довгота, зум) малює карту з вашими точками та радіусами і ставить перетягуваний маркер гравця. Куди ви перетягнете маркер — там движок і вважатиме гравця. Функція чекає на сторінці контейнер <div id=“debug_map”> і працює на Leaflet + OpenStreetMap, без API-ключів. Для тригерів на сервері вона не потрібна — у тестувальника для цього є вкладка «GPS».
Движок не підключає жодних картографічних бібліотек — карту автор додає сам у текст завдання. У прикладі нижче використовується безкоштовний Leaflet із тайлами OpenStreetMap: підключаються css та js бібліотеки, створюється контейнер карти, а мітка рухається за координатами гравця.
Врахуйте, що завдання перемальовується при автооновленні, тому стан карти (центр, зум, об'єкт карти) зручно зберігати у window, щоб вона не створювалася заново і не «стрибала» під гравцем.
Якщо за сюжетом потрібно просто відправити гравця в точку, а не перевіряти його прихід, вистачить звичайного посилання. Вставляється в режимі «Джерело»:
<a href="geo:?q=59.249,37.465">59.249, 37.465</a>
Схема geo: відкриває координати в навігаторі, встановленому на телефоні. Для настільних браузерів, де такої схеми немає, підійде посилання на карти:
<a href="https://www.google.com/maps/search/?api=1&query=49.940333,36.39305" target="_blank">49.940333, 36.39305</a>
Приклад тригерів на сервері | Приклад точки в скрипті | Приклад з картою | Приклад посилань на координати