From c7cf5cc0b1417d52eb9e1c5185fd86d0f361a5eb 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: Tue, 22 Mar 2022 14:31:55 +0300 Subject: [PATCH] M-5.1 --- M/5.1/игра.html | 54 +++++ M/5.1/игра/050.Заголовок.js | 10 + M/5.1/игра/070.Виды.js | 28 +++ M/5.1/игра/075.Анимация.js | 77 +++++++ M/5.1/игра/080.Анимации.js | 48 +++++ M/5.1/игра/100.Изображения.js | 183 +++++++++++++++++ M/5.1/игра/120.Физика.js | 28 +++ M/5.1/игра/140.Тела.js | 149 ++++++++++++++ M/5.1/игра/160.Слежение.js | 119 +++++++++++ M/5.1/игра/180.Объекты.js | 170 ++++++++++++++++ M/5.1/игра/190.Состояния.js | 31 +++ M/5.1/игра/220.Мышь.js | 16 ++ .../игра/240.Столкновения.js | 60 ++++++ M/5.1/игра/700.Игра.js | 100 +++++++++ M/5.1/игра/gr/100.grПодсказки.js | 58 ++++++ M/5.1/игра/gr/200.grМеню.js | 104 ++++++++++ M/5.1/игра/gr/300.grРеплики.js | 69 +++++++ M/5.1/игра/gr/400.grСцена.js | 190 ++++++++++++++++++ M/5.1/игра/matter-js | 1 + M/5.1/игра/uikit | 1 + M/5.1/общее/050.функции.js | 86 ++++++++ M/5.1/общее/100.События.js | 36 ++++ M/5.1/общее/150.Состояние.js | 72 +++++++ M/5.1/общее/200.обёртки.js | 4 + M/5.1/общее/base64-js | 1 + M/5.1/общее/pako | 1 + M/5.1/редактор.html | 123 ++++++++++++ .../редактор/100.Редактор.js | 127 ++++++++++++ M/5.1/редактор/200.Пульт.js | 53 +++++ M/5.1/редактор/700.Муром.js | 13 ++ M/5.1/редактор/ace | 1 + M/5.1/редактор/uikit | 1 + M/index.html | 2 +- 33 files changed, 2015 insertions(+), 1 deletion(-) create mode 100644 M/5.1/игра.html create mode 100644 M/5.1/игра/050.Заголовок.js create mode 100644 M/5.1/игра/070.Виды.js create mode 100644 M/5.1/игра/075.Анимация.js create mode 100644 M/5.1/игра/080.Анимации.js create mode 100644 M/5.1/игра/100.Изображения.js create mode 100644 M/5.1/игра/120.Физика.js create mode 100644 M/5.1/игра/140.Тела.js create mode 100644 M/5.1/игра/160.Слежение.js create mode 100644 M/5.1/игра/180.Объекты.js create mode 100644 M/5.1/игра/190.Состояния.js create mode 100644 M/5.1/игра/220.Мышь.js create mode 100644 M/5.1/игра/240.Столкновения.js create mode 100644 M/5.1/игра/700.Игра.js create mode 100644 M/5.1/игра/gr/100.grПодсказки.js create mode 100644 M/5.1/игра/gr/200.grМеню.js create mode 100644 M/5.1/игра/gr/300.grРеплики.js create mode 100644 M/5.1/игра/gr/400.grСцена.js create mode 120000 M/5.1/игра/matter-js create mode 120000 M/5.1/игра/uikit create mode 100644 M/5.1/общее/050.функции.js create mode 100644 M/5.1/общее/100.События.js create mode 100644 M/5.1/общее/150.Состояние.js create mode 100644 M/5.1/общее/200.обёртки.js create mode 120000 M/5.1/общее/base64-js create mode 120000 M/5.1/общее/pako create mode 100644 M/5.1/редактор.html create mode 100644 M/5.1/редактор/100.Редактор.js create mode 100644 M/5.1/редактор/200.Пульт.js create mode 100644 M/5.1/редактор/700.Муром.js create mode 120000 M/5.1/редактор/ace create mode 120000 M/5.1/редактор/uikit diff --git a/M/5.1/игра.html b/M/5.1/игра.html new file mode 100644 index 0000000..d30a491 --- /dev/null +++ b/M/5.1/игра.html @@ -0,0 +1,54 @@ + + + + + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/M/5.1/игра/050.Заголовок.js b/M/5.1/игра/050.Заголовок.js new file mode 100644 index 0000000..2e47500 --- /dev/null +++ b/M/5.1/игра/050.Заголовок.js @@ -0,0 +1,10 @@ +function Заголовок() +{ + this.обработатьКлюч = function(ключ, путь, значение) + { + if (ключ == "заголовок") + { + document.title = значение; + } + } +} diff --git a/M/5.1/игра/070.Виды.js b/M/5.1/игра/070.Виды.js new file mode 100644 index 0000000..c74121e --- /dev/null +++ b/M/5.1/игра/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.1/игра/075.Анимация.js b/M/5.1/игра/075.Анимация.js new file mode 100644 index 0000000..774a6c8 --- /dev/null +++ b/M/5.1/игра/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.1/игра/080.Анимации.js b/M/5.1/игра/080.Анимации.js new file mode 100644 index 0000000..0371978 --- /dev/null +++ b/M/5.1/игра/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.1/игра/100.Изображения.js b/M/5.1/игра/100.Изображения.js new file mode 100644 index 0000000..c32ab89 --- /dev/null +++ b/M/5.1/игра/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.1/игра/120.Физика.js b/M/5.1/игра/120.Физика.js new file mode 100644 index 0000000..d75fc12 --- /dev/null +++ b/M/5.1/игра/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.1/игра/140.Тела.js b/M/5.1/игра/140.Тела.js new file mode 100644 index 0000000..2e9a330 --- /dev/null +++ b/M/5.1/игра/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.1/игра/160.Слежение.js b/M/5.1/игра/160.Слежение.js new file mode 100644 index 0000000..ca538f0 --- /dev/null +++ b/M/5.1/игра/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.1/игра/180.Объекты.js b/M/5.1/игра/180.Объекты.js new file mode 100644 index 0000000..83e5e62 --- /dev/null +++ b/M/5.1/игра/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.1/игра/190.Состояния.js b/M/5.1/игра/190.Состояния.js new file mode 100644 index 0000000..114c423 --- /dev/null +++ b/M/5.1/игра/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.1/игра/220.Мышь.js b/M/5.1/игра/220.Мышь.js new file mode 100644 index 0000000..cd73551 --- /dev/null +++ b/M/5.1/игра/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.1/игра/240.Столкновения.js b/M/5.1/игра/240.Столкновения.js new file mode 100644 index 0000000..69d1f5d --- /dev/null +++ b/M/5.1/игра/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.1/игра/700.Игра.js b/M/5.1/игра/700.Игра.js new file mode 100644 index 0000000..9e31fe5 --- /dev/null +++ b/M/5.1/игра/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.1/игра/gr/100.grПодсказки.js b/M/5.1/игра/gr/100.grПодсказки.js new file mode 100644 index 0000000..3f63825 --- /dev/null +++ b/M/5.1/игра/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.1/игра/gr/200.grМеню.js b/M/5.1/игра/gr/200.grМеню.js new file mode 100644 index 0000000..6982b30 --- /dev/null +++ b/M/5.1/игра/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.1/игра/gr/300.grРеплики.js b/M/5.1/игра/gr/300.grРеплики.js new file mode 100644 index 0000000..128f537 --- /dev/null +++ b/M/5.1/игра/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.1/игра/gr/400.grСцена.js b/M/5.1/игра/gr/400.grСцена.js new file mode 100644 index 0000000..b595589 --- /dev/null +++ b/M/5.1/игра/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.1/игра/matter-js b/M/5.1/игра/matter-js new file mode 120000 index 0000000..3a19a2e --- /dev/null +++ b/M/5.1/игра/matter-js @@ -0,0 +1 @@ +../../стороннее/matter-js \ No newline at end of file diff --git a/M/5.1/игра/uikit b/M/5.1/игра/uikit new file mode 120000 index 0000000..d60f2bc --- /dev/null +++ b/M/5.1/игра/uikit @@ -0,0 +1 @@ +../../стороннее/uikit \ No newline at end of file diff --git a/M/5.1/общее/050.функции.js b/M/5.1/общее/050.функции.js new file mode 100644 index 0000000..0798274 --- /dev/null +++ b/M/5.1/общее/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.1/общее/100.События.js b/M/5.1/общее/100.События.js new file mode 100644 index 0000000..abd6710 --- /dev/null +++ b/M/5.1/общее/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.1/общее/150.Состояние.js b/M/5.1/общее/150.Состояние.js new file mode 100644 index 0000000..d0db466 --- /dev/null +++ b/M/5.1/общее/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.1/общее/200.обёртки.js b/M/5.1/общее/200.обёртки.js new file mode 100644 index 0000000..cb6eba0 --- /dev/null +++ b/M/5.1/общее/200.обёртки.js @@ -0,0 +1,4 @@ +мир.разобрать = function(словарь) +{ + мир.состояние.разобратьЛишьНовое(словарь); +}; diff --git a/M/5.1/общее/base64-js b/M/5.1/общее/base64-js new file mode 120000 index 0000000..a3367c1 --- /dev/null +++ b/M/5.1/общее/base64-js @@ -0,0 +1 @@ +../../стороннее/base64-js \ No newline at end of file diff --git a/M/5.1/общее/pako b/M/5.1/общее/pako new file mode 120000 index 0000000..504d162 --- /dev/null +++ b/M/5.1/общее/pako @@ -0,0 +1 @@ +../../стороннее/pako \ No newline at end of file diff --git a/M/5.1/редактор.html b/M/5.1/редактор.html new file mode 100644 index 0000000..fdf6a7a --- /dev/null +++ b/M/5.1/редактор.html @@ -0,0 +1,123 @@ + + + + + M-5.1 + + + + + + + + + + + + + +
+
+   + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
5.1html, body height = 100%
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.1/редактор/100.Редактор.js b/M/5.1/редактор/100.Редактор.js new file mode 100644 index 0000000..430d3a8 --- /dev/null +++ b/M/5.1/редактор/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.1/редактор/200.Пульт.js b/M/5.1/редактор/200.Пульт.js new file mode 100644 index 0000000..42889e5 --- /dev/null +++ b/M/5.1/редактор/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.1/редактор/700.Муром.js b/M/5.1/редактор/700.Муром.js new file mode 100644 index 0000000..2321260 --- /dev/null +++ b/M/5.1/редактор/700.Муром.js @@ -0,0 +1,13 @@ +function Муром() +{ + this.создать = function() + { + мир.события = new События(мир.uuid); + мир.состояние = new Состояние(); + мир.редактор = new Редактор(мир.события, "редактор"); + мир.пульт = new Пульт(мир.события, "ошибка", "перезапустить", "отдельно", "ссылка", "документация"); + }; + + // Конструктор. + this.создать(); +} diff --git a/M/5.1/редактор/ace b/M/5.1/редактор/ace new file mode 120000 index 0000000..0190be9 --- /dev/null +++ b/M/5.1/редактор/ace @@ -0,0 +1 @@ +../../стороннее/ace \ No newline at end of file diff --git a/M/5.1/редактор/uikit b/M/5.1/редактор/uikit new file mode 120000 index 0000000..d60f2bc --- /dev/null +++ b/M/5.1/редактор/uikit @@ -0,0 +1 @@ +../../стороннее/uikit \ No newline at end of file diff --git a/M/index.html b/M/index.html index 15f6d7e..4678f02 100644 --- a/M/index.html +++ b/M/index.html @@ -1,4 +1,4 @@ - +