2
0
Эх сурвалжийг харах

Ukrainian translation. Addressing and message passing. (#375)

* Fix some grammar mistakes.

* Addressing and message passing.
Dmitriy Shmilo 1 жил өмнө
parent
commit
3bd7a0b220

+ 246 - 0
docs/uk/manuals/addressing.md

@@ -0,0 +1,246 @@
+---
+title: Адресація Defold
+brief: Цей посібник пояснює як Defold вирішує проблему адресації.
+---
+
+# Адресація
+
+Код, який контролює гру під час виконання, повинен мати змогу досягти будь-який обʼєкт або компонент щоб рухати, масштабувати, анімувати, видаляти та маніпулювати все що гравець бачить та чує. Механізм адресації Defold робить це можливим.
+
+## Ідентифікатори
+
+Defold використовує адреси (або URL, але про це потім) щоб посилатися на обʼєкти та компоненти. Ці адреси складаються з ідентифікаторів. Далі наведені приклади того як Defold використовує адреси. В цьому посібнику ми детально розглянемо як вони працюють:
+
+```lua
+local id = factory.create("#enemy_factory")
+label.set_text("my_gameobject#my_label", "Hello World!")
+
+local pos = go.get_position("my_gameobject")
+go.set_position(pos, "/level/stuff/other_gameobject")
+
+msg.post("#", "hello_there")
+local id = go.get_id(".")
+```
+
+Почнемо з простого прикладу. Уявіть що у вас є ігровий обʼєкт з одним компонентом-спрайтом. Також ви маєте компонент-скрипт, що контролює ігровий обʼєкт. Така структура в редакторі буде виглядати приблизно так:
+
+![bean в редакторі](images/addressing/bean_editor.png)
+
+Тепер ви хочете відключити спрайт коли гра починається, а пізніше показати його. Це без проблем робиться таким кодом в "controller.script":
+
+```lua
+function init(self)
+    msg.post("#body", "disable") -- <1>
+end
+```
+1. Не хвилюйтеся, якщо символ'#' вас спантеличив. Ми повернемося до нього пізніше.
+
+Цей код працюватиме, як і очікується. Коли гра починається, скрипт *адресує* спрайт за його ідентифікатором "body" та використовує цю адресу щоб відправити спрайту *повідомлення* "disable". Це спеціальне повідомлення, і його ефект полягає в тому що спрайт сховає свою графіку. Схематично, структура виглядає так:
+
+![bean](images/addressing/bean.png)
+
+Ідентифікатори в цій структурі довільні. Ми вирішили назвати ігровий обʼєкт - "bean", його спрайт компонент - "body", а компонент-скрипт, що контролює персонажа, назвали "controller".
+
+::: sidenote
+Якщо ви не оберете назву, за вас це зробить редактор. Коли ви створюєте новий обʼєкт або компонент, властивості *Id* буде автоматично призначене унікальне значення.
+
+- Ігрові обʼєкти автоматично отримують назву "go" разом із лічильником ("go2", "go3" і т.д.).
+- Компоненти отрумають назву, яка відповідає типу компонента ("sprite", "sprite2" і т.д.).
+
+Якщо хочете, можете залишити ці автоматично згенеровані назви, але ми заохочуємо вас змінювати їх на описові імена.
+:::
+
+Тепер давайте додамо ще один спрайт, та дамо квасолі щит:
+
+![bean](images/addressing/bean_shield_editor.png)
+
+Новий компонент повинен мати уникальний ідентифікатор в межах ігрового обʼєкта. Якщо назвати його "body" тоді код скрипту не може визначити якому спрайту відправити повідомлення "disable". Отож ми маємо обрати унікальний (та описовий) ідентифікатор "shield". Тепер ми можемо вмикати та вимикати "body" та "shield" коли забажаємо.
+
+![bean](images/addressing/bean_shield.png)
+
+::: sidenote
+Якщо ви спробуєте використати один і той же ідентифікатор більше одного разу, редактор повідомить про це помилкою, тому, на практиці, це ніколи не проблема:
+
+![bean](images/addressing/name_collision.png)
+:::
+
+А тепер давайте подивимося що станется, якщо ви додасте більше ігрових обʼєктів. Припустимо, що треба обʼєднати дві квасолі ("beans") в маленьку команду. Ви вирішили один ігровий обʼєкт назвати "bean", а інший - "buddy". Окрім того, після деякого часу бездіяльності, "bean" має наказати свому другу "buddy" почати танцювати. Для цього треба відправити cвоє власне повідомлення "dance" від скрипту "controller", що належить обʼєкту "bean", до скрипту "controller", який належить обʼєекту "buddy":
+
+![bean](images/addressing/bean_buddy.png)
+
+::: sidenote
+Хоча ми й маємо два різних компоненти названих "controller", це не буде помилкою, оскільки кожен ігровий обʼєкт створює окремий контекст іменування.
+:::
+
+Через те, що адресат повідомлення знаходиться за межами ігрового обʼєкта, який відправляє повідомлення ("bean"), в коді треба вказати який з "controller"-ів має отримати повідомлення. Потрібно вказати ідентифікатор ігрового обʼєкта разом із ідентифікатором компонента, якому належить отримати повідомлення. Повна адреса компонента буде `"buddy#controller"`, і вона складається з двох окремих частин.
+
+- Першим вказано ідентифікатор ігрового обʼєкта, що містить бажаний компонент ("buddy"),
+- потім додається символ-роздільник обʼєктів та компонентів ("#"),
+- і, нарешті, ми вказуємо ідентифікатор бажаного компонента ("controller").
+
+Повертаючись до попереднього прикладу з єдиним обʼєктом, ми бачимо, що пропустивши ідентифікатор ігрового обʼєкта, код може адресувати компоненти в *поточному ігровому обʼєкті*.
+
+Наприклад, `"#body"` позначає адрес компонента "body" в поточному ігровому обʼєкті. Такий код буде працювати у *будь-якому* ігровому обʼєкті, до тих пір, поки в ньому є компонент "body".
+
+## Колекції
+
+Колекції дозволяють створювати групи, або ієрархії, ігрових обʼєктів та повторно їх використовувати контрольованим чином. Колекції використовуються в якості шаблонів (або "прототипів", або "prefabs"-ів) в редакторі коли ви наповнюєте свою гру змістом.
+
+Наприклад, ви хочете створити велику кількість "bean/buddy" команд. Цього можна досягти створивши шаблон в новому *файлі колекції* (назвемо його "team.collection"). В цьому файлі треба побудувати ігрові обʼєкти команди та зберегти файл. Потім створити екземпляр змісту цього файла-колекції в вашій головній колекції (bootstrap collection) і надати новому екземпляру імʼя(наприклад, "team_1"):
+
+![bean](images/addressing/team_editor.png)
+
+З такою структурою, ігровий обʼєкт "bean" все ще може посилатися на компонент "controller" в обʼєкті "buddy" за адресою `"buddy#controller"`.
+
+![bean](images/addressing/collection_team.png)
+
+А якщо ми додамо другий екземпляр "team.collection" (назвемо його "team_2"), то код, який виконується в скриптах "team_2" також буде працювати. Ігровий обʼєкт "bean", що належить колекції "team_2", все ще може адресувати компонетн "controller" в обʼєкті "buddy" за адресою `"buddy#controller"`.
+
+![bean](images/addressing/teams_editor.png)
+
+## Відносна адресація
+
+Адреса `"buddy#controller"` працює для обох обʼєктів з обох колекцій тому що вона *відносна*. Обидві колекції "team_1" та "team_2" створюють новий контекст іменування, або "простір імен". Defold враховує контекст іменування під час адресації, і таким чином уникає колізій в іменах:
+
+![відносний ідентифікатор](images/addressing/relative_same.png)
+
+- В контексті "team_1", ігрові обʼєекти "bean" та "buddy" унікально ідентифіковані.
+- Так само, в контексті "team_2", ігрові обʼєкти "bean" та "buddy" теж унікально ідентифіковані.
+
+Під час вирішення фінальної адреси через відносну адресацію, поточний контекст іменування буде автоматично доданий в початок відносної адреси. Це дуже корисно, бо дозволяє вам створювати групи ігрових обʼєктів з кодом, та ефективно використовувати їх скрізь у вашому проєкті.
+
+### Скорочення
+
+В Defold є два скорочення, які можна використовувати для відправки повідомлень, не вказуючи повний URL:
+
+:[Скорочення](../shared/url-shorthands.md)
+
+## Шляхи ігрових обʼєктів
+
+Щоб зрозуміти механізм іменування, давайте подивимося що відбувається коли ви зберете та виконаєте проєкт:
+
+1. Редактор читає стартову колекцію ("main.collection") та весь її зміст (ігрові обʼєкти та інші колекції).
+2. Компілятор створює ідентифікатор для кожного статичного ігрового обʼєкта. Ідентифікатори будуються як "шляхи", що починаються в корені стартової колекції, та прямують ієрархією колекцій до самого обʼєекта. На кожному рівні додається символ '/'.
+
+Для нашого прикладу вище, гра буде виконуватися із наступними чотирьма ігровими обʼєктами:
+
+- /team_1/bean
+- /team_1/buddy
+- /team_2/bean
+- /team_2/buddy
+
+::: sidenote
+Ідентифікатори зберігаються як хешовані значення. Середовище виконання зберігає хеші ідентифікаторів кожної колекції, та використовує їх при перетворенні відносних адрес на хеші абсолютних.
+:::
+
+Групування в колекції не існує під час виконання. Немає можливості дізнатися до якої колекції належав обʼєкт до компіляції. Виконувати дії над усіма обʼєктами в колекції водночас теж неможливо. Якщо ви потребуєте таку можливість, то вам доведеться самостійно відстежувати всі бажані обʼєкти в коді. Ідентифікатор кожного обʼєкта статичний, і він гарантовано буде незмінним на протязі всього життєвого циклу обʼєкта. Це означає що ви можете без ризику зберігати ідентифікатор обʼєкта та використовувати його у будь-який час.
+
+## Абсолютна адресація
+
+Під час адресації, можна використовувати повні ідентифікатори. В більшості випадків краще використовувати відносну адресацію, тому що вона дозволяє повторно використовувати частини проєкту, але існують випадки коли абсолютна адресаціє буде необхідною.
+
+Наприклад, якщо ви хочете створити менеджер ШІ, який відстежує стан кожного обʼєкта "bean". Ви хочете щоб "bean"-и повідомляли свій активний статус менеджеру, а менеджер приймав тактичні рішення та віддавав накази "bean"-ам в залежності від їх статусу. Логічно було б створити єдиний ігровий обʼєкт-менеджер із скриптом, та покласти його поряд з колекціями команд ("team") в стартовій колекції.
+
+![обʼєкт менеджер](images/addressing/manager_editor.png)
+
+Кожен "bean" тепер відповідає за відправку повідомлень менеджеру: "contact" якщо він подбачив ворога, або "ouch!" якщо він отримав ушкодження. Для цього скрипт "controller" в обʼєкті "bean" використовує абсолютну адресацію щоб віправляти повідомлення компоненту "controller" в обʼєкті "manager".
+
+Будь-яка адреса що починається з '/' буде вирішуватись від кореня ігрового світу. А це відповідає кореню *стартової колекції*, яка завантажується на початку гри.
+
+Абсолютною адресою скрипту менеджера буде `"/manager#controller"` і ця адреса буде вказувати на вірний компонент незалежно від того, де вона використовується.
+
+![команди та менеджер](images/addressing/teams_manager.png)
+
+![абсолютна адресація](images/addressing/absolute.png)
+
+## Хешовані ідентифікатори
+
+Рушій зберігає всі ідентифікатори як хешовані значення. Усі функції, що приймають компонент або ігровий обʼєкт в якості аргументу, приймають рядок, хеш або URL обʼєкта. Вище ми вже побачили як використовувати рядки для адресації.
+
+Коли ви отримуєте ідентифікатор ігрового обʼєкта, рушій завжди поверне хеш абсолютного шляху:
+
+```lua
+local my_id = go.get_id()
+print(my_id) --> hash: [/path/to/the/object]
+
+local spawned_id = factory.create("#some_factory")
+print(spawned_id) --> hash: [/instance42]
+```
+
+Такий хеш можна використовувати замість рядка ідентифікатора, або можна зібрати самому. Зауважте, що хешований ідентифікатор відповідає шляху до обʼєкта, тобто повній адресі:
+
+::: sidenote
+Відносні адреси мають надаватися рядками, тому що рушій буде обчислювати новий хеш ідентифікатора шляхом хешування заданого рядка разом з хешом поточного контексту іменування (колекції).
+:::
+
+```lua
+local spawned_id = factory.create("#some_factory")
+local pos = vmath.vector3(100, 100, 0)
+go.set_position(pos, spawned_id)
+
+local other_id = hash("/path/to/the/object")
+go.set_position(pos, other_id)
+
+-- This will not work! Relative addresses must be given as strings.
+local relative_id = hash("my_object")
+go.set_position(pos, relative_id)
+```
+
+## URL
+
+Для повноти картини подивимося на загальний формат адрес в Defold: URL.
+
+URL - це обʼєкт, зазвичай рядок, у спеціальному форматі. Звичайний URL складається з трьох частин:
+
+`[socket:][path][#fragment]`
+
+Сокет (socket)
+: Ідентифікує ігровий світ цілі. Він важливий коли ви працюєте з [проксі колекцій (Collection Proxies)](/manuals/collection-proxy) і ідентифікує в такому випадку _динамічно завантажену колекцію_.
+
+Шлях (path)
+: Ця частина URL містить повний ідентифікатор цільового ігрового обʼєкта.
+
+Фрагмент (fragment)
+: Ідентифікатор цільового компонента в межах вказаного ігрового обʼєкта.
+
+Як ми вже бачили, частину, або навіть більшість, цієї інформації часто можна пропускати. Вам майже ніколи не треба вказувати сокет, і вам часто, але не завжди, треба вказувати шлях. Сокет потрібно вказати, якщо вам треба адресувати речі в іншому ігровому світі. Наприклад, повний URL до скрипту "controller" в ігровому обʼєкті "manager" буде:
+
+`"main:/manager#controller"`
+
+а до "controller"-а в "buddy" в "team_2" буде:
+
+`"main:/team_2/buddy#controller"`
+
+Ми можемо відправляти їм повідомлення:
+
+```lua
+-- Send "hello" to the manager script and team buddy bean
+msg.post("main:/manager#controller", "hello_manager")
+msg.post("main:/team_2/buddy#controller", "hello_buddy")
+```
+
+## Будування обʼєктів URL
+
+URL обʼєкти можна створювати програмно в Lua коді:
+
+```lua
+-- Construct URL object from a string:
+local my_url = msg.url("main:/manager#controller")
+print(my_url) --> url: [main:/manager#controller]
+print(my_url.socket) --> 786443 (internal numeric value)
+print(my_url.path) --> hash: [/manager]
+print(my_url.fragment) --> hash: [controller]
+
+-- Construct URL from parameters:
+local my_url = msg.url("main", "/manager", "controller")
+print(my_url) --> url: [main:/manager#controller]
+
+-- Build from empty URL object:
+local my_url = msg.url()
+my_url.socket = "main" -- specify by valid name
+my_url.path = hash("/manager") -- specify as string or hash
+my_url.fragment = "controller" -- specify as string or hash
+
+-- Post to target specified by URL
+msg.post(my_url, "hello_manager!")
+```

+ 10 - 10
docs/uk/manuals/building-blocks.md

@@ -24,9 +24,9 @@ Defold гра складається з блоків трьох головних
 
 Колекції - це деревоподібні структури, які містять в собі ігрові обʼєкти та інші колекції. Вони завжди зберігаються у файлах.
 
-Коли Defold двигун стартує, він завантажує єдину _стартову колекцію (bootstrap collection)_, яка вказана в файлі налаштувань проєкту *game.project*. Стартова колекція зазвичай називається "main.collection", але ви можете переіменувати її як завгодно.
+Коли рушій Defold стартує, він завантажує єдину _стартову колекцію (bootstrap collection)_, яка вказана в файлі налаштувань проєкту *game.project*. Стартова колекція зазвичай називається "main.collection", але ви можете переіменувати її як завгодно.
 
-Колекція може містити ігрові обʼєкти та інші колекції (через посилання на файл підколекції), скомпоновані як завгодно. Ось наприклад файл "main.collection". Він містить один ігровий обʼєкт (з ідентифікатором "can") та одну підколекію (з ідентифікатором "bean"). В свою чергу, підколекція містить два ігрові обʼєкти: "bean" та "shield".
+Колекція може містити ігрові обʼєкти та інші колекції (через посилання на файл підколекції), скомпоновані як завгодно. Ось, наприклад, файл "main.collection". Він містить один ігровий обʼєкт (з ідентифікатором "can") та одну підколекію (з ідентифікатором "bean"). В свою чергу, підколекція містить два ігрові обʼєкти: "bean" та "shield".
 
 ![Колекція](images/building_blocks/collection.png){srcset="images/building_blocks/[email protected] 2x"}
 
@@ -34,7 +34,7 @@ Defold гра складається з блоків трьох головних
 
 ![Колекція Bean](images/building_blocks/bean_collection.png){srcset="images/building_blocks/[email protected] 2x"}
 
-Самі колекції не можна адресувати, тому що під час виконання не існує обʼєктів, відповідних колекціям "main" та "bean". Однак, іноді вам доведеться використовувати ідентифікатор колекції як частину _шляху_ до ігрового обʼєкту (див. [посібник з адресації](/manuals/addressing)):
+Самі колекції не можна адресувати, тому що під час виконання не існує обʼєктів, відповідних колекціям "main" та "bean". Однак, іноді вам доведеться використовувати ідентифікатор колекції як частину _шляху_ до ігрового обʼєкта (див. [посібник з адресації](/manuals/addressing)):
 
 ```lua
 -- file: can.script
@@ -55,9 +55,9 @@ local pos = go.get_position("bean/bean")
 go.animate("can", "position.x", go.PLAYBACK_LOOP_PINGPONG, 100, go.EASING_LINEAR, 1.0)
 ```
 
-Ігрові обʼєкти можна використовувати пустими (наприклад як маркери позиції), але зазвичай до них додаються різномаїтні компоненти: спрайти, звуки, сценарії, моделі, фабрики, та інші. Ігрові обʼєкти створюються в редакторі, додаються до колекцій, або генеруються динамічно під час виконання за допомогою компонентів _фабрик (factory)_.
+Ігрові обʼєкти можна використовувати пустими (наприклад, в якості маркерів позиції), але зазвичай до них додаються різномаїтні компоненти: спрайти, звуки, сценарії, моделі, фабрики, та інші. Ігрові обʼєкти створюються в редакторі, додаються до колекцій, або генеруються динамічно під час виконання за допомогою компонентів _фабрик (factory)_.
 
-Ігрові обʼєкти додаються до колекції на місці, або як посилання на файл ігрового обʼєкту:
+Ігрові обʼєкти додаються до колекції на місці, або як посилання на файл ігрового обʼєкта:
 
 Клацніть <kbd>правою кнопкою</kbd> на колекції в вікні *Структура (Outline)* та оберіть <kbd>Add Game Object</kbd> (додати на місці) або <kbd>Add Game Object File</kbd> (додати як посилання на файл).
 
@@ -70,7 +70,7 @@ go.animate("can", "position.x", go.PLAYBACK_LOOP_PINGPONG, 100, go.EASING_LINEAR
 
 ## Додавання обʼєктів на місці (in-place) або за посиланням (by reference)
 
-Коли ви створюєте _файл_ колекції, ігрового обʼєкту або компоненту, ви створюєте так званий прототип (також відомий як "prefab" або "blueprint" в інших двигунах). Такий файл лише додається до структури проєкту, нічого не буде додано до вашої гри під час виконання. Для того щоб створити екземпляр(instance) колекції, ігрового обʼєкту або компоненту, його потрібно додати до файлу колекції.
+Коли ви створюєте _файл_ колекції, ігрового обʼєкта або компонента, ви створюєте так званий прототип (також відомий як "prefab" або "blueprint" в інших рушіях). Такий файл лише додається до структури проєкту, нічого не буде додано до вашої гри під час виконання. Для того щоб створити екземпляр(instance) колекції, ігрового обʼєкта або компонента, його потрібно додати до файлу колекції.
 
 Ви можете побачити файл, із якого створюється екземпляр, у вікні структури (outline). Файл "main.collection" містить три єкземпляри, що засновані на цих файлах:
 
@@ -80,7 +80,7 @@ go.animate("can", "position.x", go.PLAYBACK_LOOP_PINGPONG, 100, go.EASING_LINEAR
 
 ![Екземпляр](images/building_blocks/instance.png){srcset="images/building_blocks/[email protected] 2x"}
 
-Користь від створення файлів-прототипів стає очевидною коли ви маєте кілька екземплярів ігрового обʼєкту або колекції та бажаєте міняти їх всіх одразу:
+Користь від створення файлів-прототипів стає очевидною коли ви маєте кілька екземплярів ігрового обʼєкта або колекції та бажаєте міняти їх всіх одразу:
 
 ![Екземпляри ІО](images/building_blocks/go_instance.png){srcset="images/building_blocks/[email protected] 2x"}
 
@@ -88,7 +88,7 @@ go.animate("can", "position.x", go.PLAYBACK_LOOP_PINGPONG, 100, go.EASING_LINEAR
 
 ![Зміна прототипу ІО](images/building_blocks/go_change_blueprint.png){srcset="images/building_blocks/[email protected] 2x"}
 
-Наприклад тут зображення спрайту було змінене в прототипі, і негайно всі екземпляри оновились:
+Наприклад, тут зображення спрайту було змінене в прототипі, і негайно всі екземпляри оновились:
 
 ![Оновлені екземпляри ІО](images/building_blocks/go_instance2.png){srcset="images/building_blocks/[email protected] 2x"}
 
@@ -98,7 +98,7 @@ go.animate("can", "position.x", go.PLAYBACK_LOOP_PINGPONG, 100, go.EASING_LINEAR
 
 ![Дочірні ігрові обʼєкти](images/building_blocks/childing.png){srcset="images/building_blocks/[email protected] 2x"}
 
-Ієрархія дочірніх обʼєктів - це динамічні відносини, вони впливають на те як обʼєкти реагують на трансформації. Будь-яка трансформація обʼєкту (пересування, поворот або масштаб) буде в свою чергу застосована до дочірнії обʼєктів, як у редакторі, так і під час виконання:
+Ієрархія дочірніх обʼєктів - це динамічні відносини, вони впливають на те як обʼєкти реагують на трансформації. Будь-яка трансформація обʼєкта (пересування, поворот або масштаб) буде в свою чергу застосована до дочірніх обʼєктів, як у редакторі, так і під час виконання:
 
 ![Дочірня трансформація](images/building_blocks/child_transform.png){srcset="images/building_blocks/[email protected] 2x"}
 
@@ -112,5 +112,5 @@ msg.post("child_bean", "set_parent", { parent_id = parent })
 ```
 
 ::: important
-Поширене непорозуміння що місце обʼєкта в колекції змінюється коли він стає частиною батьківських-дочірніх відносин. Однак, це різні речі. Ієрархія дочірніх обʼєктів динамічно змінює граф сцени, що дозволяю обʼєктам візуально приєднуватися одне до одного. Єдине, від чого залежить адрес обʼєкту, це його місце в ієрархії колекцій. Адрес залишиться статичним на весь час існування обʼєкту.
+Поширене непорозуміння що місце обʼєкта в колекції змінюється коли він стає частиною батьківських-дочірніх відносин. Однак, це різні речі. Ієрархія дочірніх обʼєктів динамічно змінює граф сцени, що дозволяю обʼєктам візуально приєднуватися одне до одного. Єдине, від чого залежить адрес обʼєкта, це його місце в ієрархії колекцій. Адреса залишиться статичною на весь час існування обʼєкта.
 :::

+ 2 - 2
docs/uk/manuals/introduction.md

@@ -20,13 +20,13 @@ Defold це рішення під ключ, яке надасть вам все
 ![Приклади](images/introduction/examples.jpg){.left} [Наша колекція простих прикладів](/examples/) допоможе розібратися як скласти із дрібних частин щось, що буде працювати. Ви знайдете невеликі приклади рішення різноманітих повсякденних задач у Defold.
 
 #### Мова Lua
-![Огляд Lua](images/introduction/lua.png){.left} [Defold використовує Lua](/manuals/lua/) для виконання всієї логіки. Двигун - швидкий механізм, написаний на C++, але на високому рівні він контролюється Lua сценаріями. Якщо ви раніше використовували Python, Javascript або іншу високорівневу мову, вам не складе труднощів зрозуміти Lua та слідувати інструкціям та урокам. В іншому випадку прочитайте наш our Lua посібник.
+![Огляд Lua](images/introduction/lua.png){.left} [Defold використовує Lua](/manuals/lua/) для виконання всієї логіки. Рушій - швидкий механізм, написаний на C++, але на високому рівні він контролюється Lua сценаріями. Якщо ви раніше використовували Python, Javascript або іншу високорівневу мову, вам не складе труднощів зрозуміти Lua та слідувати інструкціям та урокам. В іншому випадку прочитайте наш our Lua посібник.
 
 #### Уроки
 ![Уроки](images/introduction/tutorials.jpg){.left} Ми віримо що люди навчаються найкраще, роблячи. Тому прямо [в редакторі](/manuals/editor/) є набір уроків різної складності. Запускайте додаток та пройдіть один чи два уроки щоб розібратися як будувати проєкти та як працює Defold.
 
 #### Будівельні блоки Defold
-![Будівельні блоки](images/introduction/building_blocks.png){.left} [Defold ігри будуються компонуванням простих блоків](/manuals/building-blocks/), деякі з них здадуться знайомими якщо ви вже користувался іншими двигунами. Через деякі архітектурні рішення, Defold компоненти можуть здаватися незвичайними і вам знадобиться час щоб звикнути до них. Почніть з посібника по будівелним блокам, якщо вважаєте що вам потрібно ретельно розібратися як вони працюють.
+![Будівельні блоки](images/introduction/building_blocks.png){.left} [Defold ігри будуються компонуванням простих блоків](/manuals/building-blocks/), деякі з них здадуться знайомими якщо ви вже користувался іншими рушіями. Через деякі архітектурні рішення, Defold компоненти можуть здаватися незвичайними і вам знадобиться час щоб звикнути до них. Почніть з посібника по будівелним блокам, якщо вважаєте що вам потрібно ретельно розібратися як вони працюють.
 
 #### Форум
 ![Форум](images/introduction/forum.jpg){.left} [Навчання в інших](//forum.defold.com/) часто буде найкращим засобом вчитися. Наша спільнота дуже доброзичлива, має багато досвіду у будуванні ігор, зокрема за допомогою Defold. Якщо у вас виникнуть труднощі, не зволікайте та прямуйте на форум за допомогою!

+ 255 - 0
docs/uk/manuals/message-passing.md

@@ -0,0 +1,255 @@
+---
+title: Передавання повідомлень в Defold
+brief: Передавання повідомлень - це маханізм в Defold, який дозволяє спілкування між слабко повʼязаними обʼєктами. В цьому посібнику ми розглянемо цей механізм більш детально.
+---
+
+# Передавання повідомлень
+
+Передавання повідомлень - це механізм в Defold, який дозволяє ігровим обʼєктам спілкуватися одне з одним. В цьому посібнику передбачається що ви знайомі з [адресацією](/manuals/addressing) в Defold та [базовими будівельними блоками](/manuals/building-blocks).
+
+У Defold не використовується обʼєктно-орієнтований підхід у тому сенсі, що ваш додаток складається з ієрархій класів із успадкуванням та функціями-членами в ваших обʼєктах (як, наприклад, в Java, C++ або C#). Натомість Defold додає простий та потужний обʼєктно-орієнтований дизайн до Lua: стан обʼєкта зберігається внутрішньо в скриптах, доступний через посилання `self`. Крім того, обʼєкти можна відокремити одне від одного за допомогою відправлення асинхронних повідомлень в якості засоба комунікації між собою.
+
+
+## Приклади використання
+
+Перш за все, давайте подивимося на декілька прикладів використання. Уявіть, що ви будуєте гру, яка складається з:
+
+1. Головної стартової колекції, що містить ігровий обʼєкт з GUI компонентом (GUI складається з мінімапи та лічильника рахунку). А також колекції з ідентифікатором "level".
+2. Колекція "level" містить два ігрових обʼєкта: один персонаж героя гравця та один ворог.
+
+![Структура відправлення повідомлень](images/message_passing/message_passing_structure.png)
+
+::: sidenote
+Зміст цього прикладу знаходиться в двох окремих файлах. Один файл для головної стартової колекції, а другий - для колекції "level". Однак, імена файлів _не мають значення_ в Defold. Значення мають задані ідентифікатори.
+:::
+
+Гра складається з декількох простих механік, які потребують комунікацію між обʼєктами:
+
+![Відправлення повідомлень](images/message_passing/message_passing.png)
+
+① Герой бʼє ворога
+: В межах цієї механіки, повідомлення `"punch"` відправляється від скрипта, що належить "hero", до скрипта, що належить "enemy". Віддамо перевагу відносній адресації, тому що обидва обʼєкти знаходяться в одному місці в ієрархії колекції:
+
+  ```lua
+  -- Send "punch" from the "hero" script to "enemy" script
+  msg.post("enemy#controller", "punch")
+  ```
+
+  Всі удари в грі однієї сили, тому повідомлення не буде містити ніякої додаткової інформації окрім свого імені - "punch".
+
+  В скрипті, що належить ворогу (enemy), створимо функцію, щоб отримати повідомлення:
+
+  ```lua
+  function on_message(self, message_id, message, sender)
+    if message_id == hash("punch") then
+      self.health = self.health - 100
+    end
+  end
+  ```
+
+  В цьому випадку код дивиться лише на імʼя повідомлення (відправлене як хешований рядок в параметрі `message_id`). Код не піклується про дані повідомлення або відправника --- *будь-хто* може відправити повідомлення "punch" і нанести шкоду бідолашному ворогу.
+
+② Отримання балів героєм
+: Кожен раз, коли гравець долає ворога, рахунок гравця збільшується. Повідомлення `"update_score"` також відправляється від скрипта "hero" до компонента "gui", що належить ігровому обʼєкту "interface".
+
+  ```lua
+  -- Enemy defeated. Increase score counter by 100.
+  self.score = self.score + 100
+  msg.post("/interface#gui", "update_score", { score = self.score })
+  ```
+
+  Написати відносну адресу в цьому випадку неможливо, тому що "interface" знаходиться в корні ієрархії іменування, а "hero" - ні. Повідомлення відправляється GUI компоненту, до якого прикріплено скрипт, тому він може відреагувати на повідомлення відповідним чином. Повідомлення можна вільно відправляти між сриптами, GUI скриптами та рендер скриптами.
+
+  Повідомлення `"update_score"` містить дані про рахунок. Дані передаються як Lua таблиця в параметрі `message`:
+
+  ```lua
+  function on_message(self, message_id, message, sender)
+    if message_id == hash("update_score") then
+      -- set the score counter to new score
+      local score_node = gui.get_node("score")
+      gui.set_text(score_node, "SCORE: " .. message.score)
+    end
+  end
+  ```
+
+③ Позиція ворога на мінімапі
+: Гравець бачить мінімапу на екрані щоб знаходити та стежити за ворогами. Кожен ворог відповідає за трансляцію своєї позиції шляхом відправлення повідомлення `"update_minimap"` компоненту "gui" в ігровому обʼєкті "interface":
+
+  ```lua
+  -- Send the current position to update the interface minimap
+  local pos = go.get_position()
+  msg.post("/interface#gui", "update_minimap", { position = pos })
+  ```
+
+  Код GUI скрипту має стежити за позицією кожного ворога та, якщо один і той же ворог відправляє нову позицію, стара позиція має оновитись. Відправник повідомлення (параметр `sender`) може використовуватися як ключ для Lua таблиці з позиціями:
+
+  ```lua
+  function init(self)
+    self.minimap_positions = {}
+  end
+
+  local function update_minimap(self)
+    for url, pos in pairs(self.minimap_positions) do
+      -- update position on map
+      ...
+    end
+  end
+
+  function on_message(self, message_id, message, sender)
+    if message_id == hash("update_score") then
+      -- set the score counter to new score
+      local score_node = gui.get_node("score")
+      gui.set_text(score_node, "SCORE: " .. message.score)
+    elseif message_id == hash("update_minimap") then
+      -- update the minimap with new positions
+      self.minimap_positions[sender] = message.position
+      update_minimap(self)
+    end
+  end
+  ```
+
+## Відправлення повідомлень
+
+Як ми вже побачили, механіка відправлення повідомлень дуже проста. Вам достатньо викликати функцію `msg.post()`, яка відправляє ваше повідомлення в чергу повідомлень. Потім, кожен кадр, рушій обробляє чергу та доставляє кожне повідомлення по зазначеній адресі. Деякі системні повідомлення (наприклад, `"enable"`, `"disable"`, `"set_parent"` та ін.) обробляються кодом рушія. Сам рушій також створює деякі системні повідомлення для ваших обʼєктів (наприклад, `"collision_response"` під час фізичних колізій). Для обробки користувацьких повідомлень в компонентах-скриптах, рушій просто викликає спеціальну Defold Lua функцію `on_message()`.
+
+Ви можете відправляти будь-які повідомлення будь-якому існуючому обʼєкту або компоненту, і код отримувача вирішує чи відповідати на це повідомлення. Якщо ви відправили повідомленя, а скрипт отримувача проігнорував його, це нормально. Відповідальність за обробку повідомлень повністю лежить на стороні отримувача.
+
+Рушій перевірить адресу повідомлення. Якщо ви намагаєтесь відправити повідомлення невідомому отримувачу, Defold повідомить помилкою в консолі:
+
+```lua
+-- Try to post to a non existing object
+msg.post("dont_exist#script", "hello")
+```
+
+```txt
+ERROR:GAMEOBJECT: Instance '/dont_exists' could not be found when dispatching message 'hello' sent from main:/my_object#script
+```
+
+Повна сігнатура функції `msg.post()` така:
+
+`msg.post(receiver, message_id, [message])`
+
+receiver
+: Ідетифікатор цільового компонента або ігровго обʼєкта. Відмітьте, що повідомлення, відправлене ігровому обʼєкту, буде трансльоване всім компонентам цього обʼєкта.
+
+message_id
+: Рядок, або хеш рядка, з імʼям повідомлення.
+
+[message]
+: Необовʼязковий параметр, Lua таблиця, що містить дані повідомлення у вигляді пар ключ-значення. Майже будь-які дані можна включати в таблицю повідомлення. Ви можете передавати числа, рядки, булеві значення, URL-и, хеші і вкладені таблиці. Ви не можете передавати функції.
+
+  ```lua
+  -- Send table data containing a nested table
+  local inventory_table = { sword = true, shield = true, bow = true, arrows = 9 }
+  local stats = { score = 100, stars = 2, health = 4, inventory = inventory_table }
+  msg.post("other_object#script", "set_stats", stats)
+  ```
+
+::: sidenote
+Наразі параметр `message` суворо обмежений розміром у 2 кілобайти. Тривіального методу вимірювання розміру таблиці не існує, але ви можете скористатися `collectgarbage("count")` до та після додавання таблиці щоб відстежувати вживання памʼяті.
+:::
+
+### Скорочення
+
+Defold використовує два корисних скорочення, які можна використовувати для відправлення повідомлень без повного URL:
+
+:[Shorthands](../shared/url-shorthands.md)
+
+
+## Отримання повідомлень
+
+Отримання повідомлень полягає в забезпеченні цільового скрипта функцією `on_message()`. Вона отримує чотири аргументи:
+
+`function on_message(self, message_id, message, sender)`
+
+`self`
+: Посилання на сам скрипт.
+
+`message_id`
+: Містить _хешовану_ назву повідомлення.
+
+`message`
+: Містить дані повідомлення у вигляді Lua таблиці. Якщо даних немає, то таблиця буде пустою.
+
+`sender`
+: Містить повний URL відправника.
+
+```lua
+function on_message(self, message_id, message, sender)
+    print(message_id) --> hash: [my_message_name]
+
+    pprint(message) --> {
+                    -->   score = 100,
+                    -->   value = "some string"
+                    --> }
+
+    print(sender) --> url: [main:/my_object#script]
+end
+```
+
+## Спілкування між двома ігровими світами
+
+Якщо ви використовуєте компонент проксі колекції для завантаження нового нового світу в середовище виконання, вам може знадобитися відправляти повідомлення між світами. Наприклад, ви завантажили нову колекцію через проксі, а її властивість *Name* дорівнює "level":
+
+![Імʼя колекції](images/message_passing/collection_name.png)
+
+Як тільки колекцію було завантажено, ініціалізовано та активовано, ви можете відправляти повідомлення будь-яким компонентам та обʼєктам в новому світі. Для цього треба вказати імʼя ігрового світу в полі "socket" адреси отримувача:
+
+```lua
+-- Send a message to the player in the new game world
+msg.post("level:/player#controller", "wake_up")
+```
+
+Більш детальний опис того, як працюють проксі, можна подвитись в документації [проксі колекцій](/manuals/collection-proxy).
+
+## Ланцюги повідомлень
+
+Коли відправлене повідомлення дістається своєї мети, буде викликана функція отримувача `on_message()`. Часто буває так, що реагуючий код також створює нові повідомлення, які додаються до черги повідомлень.
+
+Коли рушій починає відправляти (dispatching) повідомлення, він проходиться по черзі повідомлень і викликає `on_message()` отримувача кожного повідомлення. Це продовжується поки черга повідомлень не спорожніє. Якщо після цього до черги були додані нові повідомлення, то рушій знов пройдеться по черзі. Але кількість спроб спутошити чергу повідомлень суворо обмежена. Що в свою чергу обмежує довжину ланцюгів повідомлень, які ми очікуємо встигнути повіністю обробити за поточний кадр. Наступний скрипт дозволяє протестувати скільки циклів відправки рушій виконує між кожним викликом `update()`:
+
+```lua
+function init(self)
+    -- We’re starting a long message chain during object init
+    -- and keeps it running through a number of update() steps.
+    print("INIT")
+    msg.post("#", "msg")
+    self.updates = 0
+    self.count = 0
+end
+
+function update(self, dt)
+    if self.updates < 5 then
+        self.updates = self.updates + 1
+        print("UPDATE " .. self.updates)
+        print(self.count .. " dispatch passes before this update.")
+        self.count = 0
+    end
+end
+
+function on_message(self, message_id, message, sender)
+    if message_id == hash("msg") then
+        self.count = self.count + 1
+        msg.post("#", "msg")
+    end
+end
+```
+
+Виконання цього скрипту видасть щось таке:
+
+```txt
+DEBUG:SCRIPT: INIT
+INFO:ENGINE: Defold Engine 1.2.36 (5b5af21)
+DEBUG:SCRIPT: UPDATE 1
+DEBUG:SCRIPT: 10 dispatch passes before this update.
+DEBUG:SCRIPT: UPDATE 2
+DEBUG:SCRIPT: 75 dispatch passes before this update.
+DEBUG:SCRIPT: UPDATE 3
+DEBUG:SCRIPT: 75 dispatch passes before this update.
+DEBUG:SCRIPT: UPDATE 4
+DEBUG:SCRIPT: 75 dispatch passes before this update.
+DEBUG:SCRIPT: UPDATE 5
+DEBUG:SCRIPT: 75 dispatch passes before this update.
+```
+
+Можемо побачити що ця версія рушія Defold виконує 10 проходів між викликом `init()` і першим викликом `update()`. Потім рушій виконує 75 проходів під час кожного оновлення.

+ 2 - 2
docs/uk/shared/components.md

@@ -1,4 +1,4 @@
-Компоненти надають виразливості та функціональності ігровим обʼєктам. Вони мають міститися всередині ігрових обʼєктів. Позиція, поворот та масштаб ігрового обʼєкту впливають на його компоненти:
+Компоненти надають виразливості та функціональності ігровим обʼєктам. Вони мають міститися всередині ігрових обʼєктів. Позиція, поворот та масштаб ігрового обʼєкта впливають на його компоненти:
 
 ![Компоненти](../shared/images/components.png){srcset="../shared/images/[email protected] 2x"}
 
@@ -16,7 +16,7 @@ sound.play("bean#hoohoo", { delay = 1, gain = 0.5 } )
 
 Клацніть <kbd>правою кнопкою</kbd> на ігровий обʼєкт у вікні *Структура (Outline)* та оберіть <kbd>Add Component</kbd> (додати на місці) або <kbd>Add Component File</kbd> (додати посилання на файл).
 
-Є сенс додавати більшість компонентів прямо на місці, але наступні компоненти мають бути створені в окремих файлах перш ніж бути доданими до ігрового обʼєкту:
+Є сенс додавати більшість компонентів прямо на місці, але наступні компоненти мають бути створені в окремих файлах перш ніж бути доданими до ігрового обʼєкта:
 
 * Сценарій (Script)
 * Графічний інтерфейс (GUI)

+ 17 - 0
docs/uk/shared/url-shorthands.md

@@ -0,0 +1,17 @@
+  `.`
+  : Скорочення для поточного ігрового обʼєкта.
+
+  `#`
+  : Скорочення для поточного компонента.
+
+  Наприклад:
+
+  ```lua
+   -- Let this game object acquire input focus
+   msg.post(".", "acquire_input_focus")
+  ```
+
+  ```lua
+   -- Post "reset" to the current script
+   msg.post("#", "reset")
+  ```