From c1b2a7a32ea390507e6310ce982298501ed9d644 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=9C=D0=B8=D1=85=D0=B0=D0=B8=D0=BB=20=D0=9A=D0=B0=D0=BF?=
=?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BA=D0=BE?=
Date: Wed, 19 Jan 2022 15:33:26 +0300
Subject: [PATCH] =?UTF-8?q?M-5.0=20+=20=D0=B4=D0=BE=D0=BA=D1=83=D0=BC?=
=?UTF-8?q?=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8=D1=8F=20=D1=81=D0=BE=D1=81?=
=?UTF-8?q?=D1=82=D0=BE=D1=8F=D0=BD=D0=B8=D0=B9?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
M/5.0/игра.html | 53 +++++
M/5.0/игра/050.Заголовок.js | 10 +
M/5.0/игра/070.Виды.js | 28 +++
M/5.0/игра/075.Анимация.js | 77 +++++++
M/5.0/игра/080.Анимации.js | 48 +++++
M/5.0/игра/100.Изображения.js | 183 +++++++++++++++++
M/5.0/игра/120.Физика.js | 28 +++
M/5.0/игра/140.Тела.js | 149 ++++++++++++++
M/5.0/игра/160.Слежение.js | 119 +++++++++++
M/5.0/игра/180.Объекты.js | 170 ++++++++++++++++
M/5.0/игра/190.Состояния.js | 31 +++
M/5.0/игра/220.Мышь.js | 16 ++
.../игра/240.Столкновения.js | 60 ++++++
M/5.0/игра/700.Игра.js | 100 +++++++++
M/5.0/игра/gr/100.grПодсказки.js | 58 ++++++
M/5.0/игра/gr/200.grМеню.js | 104 ++++++++++
M/5.0/игра/gr/300.grРеплики.js | 69 +++++++
M/5.0/игра/gr/400.grСцена.js | 190 ++++++++++++++++++
M/5.0/игра/matter-js | 1 +
M/5.0/игра/uikit | 1 +
M/5.0/общее/050.функции.js | 86 ++++++++
M/5.0/общее/100.События.js | 36 ++++
M/5.0/общее/150.Состояние.js | 72 +++++++
M/5.0/общее/200.обёртки.js | 4 +
M/5.0/общее/base64-js | 1 +
M/5.0/общее/pako | 1 +
M/5.0/редактор.html | 119 +++++++++++
.../редактор/100.Редактор.js | 127 ++++++++++++
M/5.0/редактор/200.Пульт.js | 53 +++++
M/5.0/редактор/700.Муром.js | 13 ++
M/5.0/редактор/ace | 1 +
M/5.0/редактор/uikit | 1 +
M/doc/ru/animations.html | 10 +-
M/doc/ru/animations.md | 6 +-
M/doc/ru/bodies.html | 8 +-
M/doc/ru/bodies.md | 4 +-
M/doc/ru/collisions.html | 6 +-
M/doc/ru/collisions.md | 2 +-
M/doc/ru/images.html | 8 +-
M/doc/ru/images.md | 4 +-
M/doc/ru/item.template | 4 +-
M/doc/ru/keys.html | 5 +-
M/doc/ru/keys.md | 2 +
M/doc/ru/objects.html | 6 +-
M/doc/ru/objects.md | 2 +-
M/doc/ru/physics.html | 6 +-
M/doc/ru/physics.md | 2 +-
M/doc/ru/states.html | 111 ++++++++++
M/doc/ru/states.md | 15 ++
M/doc/ru/styles.html | 6 +-
M/doc/ru/styles.md | 2 +-
M/doc/ru/title.html | 7 +-
M/doc/ru/title.md | 4 +-
M/doc/ru/tracking.html | 8 +-
M/doc/ru/tracking.md | 4 +-
M/index.html | 2 +-
56 files changed, 2191 insertions(+), 52 deletions(-)
create mode 100644 M/5.0/игра.html
create mode 100644 M/5.0/игра/050.Заголовок.js
create mode 100644 M/5.0/игра/070.Виды.js
create mode 100644 M/5.0/игра/075.Анимация.js
create mode 100644 M/5.0/игра/080.Анимации.js
create mode 100644 M/5.0/игра/100.Изображения.js
create mode 100644 M/5.0/игра/120.Физика.js
create mode 100644 M/5.0/игра/140.Тела.js
create mode 100644 M/5.0/игра/160.Слежение.js
create mode 100644 M/5.0/игра/180.Объекты.js
create mode 100644 M/5.0/игра/190.Состояния.js
create mode 100644 M/5.0/игра/220.Мышь.js
create mode 100644 M/5.0/игра/240.Столкновения.js
create mode 100644 M/5.0/игра/700.Игра.js
create mode 100644 M/5.0/игра/gr/100.grПодсказки.js
create mode 100644 M/5.0/игра/gr/200.grМеню.js
create mode 100644 M/5.0/игра/gr/300.grРеплики.js
create mode 100644 M/5.0/игра/gr/400.grСцена.js
create mode 120000 M/5.0/игра/matter-js
create mode 120000 M/5.0/игра/uikit
create mode 100644 M/5.0/общее/050.функции.js
create mode 100644 M/5.0/общее/100.События.js
create mode 100644 M/5.0/общее/150.Состояние.js
create mode 100644 M/5.0/общее/200.обёртки.js
create mode 120000 M/5.0/общее/base64-js
create mode 120000 M/5.0/общее/pako
create mode 100644 M/5.0/редактор.html
create mode 100644 M/5.0/редактор/100.Редактор.js
create mode 100644 M/5.0/редактор/200.Пульт.js
create mode 100644 M/5.0/редактор/700.Муром.js
create mode 120000 M/5.0/редактор/ace
create mode 120000 M/5.0/редактор/uikit
create mode 100644 M/doc/ru/states.html
create mode 100644 M/doc/ru/states.md
diff --git a/M/5.0/игра.html b/M/5.0/игра.html
new file mode 100644
index 0000000..507efc2
--- /dev/null
+++ b/M/5.0/игра.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/M/5.0/игра/050.Заголовок.js b/M/5.0/игра/050.Заголовок.js
new file mode 100644
index 0000000..2e47500
--- /dev/null
+++ b/M/5.0/игра/050.Заголовок.js
@@ -0,0 +1,10 @@
+function Заголовок()
+{
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (ключ == "заголовок")
+ {
+ document.title = значение;
+ }
+ }
+}
diff --git a/M/5.0/игра/070.Виды.js b/M/5.0/игра/070.Виды.js
new file mode 100644
index 0000000..c74121e
--- /dev/null
+++ b/M/5.0/игра/070.Виды.js
@@ -0,0 +1,28 @@
+function Виды(события)
+{
+ this.создать = function()
+ {
+ this.задано = {};
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] != "виды")
+ {
+ return;
+ }
+
+ let имя = путь[1];
+ let свойство = путь.slice(2).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+
+ события.уведомить(`виды/${имя}`);
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/075.Анимация.js b/M/5.0/игра/075.Анимация.js
new file mode 100644
index 0000000..774a6c8
--- /dev/null
+++ b/M/5.0/игра/075.Анимация.js
@@ -0,0 +1,77 @@
+function Анимация(элемент, параметры)
+{
+ this.запустить = function()
+ {
+ let п = параметры;
+ let воспроизведений = Number(п["воспроизведений"]);
+ let скорость = Number(п["скорость"]);
+ let к0 = Number(п["кадр.0"]);
+ let к1 = Number(п["кадр.1"]);
+ let д0 = Number(п["диапазон.0"]);
+ let д1 = Number(п["диапазон.1"]);
+ let д2 = Number(п["диапазон.2"]);
+ let д3 = Number(п["диапазон.3"]);
+
+ if (
+ воспроизведений == null ||
+ скорость == null ||
+ к0 == null ||
+ к1 == null ||
+ д0 == null ||
+ д1 == null ||
+ д2 == null ||
+ д3 == null
+ ) {
+ return;
+ }
+
+ let ширинаДиапазона = Math.abs(д2 - д0);
+ let высотаДиапазона = Math.abs(д3 - д1);
+ let ширинаКадра = Math.abs(к0);
+ let высотаКадра = Math.abs(к1);
+ let кадровПоГоризонтали = Math.floor(ширинаДиапазона / ширинаКадра);
+ let кадровПоВертикали = Math.floor(высотаДиапазона / высотаКадра);
+
+ this.номерВоспроизведения = 0;
+ this.колвоВоспроизведений = воспроизведений;
+ this.размерКадра = [к0, к1];
+ this.поГоризонтали = кадровПоГоризонтали > кадровПоВертикали;
+ this.номерКадра = 0;
+ this.колвоКадров = this.поГоризонтали ? кадровПоГоризонтали : кадровПоВертикали;
+ // Возможно, в будущем стоит заменить частные таймеры на один общий.
+ // Вдруг в браузерах есть ограничение на количество таймеров от одной страницы.
+ this.таймер = setInterval(() => { this.анимировать(); }, скорость);
+ };
+
+ this.остановить = function()
+ {
+ if (this.таймер)
+ {
+ clearInterval(this.таймер);
+ }
+ };
+
+ this.анимировать = function()
+ {
+ this.номерКадра += 1;
+ if (this.номерКадра >= this.колвоКадров)
+ {
+ this.номерВоспроизведения += 1;
+ this.номерКадра = 0;
+ if (
+ this.колвоВоспроизведений > 0 &&
+ this.номерВоспроизведения >= this.колвоВоспроизведений
+ ) {
+ this.остановить();
+ return;
+ }
+ }
+
+ let x = this.поГоризонтали ? this.номерКадра * this.размерКадра[0] : 0;
+ let y = this.поГоризонтали ? 0 : this.номерКадра * this.размерКадра[1];
+ элемент.style.backgroundPosition = `${x}px ${y}px`;
+ };
+
+ // Конструктор.
+ this.запустить();
+}
diff --git a/M/5.0/игра/080.Анимации.js b/M/5.0/игра/080.Анимации.js
new file mode 100644
index 0000000..0371978
--- /dev/null
+++ b/M/5.0/игра/080.Анимации.js
@@ -0,0 +1,48 @@
+function Анимации(события)
+{
+ this.создать = function()
+ {
+ this.задано = {};
+ this.анимации = {};
+ };
+
+ this.запустить = function(имя, элемент)
+ {
+ // Останавливаем прошлый экземпляр этой анимации на том же элементе.
+ this.остановить(имя, элемент);
+ // Запускаем новый экземпляр анимации на том же элементе.
+ let ключ = `${элемент.id}`;//-${имя}`;
+ this.анимации[ключ] = new Анимация(элемент, this.задано[имя]);
+ }
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] != "анимации")
+ {
+ return;
+ }
+
+ let имя = путь[1];
+ let свойство = путь.slice(2).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+
+ события.уведомить(`анимации/${имя}`);
+ };
+
+ this.остановить = function(имя, элемент)
+ {
+ let ключ = `${элемент.id}`;//-${имя}`;
+ if (ключ in this.анимации)
+ {
+ this.анимации[ключ].остановить();
+ delete this.анимации[ключ];
+ }
+ }
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/100.Изображения.js b/M/5.0/игра/100.Изображения.js
new file mode 100644
index 0000000..c32ab89
--- /dev/null
+++ b/M/5.0/игра/100.Изображения.js
@@ -0,0 +1,183 @@
+function Изображения(события, виды, анимации, корень)
+{
+ this.создать = function()
+ {
+ this.умолчание = {
+ пр: [0, 0, 100, 100],
+ угол: 0,
+ };
+ this.задано = {};
+ this.элементы = {};
+ события.подписать(this);
+ };
+
+ // Ключи и события.
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] == "изображения")
+ {
+ var имя = путь[1];
+ var свойство = путь.slice(2).join(".");
+ this.обновитьЭлемент(имя, свойство, значение);
+ }
+ };
+
+ this.обработатьСобытие = function(событие)
+ {
+ let в = "виды/";
+ let а = "анимации/";
+ if (событие.startsWith(в))
+ {
+ let вид = событие.substring(в.length);
+ this.обновитьЭлементыВида(вид);
+ }
+ else if (событие.startsWith(а))
+ {
+ let анимация = событие.substring(а.length);
+ this.обновитьЭлементыАнимации(анимация);
+ }
+ };
+
+ this.обновитьЭлементыАнимации = function(анимация)
+ {
+ for (let имя in this.задано)
+ {
+ let за = this.задано[имя];
+ let зан = за["анимация"];
+ if (зан && зан == анимация)
+ {
+ this.обновитьВидАнимацию(имя, за["вид"], за["анимация"]);
+ }
+ }
+ };
+
+ this.обновитьЭлементыВида = function(вид)
+ {
+ for (let имя in this.задано)
+ {
+ let за = this.задано[имя];
+ let заданныйВид = за["вид"];
+ if (заданныйВид && заданныйВид == вид)
+ {
+ this.обновитьВидАнимацию(имя, за["вид"], за["анимация"]);
+ }
+ }
+ };
+
+ // Без вида и анимации.
+
+ this.обновитьПозициюРазмерЭлемента = function(имя, эл)
+ {
+ let пр = this.пр(имя);
+ эл.style.left = `${пр[0]}px`;
+ эл.style.top = `${пр[1]}px`;
+ эл.style.width = `${пр[2]}px`;
+ эл.style.height = `${пр[3]}px`;
+ };
+
+ this.пр = function(имя)
+ {
+ let за = this.задано[имя];
+ let пр = this.умолчание.пр;
+ return [
+ за["пр.0"] ? за["пр.0"] : пр[0],
+ за["пр.1"] ? за["пр.1"] : пр[1],
+ за["пр.2"] ? за["пр.2"] : пр[2],
+ за["пр.3"] ? за["пр.3"] : пр[3],
+ ];
+ };
+
+ this.создатьИлиПолучитьЭлемент = function(имя)
+ {
+ var эл = this.элементы[имя];
+ if (эл)
+ {
+ return эл;
+ }
+
+ var ум = this.умолчание;
+ эл = document.createElement("div");
+ эл.id = `изображения-${имя}`;
+ эл.style.position = "absolute";
+ эл.style.display = "block";
+ // Свойства по умолчанию.
+ this.обновитьПозициюРазмерЭлемента(имя, эл);
+ эл.style.transform = `rotate(${ум.угол}rad)`;
+ this.элементы[имя] = эл;
+ корень.appendChild(эл);
+ return эл;
+ };
+
+ // Вид и анимация.
+
+ this.обновитьУгол = function(имя)
+ {
+ var за = this.задано[имя];
+ var ум = this.умолчание;
+ var эл = this.элементы[имя];
+
+ var угол = за.угол ? за.угол : ум.угол;
+ var transform = `rotate(${угол}deg) `;
+
+ let вид = за["вид"];
+ if (вид)
+ {
+ let виза = виды.задано[вид];
+ if (виза && виза["transform"])
+ {
+ transform += виза["transform"];
+ }
+ }
+
+ эл.style.transform = transform;
+ };
+
+
+ this.обновитьВидАнимацию = function(имя, вид, анимация)
+ {
+ var эл = this.создатьИлиПолучитьЭлемент(имя);
+
+ if (вид)
+ {
+ let за = виды.задано[вид];
+ for (let параметр in за)
+ {
+ эл.style.setProperty(параметр, за[параметр]);
+ }
+ }
+
+ if (анимация)
+ {
+ анимации.запустить(анимация, эл);
+ }
+
+ this.обновитьУгол(имя);
+ };
+
+ this.обновитьЭлемент = function(имя, свойство, значение)
+ {
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+ var за = this.задано[имя];
+ var эл = this.создатьИлиПолучитьЭлемент(имя);
+
+ if (свойство.startsWith("пр"))
+ {
+ this.обновитьПозициюРазмерЭлемента(имя, эл);
+ }
+ else if (
+ (свойство == "угол") ||
+ (свойство == "вид") ||
+ (свойство == "анимация")
+ ) {
+ this.обновитьВидАнимацию(имя, за["вид"], за["анимация"]);
+ }
+ };
+
+ // Конструктор.
+ this.создать();
+}
diff --git a/M/5.0/игра/120.Физика.js b/M/5.0/игра/120.Физика.js
new file mode 100644
index 0000000..d75fc12
--- /dev/null
+++ b/M/5.0/игра/120.Физика.js
@@ -0,0 +1,28 @@
+function Физика(события)
+{
+ this.создать = function()
+ {
+ this.задано = {};
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] != "физика")
+ {
+ return;
+ }
+
+ let имя = путь[1];
+ let свойство = путь.slice(2).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+
+ события.уведомить(`физика/${имя}`);
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/140.Тела.js b/M/5.0/игра/140.Тела.js
new file mode 100644
index 0000000..2e9a330
--- /dev/null
+++ b/M/5.0/игра/140.Тела.js
@@ -0,0 +1,149 @@
+function Тела(события, физика, физмир)
+{
+ this.создать = function()
+ {
+ this.умолчание = {
+ пр: [0, 0, 40, 20],
+ части: [],
+ часть: false,
+ };
+
+ this.задано = {};
+ this.тела = {};
+ this.имена = {};
+ события.подписать(this);
+ };
+
+ this.именаЧастей = function(за)
+ {
+ var имена = [];
+ for (var ключ in за)
+ {
+ if (ключ.startsWith("части"))
+ {
+ имена.push(за[ключ]);
+ }
+ }
+ return имена;
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] != "тела")
+ {
+ return;
+ }
+
+ var имя = путь[1];
+ var свойство = путь.slice(2).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+
+ this.пересоздатьТело(имя);
+ };
+
+ this.обработатьСобытие = function(событие)
+ {
+ let префикс = "физика/";
+ if (событие.startsWith(префикс))
+ {
+ let физ = событие.substring(префикс.length);
+ this.пересоздатьТелаФизики(физ);
+ }
+ };
+
+ this.пересоздатьТелаФизики = function(физ)
+ {
+ for (let имя in this.задано)
+ {
+ let заданнаяФизика = this.задано[имя]["физика"];
+ if (заданнаяФизика && заданнаяФизика == физ)
+ {
+ this.пересоздатьТело(имя);
+ }
+ }
+ };
+
+ this.пересоздатьТело = function(имя)
+ {
+ // Удаляем старое тело.
+ if (имя in this.тела)
+ {
+ var тело = this.тела[имя];
+ delete this.имена[тело.id];
+ // Всегда удаляем из мира: и составные, и несоставные тела.
+ Matter.Composite.remove(физмир, тело);
+ }
+
+ var за = this.задано[имя];
+ var ум = this.умолчание;
+ let пр = this.пр(имя);
+ // Переводим x,y из левого верхнего угла в центр.
+ пр[0] = пр[0] + пр[2] / 2.0;
+ пр[1] = пр[1] + пр[3] / 2.0;
+ // Параметры тела.
+ var параметры = {};
+ if (за.физика)
+ {
+ let заф = физика.задано[за.физика];
+ for (let параметр in заф)
+ {
+ мир.задатьПолныйКлюч(параметры, параметр, заф[параметр]);
+ }
+ }
+
+ var тело = null;
+ // Создаём новое составное тело.
+ if (за["части.0"])
+ {
+ параметры["parts"] = this.телаЧастей(this.именаЧастей(за));
+ тело = Matter.Body.create(параметры);
+ }
+ // Создаём новое несоставное тело.
+ // Вполне может быть частью другого составного тела.
+ else
+ {
+ тело = Matter.Bodies.rectangle(пр[0], пр[1], пр[2], пр[3], параметры);
+ }
+ this.тела[имя] = тело;
+ this.имена[тело.id] = имя;
+
+ // Добавляем тело в физический мир, если оно не является частью другого составного тела.
+ var часть = за.часть ? за.часть : ум.часть;
+ if (!часть)
+ {
+ Matter.Composite.add(физмир, тело);
+ }
+ };
+
+ this.пр = function(имя)
+ {
+ let за = this.задано[имя];
+ let пр = this.умолчание.пр;
+ return [
+ за["пр.0"] ? за["пр.0"] : пр[0],
+ за["пр.1"] ? за["пр.1"] : пр[1],
+ за["пр.2"] ? за["пр.2"] : пр[2],
+ за["пр.3"] ? за["пр.3"] : пр[3],
+ ];
+ };
+
+ this.телаЧастей = function(имена)
+ {
+ var тела = [];
+ for (var н in имена)
+ {
+ var имя = имена[н];
+ var тело = this.тела[имя];
+ тела.push(тело);
+ }
+ return тела;
+ };
+
+ // Конструктор.
+ this.создать();
+}
+
diff --git a/M/5.0/игра/160.Слежение.js b/M/5.0/игра/160.Слежение.js
new file mode 100644
index 0000000..ca538f0
--- /dev/null
+++ b/M/5.0/игра/160.Слежение.js
@@ -0,0 +1,119 @@
+function Слежение(состояние, изображения, тела)
+{
+ this.создать = function()
+ {
+ this.умолчание = {
+ смещение: [0, 0],
+ скорость: 1,
+ предел: 0,
+ };
+ this.задано = {};
+ };
+
+ this.обновить = function()
+ {
+ for (var имя in this.задано)
+ {
+ this.расположитьИзображение(имя);
+ }
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] != "слежение")
+ {
+ return;
+ }
+
+ var имя = путь[1];
+ var свойство = путь.slice(2).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+ };
+
+ this.расположитьИзображение = function(имя)
+ {
+ let за = this.задано[имя];
+ let тело = тела.тела[за.тело];
+ let элемент = изображения.элементы[за.изображение];
+ if (!тело || !элемент)
+ {
+ return;
+ }
+
+ let ум = this.умолчание;
+
+ // Параметры.
+ var скорость = за.скорость ? за.скорость : ум.скорость;
+ var смещениеX = за["смещение.0"] ? за["смещение.0"] : ум.смещение[0];
+ var смещениеY = за["смещение.1"] ? за["смещение.1"] : ум.смещение[1];
+ var предел = за.предел ? за.предел : ум.предел;
+
+ // Текущая позиция.
+ var x0 = 0;
+ if (элемент.dataset.слежениеX)
+ {
+ x0 = элемент.dataset.слежениеX;
+ }
+ var y0 = 0;
+ if (элемент.dataset.слежениеY)
+ {
+ y0 = элемент.dataset.слежениеY;
+ }
+
+ // Целевая позиция.
+ var x1 = тело.position.x + смещениеX;
+ var y1 = тело.position.y + смещениеY;
+ // Radians -> Degrees.
+ var угол = тело.angle * 180 / Math.PI;
+
+ // Устанавливаемая плавно позиция.
+ var x = this.lerp(x0, x1, скорость, предел);
+ var y = this.lerp(y0, y1, скорость, предел);
+
+ // Ничего не делаем, если разница ничтожна.
+ let ничтожно = 0.00001;
+ if (
+ элемент.dataset.слежениеX != null &&
+ элемент.dataset.слежениеY != null &&
+ элемент.dataset.слежениеУгол != null &&
+ Math.abs(элемент.dataset.слежениеX - x) < ничтожно &&
+ Math.abs(элемент.dataset.слежениеY - y) < ничтожно &&
+ Math.abs(элемент.dataset.слежениеУгол - угол) < ничтожно
+ ) {
+ return;
+ }
+
+ // Иначе применяем новые значения.
+ элемент.dataset.слежениеX = x;
+ элемент.dataset.слежениеY = y;
+ элемент.dataset.слежениеУгол = угол;
+ var описание = {
+ пр: [x, y],
+ угол: угол,
+ };
+ состояние.разобратьЛишьНовое({
+ изображения: {
+ [за.изображение]: описание,
+ },
+ });
+ };
+
+ this.lerp = function(v0, v1, t, предел) {
+ // Убираем мельтешение в случае наличия предела.
+ if (предел)
+ {
+ var delta = Math.abs(v0 - v1);
+ if (delta < предел) {
+ return v0;
+ }
+ }
+ return v0 * (1 - t) + v1 * t;
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/180.Объекты.js b/M/5.0/игра/180.Объекты.js
new file mode 100644
index 0000000..83e5e62
--- /dev/null
+++ b/M/5.0/игра/180.Объекты.js
@@ -0,0 +1,170 @@
+function Объекты(состояние, события)
+{
+ this.создать = function()
+ {
+ this.умолчание = {
+ пр: [0, 0, 40, 20],
+ };
+ this.задано = {};
+ события.подписать(this);
+ };
+
+ // Ключи и события.
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] != "объекты")
+ {
+ return;
+ }
+
+ let имя = путь[1];
+ let свойство = путь.slice(2).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+
+ let производноеИмя = `объекты-${имя}`;
+
+ if (свойство.startsWith("пр."))
+ {
+ let пр = this.пр(имя);
+ this.обновитьПозициюРазмер(производноеИмя, пр);
+ this.обновитьСлежение(производноеИмя, пр);
+ let вид = this.задано[имя]["вид"];
+ let анимация = this.задано[имя]["анимация"];
+ this.обновитьИзображение(производноеИмя, пр, вид, анимация);
+ }
+ else if (свойство == "физика")
+ {
+ this.обновитьФизику(производноеИмя, значение);
+ }
+ else if (
+ свойство == "вид" ||
+ свойство == "анимация"
+ ) {
+ let вид = this.задано[имя]["вид"];
+ let анимация = this.задано[имя]["анимация"];
+ this.обновитьИзображение(производноеИмя, null, вид, анимация);
+ }
+ };
+
+ this.обработатьСобытие = function(событие)
+ {
+ let в = "виды/";
+ let а = "анимации/";
+ if (событие.startsWith(в))
+ {
+ let вид = событие.substring(в.length);
+ this.обновитьОбъектыВида(вид);
+ }
+ else if (событие.startsWith(а))
+ {
+ let анимация = событие.substring(а.length);
+ this.обновитьОбъектыАнимации(анимация);
+ }
+ };
+
+ this.обновитьОбъектыАнимации = function(анимация)
+ {
+ for (let имя in this.задано)
+ {
+ let за = this.задано[имя];
+ let зан = за["анимация"];
+ if (зан && зан == анимация)
+ {
+ this.обновитьВидАнимацию(имя);
+ }
+ }
+ };
+
+ this.обновитьОбъектыВида = function(вид)
+ {
+ for (let имя in this.задано)
+ {
+ let за = this.задано[имя];
+ let зви = за["вид"];
+ if (зви && зви == вид)
+ {
+ this.обновитьВидАнимацию(имя);
+ }
+ }
+ };
+
+ this.обновитьВидАнимацию = function(имя)
+ {
+ let вид = this.задано[имя]["вид"];
+ let анимация = this.задано[имя]["анимация"];
+ let производноеИмя = `объекты-${имя}`;
+ this.обновитьИзображение(производноеИмя, null, вид, анимация);
+ };
+
+ this.обновитьИзображение = function(имя, пр, вид, анимация)
+ {
+ var описание = {
+ вид: вид,
+ анимация: анимация,
+ };
+ if (пр)
+ {
+ описание["пр"] = пр;
+ }
+ состояние.разобрать({
+ изображения: {
+ [имя]: описание,
+ },
+ });
+ };
+
+ this.обновитьПозициюРазмер = function(имя, пр)
+ {
+ состояние.разобрать({
+ тела: {
+ [имя]: {
+ пр: пр,
+ },
+ },
+ });
+ };
+
+ this.обновитьСлежение = function(имя, пр)
+ {
+ состояние.разобрать({
+ слежение: {
+ [имя]: {
+ изображение: имя,
+ тело: имя,
+ смещение: [-пр[2] / 2, -пр[3] / 2],
+ },
+ },
+ });
+ };
+
+ this.обновитьФизику = function(имя, значение)
+ {
+ состояние.разобрать({
+ тела: {
+ [имя]: {
+ физика: значение,
+ },
+ },
+ });
+ };
+
+ this.пр = function(имя)
+ {
+ let за = this.задано[имя];
+ let пр = this.умолчание.пр;
+ return [
+ за["пр.0"] ? за["пр.0"] : пр[0],
+ за["пр.1"] ? за["пр.1"] : пр[1],
+ за["пр.2"] ? за["пр.2"] : пр[2],
+ за["пр.3"] ? за["пр.3"] : пр[3],
+ ];
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/190.Состояния.js b/M/5.0/игра/190.Состояния.js
new file mode 100644
index 0000000..114c423
--- /dev/null
+++ b/M/5.0/игра/190.Состояния.js
@@ -0,0 +1,31 @@
+function Состояния(состояние)
+{
+ this.создать = function()
+ {
+ this.задано = {};
+ };
+
+ this.применить = function(имя)
+ {
+ состояние.разобратьВыпрямленный(this.задано[имя]);
+ }
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] != "состояния")
+ {
+ return;
+ }
+
+ let имя = путь[1];
+ let свойство = путь.slice(2).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/220.Мышь.js b/M/5.0/игра/220.Мышь.js
new file mode 100644
index 0000000..cd73551
--- /dev/null
+++ b/M/5.0/игра/220.Мышь.js
@@ -0,0 +1,16 @@
+function Мышь(события)
+{
+ this.создать = function()
+ {
+ window.addEventListener("click", function(o) {
+ события.уведомить(`мышь/нажатие/${o.clientX}/${o.clientY}/${o.target.id}`);
+ });
+ window.addEventListener("mousemove", function(o) {
+ события.уведомить(`мышь/перемещение/${o.clientX}/${o.clientY}/${o.target.id}`);
+ });
+ };
+
+ // Конструктор.
+ this.создать();
+};
+
diff --git a/M/5.0/игра/240.Столкновения.js b/M/5.0/игра/240.Столкновения.js
new file mode 100644
index 0000000..69d1f5d
--- /dev/null
+++ b/M/5.0/игра/240.Столкновения.js
@@ -0,0 +1,60 @@
+function Столкновения(события, тела, физдвижок)
+{
+ this.создать = function()
+ {
+ this.задано = {};
+ Matter.Events.on(
+ физдвижок,
+ "collisionActive",
+ (событие) => { this.обработатьСтолкновение(событие) }
+ );
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (путь[0] != "столкновения")
+ {
+ return;
+ }
+
+ let имя = путь[1];
+ let свойство = путь.slice(2).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+ };
+
+ this.обработатьСтолкновение = function(событие)
+ {
+ for (var имя in this.задано)
+ {
+ var ст = this.задано[имя];
+ var имя1 = ст["тела.0"];
+ var имя2 = ст["тела.1"];
+ if (!имя1 || !имя2 || !ст.событие)
+ {
+ continue;
+ }
+
+ var пары = событие.pairs;
+ for (var номер in пары)
+ {
+ var пара = пары[номер];
+ var п1 = тела.имена[пара.bodyA.id];
+ var п2 = тела.имена[пара.bodyB.id];
+ if (
+ !((имя1 == п1) && (имя2 == п2)) &&
+ !((имя1 == п2) && (имя2 == п1))
+ ) {
+ continue;
+ }
+ мир.события.уведомить(ст.событие);
+ }
+ }
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/700.Игра.js b/M/5.0/игра/700.Игра.js
new file mode 100644
index 0000000..9e31fe5
--- /dev/null
+++ b/M/5.0/игра/700.Игра.js
@@ -0,0 +1,100 @@
+function Игра()
+{
+ this.создать = function()
+ {
+ мир.физдвижок = Matter.Engine.create({
+ enableSleeping: true,
+ gravity: {
+ y: 2,
+ },
+ });
+ var корень = document.getElementById("корень");
+ мир.события = new События(мир.uuid);
+ мир.состояние = new Состояние();
+ мир.состояние.обработчик = (к, п, з) => { this.обработатьКлюч(к, п, з) };
+ мир.виды = new Виды(мир.события);
+ мир.анимации = new Анимации(мир.события);
+ мир.изображения = new Изображения(мир.события, мир.виды, мир.анимации, корень),
+ мир.физика = new Физика(мир.события);
+ мир.тела = new Тела(мир.события, мир.физика, мир.физдвижок.world);
+ мир.слежение = new Слежение(мир.состояние, мир.изображения, мир.тела);
+ мир.объекты = new Объекты(мир.состояние, мир.события);
+ мир.состояниЯ = new Состояния(мир.состояние);
+ мир.мышь = new Мышь(мир.события);
+ мир.столкновения = new Столкновения(мир.события, мир.тела, мир.физдвижок);
+
+ this.ключники = [
+ new Заголовок(),
+ мир.виды,
+ мир.анимации,
+ мир.изображения,
+ мир.физика,
+ мир.тела,
+ мир.слежение,
+ мир.объекты,
+ мир.состояниЯ,
+ мир.столкновения,
+ ];
+
+ this.настроитьКлючиGR()
+
+ var z64 = мир.параметрыЗапуска()["z64"];
+ this.исполнитьКод(z64);
+ this.отслеживатьОбновленияКода();
+ this.обновить();
+ };
+
+ this.исполнитьКод = function(z64)
+ {
+ if (z64)
+ {
+ var код = мир.изZ64(z64);
+ eval(код);
+ }
+ };
+
+ this.настроитьКлючиGR = function()
+ {
+ let адресИгры = window.location.pathname + "/../игра.html?z64=";
+ мир.grСцена = new grСцена(мир.состояние, мир.состояниЯ, мир.события, мир.тела, адресИгры);
+ this.ключники.push(мир.grСцена);
+ мир.grПодсказки = new grПодсказки();
+ this.ключники.push(мир.grПодсказки);
+ мир.grРеплики = new grРеплики(мир.события);
+ this.ключники.push(мир.grРеплики);
+ мир.grМеню = new grМеню(мир.события, мир.grПодсказки, мир.grРеплики);
+ }
+
+ this.обновить = function()
+ {
+ Matter.Engine.update(мир.физдвижок);
+ мир.слежение.обновить();
+
+ мир.grСцена.обновить();
+
+ var тут = this;
+ requestAnimationFrame(function() {
+ тут.обновить();
+ });
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ for (var номер in this.ключники)
+ {
+ var ключник = this.ключники[номер];
+ ключник.обработатьКлюч(ключ, путь, значение);
+ }
+ };
+
+ this.отслеживатьОбновленияКода = function()
+ {
+ var тут = this;
+ window.addEventListener("message", function(событие) {
+ тут.исполнитьКод(событие.data);
+ });
+ };
+
+ // Конструктор.
+ this.создать();
+}
diff --git a/M/5.0/игра/gr/100.grПодсказки.js b/M/5.0/игра/gr/100.grПодсказки.js
new file mode 100644
index 0000000..3f63825
--- /dev/null
+++ b/M/5.0/игра/gr/100.grПодсказки.js
@@ -0,0 +1,58 @@
+function grПодсказки()
+{
+ this.создать = function()
+ {
+ this.задано = {};
+ };
+
+ this.задатьПодсказку = function(имя)
+ {
+ let за = this.задано[имя];
+ if (!за.элемент || !за.текст)
+ {
+ return;
+ }
+
+ let элемент = document.getElementById(за.элемент);
+ if (!элемент)
+ {
+ return;
+ }
+
+ элемент.setAttribute("uk-tooltip", `pos: right; title: ${за.текст}`);
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (!ключ.startsWith("gr.подсказки"))
+ {
+ return;
+ }
+
+ let имя = путь[2];
+ let свойство = путь.slice(3).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+
+ this.задатьПодсказку(имя);
+ };
+
+ this.подсказкаДляЭлемента = function(элемент)
+ {
+ for (var имя in this.задано)
+ {
+ let подсказка = this.задано[имя];
+ if (подсказка.элемент == элемент)
+ {
+ return имя;
+ }
+ }
+ return null;
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/gr/200.grМеню.js b/M/5.0/игра/gr/200.grМеню.js
new file mode 100644
index 0000000..6982b30
--- /dev/null
+++ b/M/5.0/игра/gr/200.grМеню.js
@@ -0,0 +1,104 @@
+function grМеню(события, подсказки, реплики)
+{
+ this.создать = function()
+ {
+ события.подписать(this);
+ this.установитьМеню();
+ this.улавливатьВыбор();
+ };
+
+ this.обработатьСобытие = function(событие)
+ {
+ let мышь = "мышь/нажатие/";
+ let сами = "меню/";
+ if (событие.startsWith(мышь))
+ {
+ let значения = событие.substring(мышь.length).split("/");
+ let элемент = значения[2];
+ let имя = подсказки.подсказкаДляЭлемента(элемент);
+ if (имя && имя in реплики.задано)
+ {
+ this.отобразитьМеню(имя);
+ }
+ }
+ else if (событие.startsWith(сами))
+ {
+ UIkit.modal("#меню").hide();
+ }
+ };
+
+ this.отобразитьМеню = function(имя)
+ {
+ this.активнаяПодсказка = имя;
+ let подсказка = подсказки.задано[имя];
+ document.getElementById("меню-заголовок").innerHTML = подсказка.текст;
+ UIkit.modal("#меню").show();
+ };
+
+ this.улавливатьВыбор = function()
+ {
+ var тут = this;
+ let глаз = document.getElementById("меню-кнопка-глаз");
+ глаз.addEventListener(
+ "click",
+ function() {
+ события.уведомить(`меню/глаз/${тут.активнаяПодсказка}`);
+ }
+ );
+
+ let рука = document.getElementById("меню-кнопка-рука");
+ рука.addEventListener(
+ "click",
+ function() {
+ события.уведомить(`меню/рука/${тут.активнаяПодсказка}`);
+ }
+ );
+
+ let рот = document.getElementById("меню-кнопка-рот");
+ рот.addEventListener(
+ "click",
+ function() {
+ события.уведомить(`меню/рот/${тут.активнаяПодсказка}`);
+ }
+ );
+
+ let нога = document.getElementById("меню-кнопка-нога");
+ нога.addEventListener(
+ "click",
+ function() {
+ события.уведомить(`меню/нога/${тут.активнаяПодсказка}`);
+ }
+ );
+ };
+
+ this.установитьМеню = function()
+ {
+ let html = `
+
+ `;
+ document.body.insertAdjacentHTML("beforeend", html);
+ };
+
+ // Конструктор.
+ this.создать();
+};
+
diff --git a/M/5.0/игра/gr/300.grРеплики.js b/M/5.0/игра/gr/300.grРеплики.js
new file mode 100644
index 0000000..128f537
--- /dev/null
+++ b/M/5.0/игра/gr/300.grРеплики.js
@@ -0,0 +1,69 @@
+function grРеплики(события)
+{
+ this.создать = function()
+ {
+ this.задано = {};
+ события.подписать(this);
+ };
+
+ this.номерРеплики = function(инструмент)
+ {
+ if (инструмент == "рука")
+ {
+ return 1;
+ }
+ else if (инструмент == "рот")
+ {
+ return 2;
+ }
+ else if (инструмент == "нога")
+ {
+ return 3;
+ }
+ // "глаз"
+ return 0;
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (!ключ.startsWith("gr.реплики"))
+ {
+ return;
+ }
+
+ let имя = путь[2];
+ let свойство = путь.slice(3).join(".");
+ if (!this.задано[имя])
+ {
+ this.задано[имя] = {};
+ }
+ this.задано[имя][свойство] = значение;
+ };
+
+ this.обработатьСобытие = function(событие)
+ {
+ let меню = "меню/";
+ if (событие.startsWith(меню))
+ {
+ let значения = событие.substring(меню.length).split("/");
+ let инструмент = значения[0];
+ let подсказка = значения[1];
+ this.отобразитьРеплику(инструмент, подсказка);
+ }
+ };
+
+ this.отобразитьРеплику = function(инструмент, подсказка)
+ {
+ let номер = this.номерРеплики(инструмент);
+ let реплика = this.задано[подсказка][номер];
+ let частей = реплика.split(/ /);
+ let длительность = частей.length * 1000;
+ UIkit.notification({
+ message: реплика,
+ timeout: длительность,
+ });
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/gr/400.grСцена.js b/M/5.0/игра/gr/400.grСцена.js
new file mode 100644
index 0000000..b595589
--- /dev/null
+++ b/M/5.0/игра/gr/400.grСцена.js
@@ -0,0 +1,190 @@
+function grСцена(состояние, состояниЯ, события, тела, адресИгры)
+{
+ this.создать = function()
+ {
+ this.задано = {};
+ this.сцены = null;
+ this.состояниеИгрока = null;
+ события.подписать(this);
+ };
+
+ this.загрузитьСцену = function(имя)
+ {
+ let z64 = this.сцены[имя];
+ window.location = адресИгры + z64;
+ };
+
+ this.загрузитьОглавление = function(адрес)
+ {
+ var тут = this;
+ var запрос = new XMLHttpRequest();
+ запрос.onreadystatechange = function()
+ {
+ if (this.readyState == 4)
+ {
+ if (this.status == 200)
+ {
+ тут.разобратьОглавление(this.responseText);
+ }
+ else
+ {
+ console.error("Не удалось загрузить оглавление сцен:", this.status);
+ }
+ }
+ }
+ запрос.open("GET", адрес);
+ запрос.send();
+ };
+
+ this.задатьСостояниеИгрока = function(идёт, направление)
+ {
+ let стоятьЛ = this.задано["игрок.стоять.0"];
+ let стоятьП = this.задано["игрок.стоять.1"];
+ let идтиЛ = this.задано["игрок.идти.0"];
+ let идтиП = this.задано["игрок.идти.1"];
+ if (!стоятьЛ || !стоятьП || !идтиЛ || !идтиП)
+ {
+ return;
+ }
+
+ var название = идтиЛ;
+ if (идёт && направление > 0)
+ {
+ название = идтиП;
+ }
+ else if (!идёт && направление < 0)
+ {
+ название = стоятьЛ;
+ }
+ else if (!идёт && направление > 0)
+ {
+ название = стоятьП;
+ }
+
+ if (this.состояниеИгрока != название)
+ {
+ состояниЯ.применить(название);
+ this.состояниеИгрока = название;
+ }
+ };
+
+ this.обновить = function()
+ {
+ this.переместитьИгрока();
+ };
+
+ this.обработатьКлюч = function(ключ, путь, значение)
+ {
+ if (!ключ.startsWith("gr.сцена"))
+ {
+ return;
+ }
+
+ var свойство = путь.slice(2).join(".");
+ this.задано[свойство] = значение;
+ if (свойство == "оглавление")
+ {
+ this.загрузитьОглавление(значение);
+ }
+ };
+
+ this.обработатьНажатиеМышиУказатьИНажать = function(x, y, указатель)
+ {
+ let цель = this.задано["цель"];
+ if (!this.типИгрыУказатьИНажать() || !цель)
+ {
+ return;
+ }
+ let тело = тела.тела[цель];
+ if (!тело)
+ {
+ return;
+ }
+
+ var пр = [
+ тело.bounds.min.x,
+ тело.bounds.min.y,
+ тело.bounds.max.x - тело.bounds.min.x,
+ тело.bounds.max.y - тело.bounds.min.y,
+ ]
+ let ширина = пр[2];
+ пр[0] = x - ширина;
+
+ состояние.разобрать({
+ тела: {
+ [цель]: {
+ пр: пр,
+ },
+ },
+ });
+ };
+
+ this.обработатьСобытие = function(событие)
+ {
+ let мышь = "мышь/нажатие/";
+ let сцена = "сцена/";
+ if (событие.startsWith(мышь))
+ {
+ let значения = событие.substring(мышь.length).split("/");
+ let x = Number(значения[0]);
+ let y = Number(значения[1]);
+ let указатель = значения[2];
+ this.обработатьНажатиеМышиУказатьИНажать(x, y, указатель);
+ }
+ else if (событие.startsWith(сцена))
+ {
+ let название = событие.substring(сцена.length);
+ this.загрузитьСцену(название);
+ }
+ };
+
+ this.переместитьИгрока = function()
+ {
+ let цель = this.задано["цель"];
+ let объект = this.задано["игрок.объект"];
+ let скоростьX = this.задано["игрок.скорость.0"];
+ if (!this.типИгрыУказатьИНажать() || !цель || !объект || !скоростьX)
+ {
+ return;
+ }
+
+ let игрок = `объекты-${объект}`;
+ let телоЦели = тела.тела[цель];
+ let телоИгрока = тела.тела[игрок];
+ if (!телоЦели || !телоИгрока)
+ {
+ return;
+ }
+
+ let игрокX = телоИгрока.position.x;
+ let цельX = телоЦели.position.x;
+ let ширина = телоЦели.bounds.max.x - телоЦели.bounds.min.x;
+ let расстояние = цельX - игрокX;
+ let направление = расстояние > 0 ? 1 : -1;
+
+ if (Math.abs(расстояние) < ширина / 2)
+ {
+ this.задатьСостояниеИгрока(false, направление);
+ return;
+ }
+
+ this.задатьСостояниеИгрока(true, направление);
+ Matter.Sleeping.set(телоИгрока, false);
+ Matter.Body.setVelocity(телоИгрока, { x: скоростьX * направление, y: 0 });
+ };
+
+ this.разобратьОглавление = function(содержимое)
+ {
+ let код = "this.сцены = " + содержимое;
+ eval(код);
+ };
+
+ this.типИгрыУказатьИНажать = function()
+ {
+ var тип = this.задано["тип"];
+ return тип && тип == "указать и нажать";
+ };
+
+ // Конструктор.
+ this.создать();
+};
diff --git a/M/5.0/игра/matter-js b/M/5.0/игра/matter-js
new file mode 120000
index 0000000..3a19a2e
--- /dev/null
+++ b/M/5.0/игра/matter-js
@@ -0,0 +1 @@
+../../стороннее/matter-js
\ No newline at end of file
diff --git a/M/5.0/игра/uikit b/M/5.0/игра/uikit
new file mode 120000
index 0000000..d60f2bc
--- /dev/null
+++ b/M/5.0/игра/uikit
@@ -0,0 +1 @@
+../../стороннее/uikit
\ No newline at end of file
diff --git a/M/5.0/общее/050.функции.js b/M/5.0/общее/050.функции.js
new file mode 100644
index 0000000..0798274
--- /dev/null
+++ b/M/5.0/общее/050.функции.js
@@ -0,0 +1,86 @@
+var мир = {};
+
+мир.uuid = function()
+{
+ // https://stackoverflow.com/a/2117523
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
+ /[xy]/g,
+ function(c)
+ {
+ var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
+ return v.toString(16);
+ }
+ );
+};
+
+мир.вZ64 = function(строка)
+{
+ var байты = new TextEncoder("utf-8").encode(строка);
+ var архив = pako.deflate(байты, { to: 'string' });
+ return base64js.fromByteArray(архив);
+};
+
+мир.изZ64 = function(строка)
+{
+ var архив = base64js.toByteArray(строка);
+ var байты = pako.inflate(архив);
+ return new TextDecoder("utf-8").decode(байты);
+};
+
+мир.задатьПолныйКлюч = function(словарь, полныйКлюч, значение) {
+ var путь = полныйКлюч.split(".");
+ var пройти = путь.length - 1;
+ var вложенность = словарь;
+ for (var номер = 0; номер < пройти; ++номер)
+ {
+ var ключ = путь[номер];
+ if (!(ключ in вложенность))
+ {
+ вложенность[ключ] = {};
+ вложенность = вложенность[ключ];
+ }
+ }
+ // Значение в конце вложенности.
+ var ключ = путь[пройти];
+ вложенность[ключ] = значение;
+};
+
+мир.назначитьКнопкамСобытия = function(события, список)
+{
+ for (var номер in список)
+ {
+ const пара = список[номер];
+ var кнопка = document.getElementById(пара[0]);
+ кнопка.addEventListener("click", function(_) {
+ события.уведомить(пара[1]);
+ });
+ }
+};
+
+мир.параметрыЗапуска = function()
+{
+ var параметры = {};
+ var запрос = window.location.search.substring(1);
+ var аргументы = запрос.split("&");
+ for (var номер in аргументы)
+ {
+ var арг = аргументы[номер];
+ var позицияЗнака = арг.indexOf("=");
+ // Лишь ключ.
+ if (позицияЗнака == -1)
+ {
+ var ключ = decodeURIComponent(арг);
+ параметры[ключ] = null;
+ }
+ // Ключ со значением.
+ else
+ {
+ var сыройКлюч = арг.slice(0, позицияЗнака);
+ var сыроеЗначение = арг.slice(позицияЗнака + 1);
+ var ключ = decodeURIComponent(сыройКлюч);
+ var значение = decodeURIComponent(сыроеЗначение);
+ параметры[ключ] = значение;
+ }
+ }
+ return параметры;
+};
diff --git a/M/5.0/общее/100.События.js b/M/5.0/общее/100.События.js
new file mode 100644
index 0000000..abd6710
--- /dev/null
+++ b/M/5.0/общее/100.События.js
@@ -0,0 +1,36 @@
+function События(uuid)
+{
+ this.создать = function()
+ {
+ this.обработчики = [];
+ this.обработчики = {};
+ };
+
+ this.подписать = function(обработчик, имя)
+ {
+ let указатель = имя || uuid();
+ this.обработчики[указатель] = обработчик;
+ };
+
+ this.отписать = function(обработчик) {
+ for (var указатель in this.обработчики) {
+ let обр = this.обработчики[указатель];
+ if (обр == обработчик)
+ {
+ delete this.обработчики[указатель];
+ return;
+ }
+ }
+ };
+
+ this.уведомить = function(событие) {
+ for (var номер in this.обработчики)
+ {
+ var обработчик = this.обработчики[номер];
+ обработчик.обработатьСобытие(событие);
+ }
+ };
+
+ // Конструктор.
+ this.создать();
+}
diff --git a/M/5.0/общее/150.Состояние.js b/M/5.0/общее/150.Состояние.js
new file mode 100644
index 0000000..d0db466
--- /dev/null
+++ b/M/5.0/общее/150.Состояние.js
@@ -0,0 +1,72 @@
+function Состояние()
+{
+ this.создать = function()
+ {
+ this.обработчик = null;
+ this.значения = {};
+ };
+
+ this.выпрямить = function(obj)
+ {
+ // https://stackoverflow.com/a/42121920
+ var newObj = {};
+ for (var key in obj)
+ {
+ if (typeof obj[key] === 'object' && obj[key] !== null)
+ {
+ var temp = this.выпрямить(obj[key])
+ for (var key2 in temp)
+ {
+ newObj[key + "." + key2] = temp[key2];
+ }
+ }
+ else
+ {
+ newObj[key] = obj[key];
+ }
+ }
+ return newObj;
+ };
+
+ this.лишьНовыеЗначения = function(значения)
+ {
+ var новые = {};
+ for (var ключ in значения)
+ {
+ var было = this.значения[ключ];
+ var стало = значения[ключ];
+ if (!(было != null && было == стало))
+ {
+ новые[ключ] = стало;
+ }
+ }
+ return новые;
+ };
+
+ this.разобрать = function(словарь)
+ {
+ this.разобратьВыпрямленный(this.выпрямить(словарь));
+ };
+
+ this.разобратьВыпрямленный = function(выпрямленныйСловарь)
+ {
+ for (var ключ in выпрямленныйСловарь)
+ {
+ let путь = ключ.split(".");
+ let значение = выпрямленныйСловарь[ключ];
+ if (this.обработчик)
+ {
+ this.обработчик(ключ, путь, значение);
+ }
+ this.значения[ключ] = значение;
+ }
+ };
+
+ this.разобратьЛишьНовое = function(словарь)
+ {
+ this.разобратьВыпрямленный(this.лишьНовыеЗначения(this.выпрямить(словарь)));
+ };
+
+ // Конструктор.
+ this.создать();
+}
diff --git a/M/5.0/общее/200.обёртки.js b/M/5.0/общее/200.обёртки.js
new file mode 100644
index 0000000..cb6eba0
--- /dev/null
+++ b/M/5.0/общее/200.обёртки.js
@@ -0,0 +1,4 @@
+мир.разобрать = function(словарь)
+{
+ мир.состояние.разобратьЛишьНовое(словарь);
+};
diff --git a/M/5.0/общее/base64-js b/M/5.0/общее/base64-js
new file mode 120000
index 0000000..a3367c1
--- /dev/null
+++ b/M/5.0/общее/base64-js
@@ -0,0 +1 @@
+../../стороннее/base64-js
\ No newline at end of file
diff --git a/M/5.0/общее/pako b/M/5.0/общее/pako
new file mode 120000
index 0000000..504d162
--- /dev/null
+++ b/M/5.0/общее/pako
@@ -0,0 +1 @@
+../../стороннее/pako
\ No newline at end of file
diff --git a/M/5.0/редактор.html b/M/5.0/редактор.html
new file mode 100644
index 0000000..c5a9501
--- /dev/null
+++ b/M/5.0/редактор.html
@@ -0,0 +1,119 @@
+
+
+
+
+ M-5.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 5.0
+ мир.разобрать, мир.события.подписать, gr.подсказки, gr.реплики, gr.сцена
+
+
+ 4.1
+ анимации, подсказки, реплики, состояния, столкновения, сцена
+
+
+ 4.0
+ виды, физика; переработанные объекты, изображения, тела
+
+
+ 3.5
+ объекты
+
+
+ 3.4
+ Документация
+
+
+ 3.3
+ тела, слежение
+
+
+ 3.2
+ мир.параметрыЗапуска, мир.разобрать, заголовок, изображения, состояние, физика
+
+
+ 3.1
+ Кнопки перезапуска, копирования ссылки, запуска в отдельной вкладке
+
+
+ 3.0
+ Проверка введённого кода на отсутствие синтаксических ошибок
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/M/5.0/редактор/100.Редактор.js b/M/5.0/редактор/100.Редактор.js
new file mode 100644
index 0000000..430d3a8
--- /dev/null
+++ b/M/5.0/редактор/100.Редактор.js
@@ -0,0 +1,127 @@
+function Редактор(события, имяРедактора)
+{
+ this.создать = function()
+ {
+ this.первоначальныйЗаголовок = document.title;
+ this.установитьAce();
+ this.улавливатьЗавершениеРедактирования();
+ this.задатьКодПриЗапуске();
+ события.подписать(this);
+ };
+
+ this.задатьКодПриЗапуске = function()
+ {
+ var z64 = мир.параметрыЗапуска()["z64"];
+ if (z64)
+ {
+ var код = мир.изZ64(z64);
+ this.ace.session.setValue(код);
+ }
+ };
+
+ this.запуститьОтдельно = function()
+ {
+ var содержимое = this.ace.session.getValue();
+ var z64 = мир.вZ64(содержимое);
+ var путь = window.location.pathname + "/../игра.html?z64=" + z64;
+ window.open(путь);
+ };
+
+ this.исполнитьКод = function()
+ {
+ var содержимое = this.ace.session.getValue();
+ var z64 = мир.вZ64(содержимое);
+ // Исполняем явно код лишь первый раз.
+ var проигрыватель = document.getElementById("проигрыватель");
+ if (!проигрыватель.src)
+ {
+ проигрыватель.src = "игра.html?z64=" + z64;
+ }
+ // После запуска уведомляем iframe о новом коде без перезагрузки.
+ else
+ {
+ window.frames.проигрыватель.postMessage(z64, "*");
+ }
+ };
+
+ this.обновитьАдреснуюСтрокуИЗаголовок = function()
+ {
+ var содержимое = this.ace.session.getValue();
+ var z64 = мир.вZ64(содержимое);
+ var путь = window.location.pathname + "?z64=" + z64;
+ history.pushState(null, "", путь);
+ document.title = `${this.первоначальныйЗаголовок} ${z64.length}:${z64.slice(z64.length - 5)}`;
+ };
+
+ this.обработатьСобытие = function(событие)
+ {
+ if (событие == "завершили редактирование")
+ {
+ this.обновитьАдреснуюСтрокуИЗаголовок();
+ this.проверитьКорректностьКода();
+ }
+ else if (событие == "код корректен")
+ {
+ this.исполнитьКод();
+ }
+ else if (событие == "перезапустить")
+ {
+ this.перезапуститьКод();
+ }
+ else if (событие == "запустить отдельно")
+ {
+ this.запуститьОтдельно();
+ }
+ };
+
+ this.перезапуститьКод = function()
+ {
+ var содержимое = this.ace.session.getValue();
+ var z64 = мир.вZ64(содержимое);
+ var проигрыватель = document.getElementById("проигрыватель");
+ проигрыватель.src = "игра.html?z64=" + z64;
+ };
+
+ this.проверитьКорректностьКода = function()
+ {
+ try
+ {
+ eval(this.ace.session.getValue());
+ события.уведомить("код корректен");
+ }
+ catch (ошибка)
+ {
+ события.уведомить("код некорректен");
+ }
+ };
+
+ this.улавливатьЗавершениеРедактирования = function()
+ {
+ var тут = this;
+ this.ace.session.on("change", function(дельта) {
+ const билет = мир.uuid();
+ тут.билет = билет;
+ setTimeout(
+ function()
+ {
+ if (билет == тут.билет)
+ {
+ события.уведомить("завершили редактирование");
+ }
+ },
+ 300
+ );
+ });
+ };
+
+ this.установитьAce = function()
+ {
+ var область = document.getElementById(имяРедактора);
+ this.ace = window.ace.edit(имяРедактора);
+ this.ace.session.setMode("ace/mode/javascript");
+ this.ace.session.setUseWrapMode(true);
+ };
+
+ // Конструктор.
+ this.создать();
+}
diff --git a/M/5.0/редактор/200.Пульт.js b/M/5.0/редактор/200.Пульт.js
new file mode 100644
index 0000000..42889e5
--- /dev/null
+++ b/M/5.0/редактор/200.Пульт.js
@@ -0,0 +1,53 @@
+function Пульт(события, имяОшибки, имяПерезапуска, имяОтдельно, имяСсылки, имяДокументации)
+{
+ this.создать = function()
+ {
+ var ошибка = document.getElementById(имяОшибки);
+ мир.назначитьКнопкамСобытия(
+ события,
+ [
+ [имяПерезапуска, "перезапустить"],
+ [имяОтдельно, "запустить отдельно"],
+ [имяСсылки, "скопировать ссылку"],
+ [имяДокументации, "открыть документацию"],
+ ]
+ );
+ события.подписать(this);
+ };
+
+ this.обработатьСобытие = function(событие)
+ {
+ if (событие == "код корректен")
+ {
+ this.показатьОшибку(false);
+ }
+ else if (событие == "код некорректен")
+ {
+ this.показатьОшибку(true);
+ }
+ else if (событие == "скопировать ссылку")
+ {
+ navigator.clipboard.writeText(window.location)
+ .then(() => {
+ UIkit.notification("Скопировали ссылку", { status: "success", timeout: 1000 });
+ })
+ .catch(err => {
+ UIkit.notification("Не удалось скопировать ссылку :(", { status: "danger", timeout: 5000 });
+ });
+ }
+ else if (событие == "открыть документацию")
+ {
+ var путь = window.location.pathname + "/../../doc/ru/index.html";
+ window.open(путь);
+ }
+ };
+
+
+ this.показатьОшибку = function(показать)
+ {
+ ошибка.innerHTML = показать ? " " : " ";
+ };
+
+ // Конструктор.
+ this.создать();
+}
diff --git a/M/5.0/редактор/700.Муром.js b/M/5.0/редактор/700.Муром.js
new file mode 100644
index 0000000..2321260
--- /dev/null
+++ b/M/5.0/редактор/700.Муром.js
@@ -0,0 +1,13 @@
+function Муром()
+{
+ this.создать = function()
+ {
+ мир.события = new События(мир.uuid);
+ мир.состояние = new Состояние();
+ мир.редактор = new Редактор(мир.события, "редактор");
+ мир.пульт = new Пульт(мир.события, "ошибка", "перезапустить", "отдельно", "ссылка", "документация");
+ };
+
+ // Конструктор.
+ this.создать();
+}
diff --git a/M/5.0/редактор/ace b/M/5.0/редактор/ace
new file mode 120000
index 0000000..0190be9
--- /dev/null
+++ b/M/5.0/редактор/ace
@@ -0,0 +1 @@
+../../стороннее/ace
\ No newline at end of file
diff --git a/M/5.0/редактор/uikit b/M/5.0/редактор/uikit
new file mode 120000
index 0000000..d60f2bc
--- /dev/null
+++ b/M/5.0/редактор/uikit
@@ -0,0 +1 @@
+../../стороннее/uikit
\ No newline at end of file
diff --git a/M/doc/ru/animations.html b/M/doc/ru/animations.html
index 4f74cdc..bdfa106 100644
--- a/M/doc/ru/animations.html
+++ b/M/doc/ru/animations.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -102,13 +102,13 @@
Пример № 1. Отображение бесконечной анимации на основе вертикальных кадров.
-
+
Пример № 2. Отображение конечной анимации.
-
+
Пример № 3. Отображение анимации на объекте.
-
+
diff --git a/M/doc/ru/animations.md b/M/doc/ru/animations.md
index e90cf20..1730455 100644
--- a/M/doc/ru/animations.md
+++ b/M/doc/ru/animations.md
@@ -13,19 +13,19 @@ Lang: ru
Пример № 1. Отображение бесконечной анимации на основе вертикальных кадров.
-
+
Пример № 2. Отображение конечной анимации.
-
+
Пример № 3. Отображение анимации на объекте.
-
+
diff --git a/M/doc/ru/bodies.html b/M/doc/ru/bodies.html
index d3b3a56..f391beb 100644
--- a/M/doc/ru/bodies.html
+++ b/M/doc/ru/bodies.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -98,12 +98,12 @@
Тело представляет из себя сущность Matter.js с полной поддержкой свойств, которые можно указывать телам в Matter.js.
Пример № 1. Отображение статичной платформы и падающего на неё самовара.
-
+
Пример № 2. Составное тело с сенсором и статичная платформа.
ВНИМАНИЕ : на текущий момент слежение некорректно отрабатывает для составных объектов,
т.к. сенсор должен находиться строго под основанием самовара.
-
+
diff --git a/M/doc/ru/bodies.md b/M/doc/ru/bodies.md
index 1463009..4bc5cff 100644
--- a/M/doc/ru/bodies.md
+++ b/M/doc/ru/bodies.md
@@ -12,7 +12,7 @@ Lang: ru
Пример № 1. Отображение статичной платформы и падающего на неё самовара.
-
+
@@ -21,7 +21,7 @@ Lang: ru
**ВНИМАНИЕ**: на текущий момент слежение некорректно отрабатывает для составных объектов,
т.к. сенсор должен находиться строго под основанием самовара.
-
+
diff --git a/M/doc/ru/collisions.html b/M/doc/ru/collisions.html
index 961c8eb..5c3d1eb 100644
--- a/M/doc/ru/collisions.html
+++ b/M/doc/ru/collisions.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -97,7 +97,7 @@
Определение столкновения двух физических тел с последующей отправкой события.
Пример № 1. Отображение факта столкновения кирпича с землёй с помощью встроенной библиотеки UIkit .
-
+
diff --git a/M/doc/ru/collisions.md b/M/doc/ru/collisions.md
index 7fd6d36..9e9d8a2 100644
--- a/M/doc/ru/collisions.md
+++ b/M/doc/ru/collisions.md
@@ -10,7 +10,7 @@ Lang: ru
Пример № 1. Отображение факта столкновения кирпича с землёй с помощью встроенной библиотеки [UIkit][uikit].
-
+
diff --git a/M/doc/ru/images.html b/M/doc/ru/images.html
index 85c4fd5..f5bc581 100644
--- a/M/doc/ru/images.html
+++ b/M/doc/ru/images.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -99,10 +99,10 @@
Изображение представляет из себя отдельный <div>
, который можно исследовать в отладке браузера.
Пример № 1. Отображение статичного изображения под углом.
-
+
Пример № 2. Отображение статичной платформы и падающего на неё самовара.
-
+
diff --git a/M/doc/ru/images.md b/M/doc/ru/images.md
index efc36e8..3d17f8b 100644
--- a/M/doc/ru/images.md
+++ b/M/doc/ru/images.md
@@ -14,13 +14,13 @@ Lang: ru
Пример № 1. Отображение статичного изображения под углом.
-
+
Пример № 2. Отображение статичной платформы и падающего на неё самовара.
-
+
diff --git a/M/doc/ru/item.template b/M/doc/ru/item.template
index 060f4d2..85d6ed3 100644
--- a/M/doc/ru/item.template
+++ b/M/doc/ru/item.template
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
diff --git a/M/doc/ru/keys.html b/M/doc/ru/keys.html
index 0fe4d97..e00a391 100644
--- a/M/doc/ru/keys.html
+++ b/M/doc/ru/keys.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -103,6 +103,7 @@
изображения
объекты
слежение
+состояния
столкновения
тела
физика
diff --git a/M/doc/ru/keys.md b/M/doc/ru/keys.md
index 5269358..9e4141b 100644
--- a/M/doc/ru/keys.md
+++ b/M/doc/ru/keys.md
@@ -13,6 +13,7 @@ Lang: ru
1. [изображения][images]
1. [объекты][objects]
1. [слежение][tracking]
+1. [состояния][states]
1. [столкновения][collisions]
1. [тела][bodies]
1. [физика][physics]
@@ -23,6 +24,7 @@ Lang: ru
[images]: images.html
[objects]: objects.html
[physics]: physics.html
+[states]: states.html
[styles]: styles.html
[title]: title.html
[tracking]: tracking.html
diff --git a/M/doc/ru/objects.html b/M/doc/ru/objects.html
index 86b2a2a..bcf4bba 100644
--- a/M/doc/ru/objects.html
+++ b/M/doc/ru/objects.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -97,7 +97,7 @@
Добавление одного или нескольких объектов, которые представляют собой комбинацию изображения , тела и их синхронизацию через слежение .
Пример № 1. Отображение двух падающих на платформу пауков.
-
+
diff --git a/M/doc/ru/objects.md b/M/doc/ru/objects.md
index 8296acb..28e6956 100644
--- a/M/doc/ru/objects.md
+++ b/M/doc/ru/objects.md
@@ -10,7 +10,7 @@ Lang: ru
Пример № 1. Отображение двух падающих на платформу пауков.
-
+
diff --git a/M/doc/ru/physics.html b/M/doc/ru/physics.html
index 96df468..731bfc2 100644
--- a/M/doc/ru/physics.html
+++ b/M/doc/ru/physics.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -97,7 +97,7 @@
Задание одного или нескольких настроек физики Matter.js, которые будут применяться для конкретного тела или объекта .
Пример № 1. Маски столкновений.
-
+
diff --git a/M/doc/ru/physics.md b/M/doc/ru/physics.md
index 12bba81..f1cb492 100644
--- a/M/doc/ru/physics.md
+++ b/M/doc/ru/physics.md
@@ -10,7 +10,7 @@ Lang: ru
Пример № 1. Маски столкновений.
-
+
diff --git a/M/doc/ru/states.html b/M/doc/ru/states.html
new file mode 100644
index 0000000..164673a
--- /dev/null
+++ b/M/doc/ru/states.html
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+ Документация МУРОМа 5.0
+
+
+
+
+
+
+состояния
+
+
+
+
+
Задание и применение различных состояний.
+
+
Пример № 1. Возвращение кирпича в начальное положение после столкновения с землёй.
+
+
+
+
+
+
+
+
diff --git a/M/doc/ru/states.md b/M/doc/ru/states.md
new file mode 100644
index 0000000..2a68b6d
--- /dev/null
+++ b/M/doc/ru/states.md
@@ -0,0 +1,15 @@
+Title: состояния
+Date: 2022-01-17 00:00
+Category: Страница
+Slug: states
+Lang: ru
+
+Задание и применение различных состояний.
+
+
+
+Пример № 1. Возвращение кирпича в начальное положение после столкновения с землёй.
+
+
+
+
diff --git a/M/doc/ru/styles.html b/M/doc/ru/styles.html
index 5e5f2e6..0782246 100644
--- a/M/doc/ru/styles.html
+++ b/M/doc/ru/styles.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -97,7 +97,7 @@
Задание одного или нескольких стилей CSS, которые будут применяться для конкретного изображения или объекта .
Пример № 1. Задание стилей для изображения и объекта.
-
+
diff --git a/M/doc/ru/styles.md b/M/doc/ru/styles.md
index 381087b..8efae65 100644
--- a/M/doc/ru/styles.md
+++ b/M/doc/ru/styles.md
@@ -10,7 +10,7 @@ Lang: ru
Пример № 1. Задание стилей для изображения и объекта.
-
+
diff --git a/M/doc/ru/title.html b/M/doc/ru/title.html
index f7c2301..43d1268 100644
--- a/M/doc/ru/title.html
+++ b/M/doc/ru/title.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -101,8 +101,9 @@
заголовок: "Колобок",
});
-Посмотреть результат .
+Посмотреть результат
+[result]:
-[result]: ../../3.4/игра.html?z64=eJy7sOfCjosNehcbLmy4sP3CvgsbQayLTRd7NKq5FIAAKLjhwmagxG4g3gTEu6wUlC7MggpsBAko6XDValoDAL+VLNM=
+[result]:
diff --git a/M/doc/ru/tracking.html b/M/doc/ru/tracking.html
index 7d88784..172758a 100644
--- a/M/doc/ru/tracking.html
+++ b/M/doc/ru/tracking.html
@@ -78,12 +78,12 @@
}
- Документация МУРОМа 4.1
+ Документация МУРОМа 5.0
@@ -98,10 +98,10 @@
ВНИМАНИЕ : на текущий момент некорректно работает с составными телами: не учитывается вращение частей.
Пример № 1. Мгновенное следование изображения за телом.
-
+
Пример № 2. Замедленное следование изображения за телом со смещением и пределом для ограничения мельтешения.
-
+
diff --git a/M/doc/ru/tracking.md b/M/doc/ru/tracking.md
index 3729f7a..2281fee 100644
--- a/M/doc/ru/tracking.md
+++ b/M/doc/ru/tracking.md
@@ -12,13 +12,13 @@ Lang: ru
Пример № 1. Мгновенное следование изображения за телом.
-
+
Пример № 2. Замедленное следование изображения за телом со смещением и пределом для ограничения мельтешения.
-
+
diff --git a/M/index.html b/M/index.html
index 451da8c..15f6d7e 100644
--- a/M/index.html
+++ b/M/index.html
@@ -1,4 +1,4 @@
-
+