Інвентар гравця
Інвентар — це сумка з предметами, які гравець знаходить упродовж гри і застосовує до речей на рівні: ключ до замка, лом до кришки, монету до автомата. Предмет — це рядок-ключ (hammer123), і вся гра з ним зводиться до кодів: застосував предмет — рушій увів за гравця код.
Версій інвентаря дві, і вони живуть поруч.
- Друга — панель унизу екрана, сумка з лічильником, предмети застосовуються до зон на картинці завдання. Вмикається одним рядком у скрипті, місця в тексті завдання не потребує. Про неї вся ця сторінка.
- Перша — список предметів у відведеному автором блоці, у предмета дві кнопки: «око» і «застосувати». Вона працює як працювала й описана наприкінці сторінки; в ігор, що йдуть, її не забирають.
Рівень обирає одну з двох: яку функцію покликав скрипт, та й малює.
Що бачить гравець
Унизу екрана — кнопка-сумка. На ній загальна кількість предметів і окремо «+N» — скільки нових; поки нові є, сумка подригує.
За кнопкою розкривається смуга предметів; нові в ній підсвічені жовтим і перестають бути новими, щойно гравець їх торкнувся — навів мишу, тапнув, потягнув.
Застосувати предмет можна двома способами, і вони рівноправні:
- перетягнути предмет на місце застосування;
- натиснути на предмет, а потім на місце застосування.
Щойно предмет «у руках», на рівні загоряються всі місця, куди його можна застосувати, — зони. Поряд із сумкою тієї ж миті з’являються ще два приймачі: «застосувати» (без зони, просто саме по собі) і «око» — подивитися предмет великим.
Відпустив повз або натиснув порожнє місце — предмет повернувся в сумку.
Що вийшло із застосування, гравець бачить на самому предметі: підійшло — предмет підстрибує зеленим, не підійшло — хитає головою червоним. Якщо предмет забрав бонус, він розчиняється там, куди його донесли. Поки відповіді немає, предмет пульсує на місці.
Розкрита панель і місце, до якого гравець догортав смугу, переживають перезавантаження сторінки: код уведено, рівень змінився — сумка лишилася відкритою на тому самому місці.
Панель притиснута до низу вікна, а не стоїть у тексті завдання, тому на телефоні предмет і місце застосування не зобов’язані вміщатися на екран одночасно.
Як увімкнути
У скрипт завдання (поле внизу рівня):
showInventoryItems2({gameId: 1234});
Більше нічого не треба: ні блоку в тексті завдання, ні id — панель рушій малює сам.
gameId — гра, у теці якої лежать картинки предметів. Можна не вказувати, тоді береться поточна гра, — але див. про копіювання гри.
Виклик має стояти саме у скрипті завдання. Рушій під’єднує другу версію, побачившиshowInventoryItems2у скрипті рівня; з тексту завдання, з бонуса чи із спільної шапки гри він її не під’єднає — функції просто не буде.
І виклик має бути один: він забирає накопичений список предметів, і другий за те саме промальовування намалює порожню сумку.
Предмети
Звідки беруться
Предмет видається з «Тексту після розв’язання» бонуса — у режимі «Джерело»:
<script>
addInventoryItem('hammer123');
</script>
Забирається звідти ж, бонусом пізнішого кроку:
<script>
removeInventoryItem('hammer123');
</script>
Тексти розв’язаних бонусів рушій виконує заново на кожному промальовуванні сторінки. Тому список предметів не зберігається ніде: він щоразу збирається з нуля з того, що вже розв’язано. Сервер про предмети не знає нічого.
Із цього ж випливає і зворотний прийом: видавати предмети не бонусами, а самим скриптом завдання, порахувавши за введеними кодами, що зараз має лежати в сумці. Так зроблено рівень-приклад із полицею — книжку можна поставити, зняти й замінити іншою, і окремих кодів на це не треба.
Наскрізний бонус. Предмет, виданий наскрізним бонусом, звичайним бонусом рівня не забрати — тільки наскрізним із більшим порядковим номером.
На наступний рівень предмет сам не переїжджає. Бонус рівня на іншому рівні не виконується, отже, і предмета там немає. Річ, яку носять через усю гру, видається наскрізним бонусом.
Картинки предметів
Картинка предмета шукається за іменем файлу: item_<ключ> — іконка у смузі, item_<ключ>_big — те, що відкривається за «оком».
Заливати обидві руками не треба. Залийте одну картинку з іменем item_hammer123.png у файли гри: якщо вона від 512 точок по обох сторонах, рушій сам розкладе її на іконку і велику версію. Дрібніша — лишиться одним файлом, і «око» покаже її ж.
У списку залитих файлів у такої картинки з’являється готовий рядок addInventoryItem('hammer123') — за кліком він копіюється в буфер. Вставляти в бонус треба саме його: предмет під’єднується ключем, а не адресою файлу.
Ім’я такого файлу рушій зберігає як є, навіть якщо галочку «Зберегти назву» знято: інвентар шукає картинку за іменем. Ключ береться з імені разом із регістром — це рівно той рядок, що йде в addInventoryItem().
Формат
Типово рушій шукає .jpg. Картинки в іншому форматі — зокрема прозорі png, заради яких у панелі й зроблено слот і тінь, — оголошуються один раз на гру, у «Спільному HTML-заголовку»:
<script>
setInventoryImageExt('png');
setInventoryBigExt('png');
</script>
Іконка і великий вигляд оголошуються окремо: вони можуть бути в різних форматах. Поштучний виняток — другим аргументом:
addInventoryItem('map7', {icon: 'png', big: 'png'});
Розширення не входить у ключ: ключ — це код, який іде на сервер.
Картинки при копіюванні гри
Картинки предметів беруться з теки тієї гри, чий номер ви передали. Копіювання гри файли не копіює, тому в копії картинки зникнуть — якщо gameId не названо явно або він указує на саму копію.
Прив’яжіть інвентар до гри, у яку залито картинки:
showInventoryItems2({gameId: 3493});
Той самий номер можна задати один раз на всю гру, у «Спільному HTML-заголовку», — він копіюється разом із грою:
<script> setInventoryGameId(3493); </script>
Зони застосування
Зона — місце на рівні, до якого застосовують предмет: двері, замок, торговець, слот полиці. У зони є код.
Коли гравець застосовує предмет до зони, рушій уводить складений код: код зони + ключ предмета. Лом (crowbar) на зону lid — це код lidcrowbar. Такий код і має стояти в бонуса, який відкриває кришку.
Зона, під яку коду немає, просто відповідає «не підійшло», і предмет повертається в сумку. Вигадувати «порожні» зони не потрібно: зона без відповідного предмета нічим не загрожує.
Застосування без зони — «застосувати» поряд із сумкою — уводить код, що дорівнює ключу предмета (як у першій версії).
Код зони і ключ склеюються без роздільника, тому імена варто розводити самому: зонаslotіз предметом1bookі зонаslot1із предметомbookдадуть один і той самий код.
Перевіряти на боці гравця, який предмет до якої зони підходить, рушій не вміє і не буде: тоді правильна відповідь лежала б у джерелі сторінки. Будь-який предмет на будь-яку зону — це просто код, і відповідає на нього сервер.
Як задати зону
Чотири способи, і всі вони про одне й те саме — точку і радіус навколо неї. Різняться тим, звідки береться точка.
Точка на картинці (інлайновий svg)
Основний спосіб, коли на картинці кілька місць застосування. У тексті завдання, у режимі «Джерело»:
<svg viewBox="0 0 800 600"> <image href="https://cdn.qeng.org/f/g/1234/room.jpg" width="800" height="600"/> <circle data-inventory-zone="door" cx="410" cy="255" r="40" fill="none"/> <circle data-inventory-zone="chest" cx="96" cy="470" r="55" fill="none"/> </svg>
Координати живуть у системі viewBox, тобто прив’язані до картинки, а не до екрана: телефон, десктоп, поворот, зум — точка лишається на тому самому місці малюнка. Перераховувати нічого не треба.
r — радіус застосування в одиницях картинки. На малому екрані картинка стискається, і разом із нею стискалася б зона, — рушій сам піднімає область влучання до пальця.
Годяться не тільки circle: у будь-якої фігури береться її габаритний прямокутник.
Картинка, вставлена як<img>, так не розмічається: у зовнішнього svg немає доступного рушієві вмісту. Для картинки в<img>— спосіб із відсотками нижче.
Відсотки на картинці
Найдешевший спосіб, коли svg розводити не хочеться:
<img src="..." data-inventory-zones="door:41,42 chest:12,78,6">
Через двокрапку — код зони, далі відсотки від розмірів самої картинки: x, y і (необов’язково) радіус. Зон в одному атрибуті може бути скільки завгодно, через пробіл.
Свій значок так задати не можна — тільки спільний на всі зони носія. Потрібен свій у кожної — беріть data-inventory-zone на окремих елементах або addInventoryZone().
Будь-який елемент сторінки
<div data-inventory-zone="npc">Торговець</div> <img src="..." data-inventory-zone="lock">
Область влучання — прямокутник елемента цілком. Це відповідь для випадку «зона — це блок тексту, картинка цілком або кнопка».
Зі скрипта
Зона, якої на рівні спочатку немає, оголошується викликом — у скрипті завдання або в «Тексті після розв’язання» бонуса:
addInventoryZone('box', {el: '#room', x: 120, y: 150, r: 45});
Перший аргумент — код зони. Далі:
| Поле | Що означає |
|---|---|
el | носій: селектор або елемент. Обов’язковий — він задає систему координат |
x, y | позиція всередині носія; без них — центр елемента, а область влучання — весь його прямокутник |
r | радіус застосування; без нього — розмір значка, піднятий до пальця |
icon | свій значок зони; без нього спільний |
Одиниці визначає носій: інлайновий svg — координати його viewBox, будь-який інший елемент — відсотки його прямокутника (радіус — відсотки меншої сторони). Ті самі {x: 150, y: 262} на svg і на картинці означають різне. Абсолютних екранних координат немає навмисно: вони поїхали б на першому ж іншому екрані.
Повторний виклик із тим самим кодом не заводить другу зону, а оновлює наявну. Отже, зону можна й рухати: перерахував позицію — покликав ще раз.
Прибрати — removeInventoryZone('door'). Зону з розмітки цей виклик теж зніме, але тільки до найближчого автооновлення: html прийде із сервера знову, і зона повернеться. Прибирати її треба там само, де прибирається все інше на рівні, — шаблоном на сервері.
Зона зі скрипта перекриває зону з розмітки з тим самим кодом.
Свій значок зони
Типово в усіх зон один спільний напівпрозорий значок. Свій задається в розмітці атрибутом data-inventory-zone-icon або полем icon у addInventoryZone(), і вид його оголошувати не треба — рушій розрізняє сам:
<circle data-inventory-zone="door" data-inventory-zone-icon="fa-lock" .../> <circle data-inventory-zone="gate" data-inventory-zone-icon="/f/g/123/door.png" .../> <circle data-inventory-zone="safe" data-inventory-zone-icon="🔑" .../>
fa-lock— значок font-awesome;- шлях або адреса — своя картинка;
- будь-що інше — просто символ.
Зони, яких ще немає
Набір зон зазвичай залежить від того, що гравець уже зробив: у розкритої скрині зон немає, щілина автомата з’являється разом із монетою. Розмітку під це зручно збирати шаблонами {% match bonus_N %} — вони рахуються на сервері, тому в джерелі сторінки у гравця лежать тільки ті шари і зони, що видно зараз.
У скрипті завдання шаблони працюють так само, але рядки шаблона коментуються подвійним слешем — рушій знімає коментар сам:
// {% match bonus_2}:{ // {%= leverdncrowbar}:{ addInventoryZone('leverup', {el: '#quest_room', x: 288, y: 305, r: 45}); // %} // {%= ?}:{ addInventoryZone('leverdn', {el: '#quest_room', x: 315, y: 112, r: 45}); // %} // %}
Що варто знати
- Ключ предмета — це код. Крапки, лапки і розширення в нього класти не можна.
- Застосування завжди мовчазне: у формі відповідей нічого не з’являється. Весь зворотний зв’язок — на самому предметі й на зоні.
- Вердикт рушій читає з блоку «Попередні відповіді». Якщо моніторинг на рівні вимкнено, предмет просто мовчки повернеться в сумку — без зеленого й червоного.
- Той самий неправильний код удруге не йде на сервер. Предмет повернеться одразу, з тим самим вердиктом, що й минулого разу, — спроба не витрачається.
- Схований носій зони не дає. Зона на елементі всередині згорнутого
<details>, наdisplay: noneабо на ще не завантаженій картинці не з’явиться — доти, доки носій не покажеться. Перерахунок рушій робить сам: при зміні розмірів вікна, завантаженні картинки і тієї миті, коли гравець бере предмет. - Поки предмет у руках, значок зони лежить поверх сторінки і перехоплює клік по тому, що під ним, — зокрема по вашій кнопці.
- Синоніми бонуса — це стан. Значення бонуса в шаблоні — його остання введена відповідь, а кожен новий синонім заміняє попередній. Тому важіль ходить туди-сюди, а книжка ставиться і знімається: два синоніми в одного бонуса замість двох бонусів.
- Опис бонуса
%hide%не видно в джерелі сторінки до розв’язання — ланцюжок застосувань не підглянути. - Схований рушієм бонус друкується без введеної відповіді. Якщо відповідь потрібна скрипту, ховайте блок бонусів стилем, а не позначкою.
- Панель живе поза автооновлюваною частиною сторінки: чужий код або нова підказка її не закриють і вибраний предмет не заберуть.
- Розкрита панель відсуває низ сторінки. Свій притиснутий до низу блок із нею посперечається.
Чого в інвентаря немає: кількості (предмет або є, або немає — «три монети» робляться трьома предметами чи кодами), сортування і перетягування предмета на предмет.
Приклади у грі
- Інвентар: кімната — предмети знаходять і застосовують до точок на картинці: лом, важіль, замок, кришка, монета в автомат. Зони зі скрипта, шари сцени — шаблонами.
- Інвентар: полиця — предмети не видаються бонусами взагалі: що лежить у сумці і що стоїть на полиці, скрипт щоразу рахує за введеними кодами.
В обох рівнів усередині є розділ «Як так зробити?» з розбором.
Перша версія
Працює як працювала. Різниться тим, що інвентар малюється у відведеному автором блоці, зон немає, а у вибраного предмета дві кнопки — «око» і «застосувати».
- У текст завдання (у режимі «Джерело») — блок, де показувати список:
<div id="inventory_container">Завантаження інвентаря...</div>
- У скрипт завдання — виклик:
showInventoryItems('inventory_container');
Другим параметром — та сама прив’язка картинок до чужої гри: showInventoryItems('inventory_container', 1234).
Предмети видаються і забираються так само, addInventoryItem() і removeInventoryItem() у «Тексті після розв’язання» бонуса. Кнопка «застосувати» вводить код, що дорівнює ключу предмета.
Приклад у грі: Інвентар.
Дивіться також
- Шаблони —
{% match bonus_N %}для сцени і зон, що залежать від стану рівня. - Складені коди — підсумковий код рівня, зібраний із частин.
- Інтерактивні елементи (скрипти) — решта функцій, доступних у скрипті завдання.







